1
0
mirror of https://github.com/ppy/osu.git synced 2025-01-12 16:02:55 +08:00

Merge remote-tracking branch 'origin/master' into auto-restart-mod-perfect

# Conflicts:
#	osu.Game/Screens/Play/Player.cs
This commit is contained in:
smoogipoo 2019-09-19 17:53:10 +09:00
commit db24cfbead
18 changed files with 173 additions and 61 deletions

View File

@ -51,7 +51,6 @@
<None Include="$(MSBuildThisFileDirectory)\osu.licenseheader"> <None Include="$(MSBuildThisFileDirectory)\osu.licenseheader">
<Link>osu.licenseheader</Link> <Link>osu.licenseheader</Link>
</None> </None>
<AndroidNativeLibrary Include="$(OutputPath)\**\*.so" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Reference Include="System" /> <Reference Include="System" />

View File

@ -17,7 +17,9 @@ namespace osu.Game.Rulesets.Osu.Mods
{ {
public override string Description => @"Play with no approach circles and fading circles/sliders."; public override string Description => @"Play with no approach circles and fading circles/sliders.";
public override double ScoreMultiplier => 1.06; public override double ScoreMultiplier => 1.06;
public override Type[] IncompatibleMods => new[] { typeof(OsuModSpinIn) };
public override Type[] IncompatibleMods => new[] { typeof(OsuModTraceable), typeof(OsuModSpinIn) };
private const double fade_in_duration_multiplier = 0.4; private const double fade_in_duration_multiplier = 0.4;
private const double fade_out_duration_multiplier = 0.3; private const double fade_out_duration_multiplier = 0.3;

View File

@ -26,7 +26,7 @@ namespace osu.Game.Rulesets.Osu.Mods
public override double ScoreMultiplier => 1; public override double ScoreMultiplier => 1;
// todo: this mod should be able to be compatible with hidden with a bit of further implementation. // todo: this mod should be able to be compatible with hidden with a bit of further implementation.
public override Type[] IncompatibleMods => new[] { typeof(OsuModeObjectScaleTween), typeof(OsuModHidden) }; public override Type[] IncompatibleMods => new[] { typeof(OsuModeObjectScaleTween), typeof(OsuModHidden), typeof(OsuModTraceable) };
private const int rotate_offset = 360; private const int rotate_offset = 360;
private const float rotate_starting_width = 2; private const float rotate_starting_width = 2;

View File

@ -0,0 +1,73 @@
// 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.Linq;
using osu.Framework.Bindables;
using System.Collections.Generic;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics.Sprites;
using osu.Game.Configuration;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Osu.Objects.Drawables;
namespace osu.Game.Rulesets.Osu.Mods
{
internal class OsuModTraceable : Mod, IReadFromConfig, IApplicableToDrawableHitObjects
{
public override string Name => "Traceable";
public override string Acronym => "TC";
public override IconUsage Icon => FontAwesome.Brands.SnapchatGhost;
public override ModType Type => ModType.Fun;
public override string Description => "Put your faith in the approach circles...";
public override double ScoreMultiplier => 1;
public override Type[] IncompatibleMods => new[] { typeof(OsuModHidden), typeof(OsuModSpinIn), typeof(OsuModeObjectScaleTween) };
private Bindable<bool> increaseFirstObjectVisibility = new Bindable<bool>();
public void ReadFromConfig(OsuConfigManager config)
{
increaseFirstObjectVisibility = config.GetBindable<bool>(OsuSetting.IncreaseFirstObjectVisibility);
}
public void ApplyToDrawableHitObjects(IEnumerable<DrawableHitObject> drawables)
{
foreach (var drawable in drawables.Skip(increaseFirstObjectVisibility.Value ? 1 : 0))
drawable.ApplyCustomUpdateState += ApplyTraceableState;
}
protected void ApplyTraceableState(DrawableHitObject drawable, ArmedState state)
{
if (!(drawable is DrawableOsuHitObject drawableOsu))
return;
var h = drawableOsu.HitObject;
switch (drawable)
{
case DrawableHitCircle circle:
// we only want to see the approach circle
using (circle.BeginAbsoluteSequence(h.StartTime - h.TimePreempt, true))
circle.CirclePiece.Hide();
break;
case DrawableSlider slider:
slider.AccentColour.BindValueChanged(_ =>
{
//will trigger on skin change.
slider.Body.AccentColour = slider.AccentColour.Value.Opacity(0);
slider.Body.BorderColour = slider.AccentColour.Value;
}, true);
break;
case DrawableSpinner spinner:
spinner.Disc.Hide();
spinner.Background.Hide();
break;
}
}
}
}

View File

@ -29,7 +29,7 @@ namespace osu.Game.Rulesets.Osu.Mods
private Bindable<bool> increaseFirstObjectVisibility = new Bindable<bool>(); private Bindable<bool> increaseFirstObjectVisibility = new Bindable<bool>();
public override Type[] IncompatibleMods => new[] { typeof(OsuModSpinIn) }; public override Type[] IncompatibleMods => new[] { typeof(OsuModSpinIn), typeof(OsuModTraceable) };
public void ReadFromConfig(OsuConfigManager config) public void ReadFromConfig(OsuConfigManager config)
{ {

View File

@ -18,7 +18,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
{ {
public class DrawableHitCircle : DrawableOsuHitObject, IDrawableHitObjectWithProxiedApproach public class DrawableHitCircle : DrawableOsuHitObject, IDrawableHitObjectWithProxiedApproach
{ {
public ApproachCircle ApproachCircle; public ApproachCircle ApproachCircle { get; }
private readonly IBindable<Vector2> positionBindable = new Bindable<Vector2>(); private readonly IBindable<Vector2> positionBindable = new Bindable<Vector2>();
private readonly IBindable<int> stackHeightBindable = new Bindable<int>(); private readonly IBindable<int> stackHeightBindable = new Bindable<int>();
@ -30,7 +30,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
private readonly HitArea hitArea; private readonly HitArea hitArea;
private readonly SkinnableDrawable mainContent; public SkinnableDrawable CirclePiece { get; }
public DrawableHitCircle(HitCircle h) public DrawableHitCircle(HitCircle h)
: base(h) : base(h)
@ -59,7 +59,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
return true; return true;
}, },
}, },
mainContent = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.HitCircle), _ => new MainCirclePiece(HitObject.IndexInCurrentCombo)), CirclePiece = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.HitCircle), _ => new MainCirclePiece(HitObject.IndexInCurrentCombo)),
ApproachCircle = new ApproachCircle ApproachCircle = new ApproachCircle
{ {
Alpha = 0, Alpha = 0,
@ -133,7 +133,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
{ {
base.UpdateInitialTransforms(); base.UpdateInitialTransforms();
mainContent.FadeInFromZero(HitObject.TimeFadeIn); CirclePiece.FadeInFromZero(HitObject.TimeFadeIn);
ApproachCircle.FadeIn(Math.Min(HitObject.TimeFadeIn * 2, HitObject.TimePreempt)); ApproachCircle.FadeIn(Math.Min(HitObject.TimeFadeIn * 2, HitObject.TimePreempt));
ApproachCircle.ScaleTo(1f, HitObject.TimePreempt); ApproachCircle.ScaleTo(1f, HitObject.TimePreempt);

View File

@ -163,9 +163,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
private float sliderPathRadius; private float sliderPathRadius;
protected override void SkinChanged(ISkinSource skin, bool allowFallback) protected override void ApplySkin(ISkinSource skin, bool allowFallback)
{ {
base.SkinChanged(skin, allowFallback); base.ApplySkin(skin, allowFallback);
Body.BorderSize = skin.GetConfig<OsuSkinConfiguration, float>(OsuSkinConfiguration.SliderBorderSize)?.Value ?? SliderBody.DEFAULT_BORDER_SIZE; Body.BorderSize = skin.GetConfig<OsuSkinConfiguration, float>(OsuSkinConfiguration.SliderBorderSize)?.Value ?? SliderBody.DEFAULT_BORDER_SIZE;
sliderPathRadius = skin.GetConfig<OsuSkinConfiguration, float>(OsuSkinConfiguration.SliderPathRadius)?.Value ?? OsuHitObject.OBJECT_RADIUS; sliderPathRadius = skin.GetConfig<OsuSkinConfiguration, float>(OsuSkinConfiguration.SliderPathRadius)?.Value ?? OsuHitObject.OBJECT_RADIUS;

View File

@ -139,6 +139,7 @@ namespace osu.Game.Rulesets.Osu
new OsuModSpinIn(), new OsuModSpinIn(),
new MultiMod(new OsuModGrow(), new OsuModDeflate()), new MultiMod(new OsuModGrow(), new OsuModDeflate()),
new MultiMod(new ModWindUp(), new ModWindDown()), new MultiMod(new ModWindUp(), new ModWindDown()),
new OsuModTraceable(),
}; };
case ModType.System: case ModType.System:

View File

@ -6,8 +6,6 @@ using System.Linq;
using osu.Game.Rulesets; using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.UI;
using osu.Game.Scoring;
using osu.Game.Screens.Play; using osu.Game.Screens.Play;
namespace osu.Game.Tests.Visual.Gameplay namespace osu.Game.Tests.Visual.Gameplay
@ -17,9 +15,7 @@ namespace osu.Game.Tests.Visual.Gameplay
protected override Player CreatePlayer(Ruleset ruleset) protected override Player CreatePlayer(Ruleset ruleset)
{ {
Mods.Value = Array.Empty<Mod>(); Mods.Value = Array.Empty<Mod>();
return new FailPlayer();
var beatmap = Beatmap.Value.GetPlayableBeatmap(ruleset.RulesetInfo, Array.Empty<Mod>());
return new FailPlayer(ruleset.GetAutoplayMod().CreateReplayScore(beatmap));
} }
protected override void AddCheckSteps() protected override void AddCheckSteps()
@ -29,16 +25,12 @@ namespace osu.Game.Tests.Visual.Gameplay
AddAssert("total judgements == 1", () => ((FailPlayer)Player).ScoreProcessor.JudgedHits == 1); AddAssert("total judgements == 1", () => ((FailPlayer)Player).ScoreProcessor.JudgedHits == 1);
} }
private class FailPlayer : ReplayPlayer private class FailPlayer : TestPlayer
{ {
public new DrawableRuleset DrawableRuleset => base.DrawableRuleset;
public new ScoreProcessor ScoreProcessor => base.ScoreProcessor; public new ScoreProcessor ScoreProcessor => base.ScoreProcessor;
protected override bool PauseOnFocusLost => false; public FailPlayer()
: base(false, false)
public FailPlayer(Score score)
: base(score, false, false)
{ {
} }

View File

@ -26,12 +26,14 @@ namespace osu.Game.Tests.Visual.Gameplay
{ {
AddUntilStep("score above zero", () => ((ScoreAccessibleReplayPlayer)Player).ScoreProcessor.TotalScore.Value > 0); AddUntilStep("score above zero", () => ((ScoreAccessibleReplayPlayer)Player).ScoreProcessor.TotalScore.Value > 0);
AddUntilStep("key counter counted keys", () => ((ScoreAccessibleReplayPlayer)Player).HUDOverlay.KeyCounter.Children.Any(kc => kc.CountPresses > 0)); AddUntilStep("key counter counted keys", () => ((ScoreAccessibleReplayPlayer)Player).HUDOverlay.KeyCounter.Children.Any(kc => kc.CountPresses > 0));
AddAssert("cannot fail", () => !((ScoreAccessibleReplayPlayer)Player).AllowFail);
} }
private class ScoreAccessibleReplayPlayer : ReplayPlayer private class ScoreAccessibleReplayPlayer : ReplayPlayer
{ {
public new ScoreProcessor ScoreProcessor => base.ScoreProcessor; public new ScoreProcessor ScoreProcessor => base.ScoreProcessor;
public new HUDOverlay HUDOverlay => base.HUDOverlay; public new HUDOverlay HUDOverlay => base.HUDOverlay;
public new bool AllowFail => base.AllowFail;
protected override bool PauseOnFocusLost => false; protected override bool PauseOnFocusLost => false;

View File

@ -6,6 +6,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Input.Events; using osu.Framework.Input.Events;
@ -18,7 +19,6 @@ namespace osu.Game.Overlays.Music
public class PlaylistList : CompositeDrawable public class PlaylistList : CompositeDrawable
{ {
public Action<BeatmapSetInfo> Selected; public Action<BeatmapSetInfo> Selected;
public Action<BeatmapSetInfo, int> OrderChanged;
private readonly ItemsScrollContainer items; private readonly ItemsScrollContainer items;
@ -28,7 +28,6 @@ namespace osu.Game.Overlays.Music
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Selected = set => Selected?.Invoke(set), Selected = set => Selected?.Invoke(set),
OrderChanged = (s, i) => OrderChanged?.Invoke(s, i)
}; };
} }
@ -45,13 +44,17 @@ namespace osu.Game.Overlays.Music
private class ItemsScrollContainer : OsuScrollContainer private class ItemsScrollContainer : OsuScrollContainer
{ {
public Action<BeatmapSetInfo> Selected; public Action<BeatmapSetInfo> Selected;
public Action<BeatmapSetInfo, int> OrderChanged;
private readonly SearchContainer search; private readonly SearchContainer search;
private readonly FillFlowContainer<PlaylistItem> items; private readonly FillFlowContainer<PlaylistItem> items;
private readonly IBindable<WorkingBeatmap> beatmapBacking = new Bindable<WorkingBeatmap>(); private readonly IBindable<WorkingBeatmap> beatmapBacking = new Bindable<WorkingBeatmap>();
private IBindableList<BeatmapSetInfo> beatmaps;
[Resolved]
private MusicController musicController { get; set; }
public ItemsScrollContainer() public ItemsScrollContainer()
{ {
Children = new Drawable[] Children = new Drawable[]
@ -73,27 +76,35 @@ namespace osu.Game.Overlays.Music
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(BeatmapManager beatmaps, IBindable<WorkingBeatmap> beatmap) private void load(IBindable<WorkingBeatmap> beatmap)
{ {
beatmaps.GetAllUsableBeatmapSets().ForEach(addBeatmapSet); beatmaps = musicController.BeatmapSets.GetBoundCopy();
beatmaps.ItemAdded += addBeatmapSet; beatmaps.ItemsAdded += i => i.ForEach(addBeatmapSet);
beatmaps.ItemRemoved += removeBeatmapSet; beatmaps.ItemsRemoved += i => i.ForEach(removeBeatmapSet);
beatmaps.ForEach(addBeatmapSet);
beatmapBacking.BindTo(beatmap); beatmapBacking.BindTo(beatmap);
beatmapBacking.ValueChanged += _ => updateSelectedSet(); beatmapBacking.ValueChanged += _ => updateSelectedSet();
} }
private void addBeatmapSet(BeatmapSetInfo obj) => Schedule(() => private void addBeatmapSet(BeatmapSetInfo obj)
{ {
items.Insert(items.Count - 1, new PlaylistItem(obj) { OnSelect = set => Selected?.Invoke(set) }); if (obj == draggedItem?.BeatmapSetInfo) return;
});
private void removeBeatmapSet(BeatmapSetInfo obj) => Schedule(() => Schedule(() => items.Insert(items.Count - 1, new PlaylistItem(obj) { OnSelect = set => Selected?.Invoke(set) }));
}
private void removeBeatmapSet(BeatmapSetInfo obj)
{ {
var itemToRemove = items.FirstOrDefault(i => i.BeatmapSetInfo.ID == obj.ID); if (obj == draggedItem?.BeatmapSetInfo) return;
if (itemToRemove != null)
items.Remove(itemToRemove); Schedule(() =>
}); {
var itemToRemove = items.FirstOrDefault(i => i.BeatmapSetInfo.ID == obj.ID);
if (itemToRemove != null)
items.Remove(itemToRemove);
});
}
private void updateSelectedSet() private void updateSelectedSet()
{ {
@ -112,6 +123,8 @@ namespace osu.Game.Overlays.Music
private Vector2 nativeDragPosition; private Vector2 nativeDragPosition;
private PlaylistItem draggedItem; private PlaylistItem draggedItem;
private int? dragDestination;
protected override bool OnDragStart(DragStartEvent e) protected override bool OnDragStart(DragStartEvent e)
{ {
nativeDragPosition = e.ScreenSpaceMousePosition; nativeDragPosition = e.ScreenSpaceMousePosition;
@ -131,10 +144,17 @@ namespace osu.Game.Overlays.Music
protected override bool OnDragEnd(DragEndEvent e) protected override bool OnDragEnd(DragEndEvent e)
{ {
nativeDragPosition = e.ScreenSpaceMousePosition; nativeDragPosition = e.ScreenSpaceMousePosition;
var handled = draggedItem != null || base.OnDragEnd(e);
draggedItem = null;
return handled; if (draggedItem == null)
return base.OnDragEnd(e);
if (dragDestination != null)
musicController.ChangeBeatmapSetPosition(draggedItem.BeatmapSetInfo, dragDestination.Value);
draggedItem = null;
dragDestination = null;
return true;
} }
protected override void Update() protected override void Update()
@ -210,7 +230,7 @@ namespace osu.Game.Overlays.Music
} }
items.SetLayoutPosition(draggedItem, dstIndex); items.SetLayoutPosition(draggedItem, dstIndex);
OrderChanged?.Invoke(draggedItem.BeatmapSetInfo, dstIndex); dragDestination = dstIndex;
} }
private class ItemSearchContainer : FillFlowContainer<PlaylistItem>, IHasFilterableChildren private class ItemSearchContainer : FillFlowContainer<PlaylistItem>, IHasFilterableChildren

View File

@ -1,7 +1,6 @@
// 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 System;
using System.Linq; using System.Linq;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Bindables; using osu.Framework.Bindables;
@ -22,12 +21,6 @@ namespace osu.Game.Overlays.Music
private const float transition_duration = 600; private const float transition_duration = 600;
private const float playlist_height = 510; private const float playlist_height = 510;
/// <summary>
/// Invoked when the order of an item in the list has changed.
/// The second parameter indicates the new index of the item.
/// </summary>
public Action<BeatmapSetInfo, int> OrderChanged;
private readonly Bindable<WorkingBeatmap> beatmap = new Bindable<WorkingBeatmap>(); private readonly Bindable<WorkingBeatmap> beatmap = new Bindable<WorkingBeatmap>();
private BeatmapManager beatmaps; private BeatmapManager beatmaps;
@ -65,7 +58,6 @@ namespace osu.Game.Overlays.Music
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding { Top = 95, Bottom = 10, Right = 10 }, Padding = new MarginPadding { Top = 95, Bottom = 10, Right = 10 },
Selected = itemSelected, Selected = itemSelected,
OrderChanged = (s, i) => OrderChanged?.Invoke(s, i)
}, },
filter = new FilterControl filter = new FilterControl
{ {

View File

@ -8,6 +8,7 @@ using osu.Framework.Allocation;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Input.Bindings; using osu.Framework.Input.Bindings;
using osu.Framework.MathUtils;
using osu.Framework.Threading; using osu.Framework.Threading;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Input.Bindings; using osu.Game.Input.Bindings;
@ -24,7 +25,9 @@ namespace osu.Game.Overlays
[Resolved] [Resolved]
private BeatmapManager beatmaps { get; set; } private BeatmapManager beatmaps { get; set; }
private List<BeatmapSetInfo> beatmapSets; public IBindableList<BeatmapSetInfo> BeatmapSets => beatmapSets;
private readonly BindableList<BeatmapSetInfo> beatmapSets = new BindableList<BeatmapSetInfo>();
public bool IsUserPaused { get; private set; } public bool IsUserPaused { get; private set; }
@ -46,7 +49,7 @@ namespace osu.Game.Overlays
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load()
{ {
beatmapSets = beatmaps.GetAllUsableBeatmapSets(); beatmapSets.AddRange(beatmaps.GetAllUsableBeatmapSets().OrderBy(_ => RNG.Next()));
beatmaps.ItemAdded += handleBeatmapAdded; beatmaps.ItemAdded += handleBeatmapAdded;
beatmaps.ItemRemoved += handleBeatmapRemoved; beatmaps.ItemRemoved += handleBeatmapRemoved;
} }
@ -140,7 +143,7 @@ namespace osu.Game.Overlays
{ {
queuedDirection = TrackChangeDirection.Prev; queuedDirection = TrackChangeDirection.Prev;
var playable = beatmapSets.TakeWhile(i => i.ID != current.BeatmapSetInfo.ID).LastOrDefault() ?? beatmapSets.LastOrDefault(); var playable = BeatmapSets.TakeWhile(i => i.ID != current.BeatmapSetInfo.ID).LastOrDefault() ?? BeatmapSets.LastOrDefault();
if (playable != null) if (playable != null)
{ {
@ -165,7 +168,7 @@ namespace osu.Game.Overlays
if (!instant) if (!instant)
queuedDirection = TrackChangeDirection.Next; queuedDirection = TrackChangeDirection.Next;
var playable = beatmapSets.SkipWhile(i => i.ID != current.BeatmapSetInfo.ID).Skip(1).FirstOrDefault() ?? beatmapSets.FirstOrDefault(); var playable = BeatmapSets.SkipWhile(i => i.ID != current.BeatmapSetInfo.ID).Skip(1).FirstOrDefault() ?? BeatmapSets.FirstOrDefault();
if (playable != null) if (playable != null)
{ {
@ -200,8 +203,8 @@ namespace osu.Game.Overlays
else else
{ {
//figure out the best direction based on order in playlist. //figure out the best direction based on order in playlist.
var last = beatmapSets.TakeWhile(b => b.ID != current.BeatmapSetInfo?.ID).Count(); var last = BeatmapSets.TakeWhile(b => b.ID != current.BeatmapSetInfo?.ID).Count();
var next = beatmap.NewValue == null ? -1 : beatmapSets.TakeWhile(b => b.ID != beatmap.NewValue.BeatmapSetInfo?.ID).Count(); var next = beatmap.NewValue == null ? -1 : BeatmapSets.TakeWhile(b => b.ID != beatmap.NewValue.BeatmapSetInfo?.ID).Count();
direction = last > next ? TrackChangeDirection.Prev : TrackChangeDirection.Next; direction = last > next ? TrackChangeDirection.Prev : TrackChangeDirection.Next;
} }

View File

@ -81,7 +81,6 @@ namespace osu.Game.Overlays
{ {
RelativeSizeAxes = Axes.X, RelativeSizeAxes = Axes.X,
Y = player_height + 10, Y = player_height + 10,
OrderChanged = musicController.ChangeBeatmapSetPosition
}, },
playerContainer = new Container playerContainer = new Container
{ {

View File

@ -240,7 +240,7 @@ namespace osu.Game.Rulesets.Objects.Drawables
#endregion #endregion
protected override void SkinChanged(ISkinSource skin, bool allowFallback) protected sealed override void SkinChanged(ISkinSource skin, bool allowFallback)
{ {
base.SkinChanged(skin, allowFallback); base.SkinChanged(skin, allowFallback);
@ -250,6 +250,20 @@ namespace osu.Game.Rulesets.Objects.Drawables
AccentColour.Value = comboColours?.Count > 0 ? comboColours[combo.ComboIndex % comboColours.Count] : Color4.White; AccentColour.Value = comboColours?.Count > 0 ? comboColours[combo.ComboIndex % comboColours.Count] : Color4.White;
} }
ApplySkin(skin, allowFallback);
if (IsLoaded)
updateState(State.Value, true);
}
/// <summary>
/// Called when a change is made to the skin.
/// </summary>
/// <param name="skin">The new skin.</param>
/// <param name="allowFallback">Whether fallback to default skin should be allowed if the custom skin is missing this resource.</param>
protected virtual void ApplySkin(ISkinSource skin, bool allowFallback)
{
} }
/// <summary> /// <summary>

View File

@ -86,6 +86,12 @@ namespace osu.Game.Screens.Play
[Cached(Type = typeof(IBindable<IReadOnlyList<Mod>>))] [Cached(Type = typeof(IBindable<IReadOnlyList<Mod>>))]
protected new readonly Bindable<IReadOnlyList<Mod>> Mods = new Bindable<IReadOnlyList<Mod>>(Array.Empty<Mod>()); protected new readonly Bindable<IReadOnlyList<Mod>> Mods = new Bindable<IReadOnlyList<Mod>>(Array.Empty<Mod>());
/// <summary>
/// Whether failing should be allowed.
/// By default, this checks whether all selected mods allow failing.
/// </summary>
protected virtual bool AllowFail => Mods.Value.OfType<IApplicableFailOverride>().All(m => m.AllowFail);
private readonly bool allowPause; private readonly bool allowPause;
private readonly bool showResults; private readonly bool showResults;
@ -360,9 +366,7 @@ namespace osu.Game.Screens.Play
private bool onFail() private bool onFail()
{ {
var failOverrideMods = Mods.Value.OfType<IApplicableFailOverride>(); if (!AllowFail)
if (failOverrideMods.Any(m => !m.AllowFail))
return false; return false;
HasFailed = true; HasFailed = true;
@ -374,7 +378,8 @@ namespace osu.Game.Screens.Play
PauseOverlay.Hide(); PauseOverlay.Hide();
failAnimation.Start(); failAnimation.Start();
if (failOverrideMods.Any(m => m.RestartOnFail))
if (Mods.Value.OfType<IApplicableFailOverride>().Any(m => m.RestartOnFail))
Restart(); Restart();
return true; return true;

View File

@ -9,6 +9,9 @@ namespace osu.Game.Screens.Play
{ {
private readonly Score score; private readonly Score score;
// Disallow replays from failing. (see https://github.com/ppy/osu/issues/6108)
protected override bool AllowFail => false;
public ReplayPlayer(Score score, bool allowPause = true, bool showResults = true) public ReplayPlayer(Score score, bool allowPause = true, bool showResults = true)
: base(allowPause, showResults) : base(allowPause, showResults)
{ {

View File

@ -13,6 +13,13 @@ namespace osu.Game.Skinning
: base(Info, storage, audioManager, string.Empty) : base(Info, storage, audioManager, string.Empty)
{ {
Configuration.CustomColours["SliderBall"] = new Color4(2, 170, 255, 255); Configuration.CustomColours["SliderBall"] = new Color4(2, 170, 255, 255);
Configuration.ComboColours.AddRange(new[]
{
new Color4(255, 192, 0, 255),
new Color4(0, 202, 0, 255),
new Color4(18, 124, 255, 255),
new Color4(242, 24, 57, 255),
});
} }
public static SkinInfo Info { get; } = new SkinInfo public static SkinInfo Info { get; } = new SkinInfo