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

Merge branch 'master' into fix_taiko_sizing

This commit is contained in:
Dean Herbert 2017-08-22 23:19:41 +09:00 committed by GitHub
commit 6f8e85c2e1
28 changed files with 253 additions and 150 deletions

@ -1 +1 @@
Subproject commit f1527e5456cd228ddfb68cf6d56eb5d28dc360bf
Subproject commit ba70b8eaa9b79d4248873d4399f3b9e918fc3c8f

View File

@ -28,12 +28,20 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
private Pattern lastPattern = new Pattern();
private FastRandom random;
private Beatmap beatmap;
private bool isForCurrentRuleset;
protected override Beatmap<ManiaHitObject> ConvertBeatmap(Beatmap original, bool isForCurrentRuleset)
private readonly int availableColumns;
private readonly bool isForCurrentRuleset;
public ManiaBeatmapConverter(bool isForCurrentRuleset, int availableColumns)
{
this.isForCurrentRuleset = isForCurrentRuleset;
if (availableColumns <= 0) throw new ArgumentOutOfRangeException(nameof(availableColumns));
this.isForCurrentRuleset = isForCurrentRuleset;
this.availableColumns = availableColumns;
}
protected override Beatmap<ManiaHitObject> ConvertBeatmap(Beatmap original)
{
beatmap = original;
BeatmapDifficulty difficulty = original.BeatmapInfo.Difficulty;
@ -41,7 +49,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
int seed = (int)Math.Round(difficulty.DrainRate + difficulty.CircleSize) * 20 + (int)(difficulty.OverallDifficulty * 41.2) + (int)Math.Round(difficulty.ApproachRate);
random = new FastRandom(seed);
return base.ConvertBeatmap(original, isForCurrentRuleset);
return base.ConvertBeatmap(original);
}
protected override IEnumerable<ManiaHitObject> ConvertHitObject(HitObject original, Beatmap beatmap)
@ -89,7 +97,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
/// <returns>The hit objects generated.</returns>
private IEnumerable<ManiaHitObject> generateSpecific(HitObject original)
{
var generator = new SpecificBeatmapPatternGenerator(random, original, beatmap, lastPattern);
var generator = new SpecificBeatmapPatternGenerator(random, original, beatmap, availableColumns, lastPattern);
Pattern newPattern = generator.Generate();
lastPattern = newPattern;
@ -113,14 +121,14 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
Patterns.PatternGenerator conversion = null;
if (distanceData != null)
conversion = new DistanceObjectPatternGenerator(random, original, beatmap, lastPattern);
conversion = new DistanceObjectPatternGenerator(random, original, beatmap, availableColumns, lastPattern);
else if (endTimeData != null)
conversion = new EndTimeObjectPatternGenerator(random, original, beatmap);
conversion = new EndTimeObjectPatternGenerator(random, original, beatmap, availableColumns);
else if (positionData != null)
{
computeDensity(original.StartTime);
conversion = new HitObjectPatternGenerator(random, original, beatmap, lastPattern, lastTime, lastPosition, density, lastStair);
conversion = new HitObjectPatternGenerator(random, original, beatmap, availableColumns, lastPattern, lastTime, lastPosition, density, lastStair);
recordNote(original.StartTime, positionData.Position);
}
@ -142,8 +150,8 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
/// </summary>
private class SpecificBeatmapPatternGenerator : Patterns.Legacy.PatternGenerator
{
public SpecificBeatmapPatternGenerator(FastRandom random, HitObject hitObject, Beatmap beatmap, Pattern previousPattern)
: base(random, hitObject, beatmap, previousPattern)
public SpecificBeatmapPatternGenerator(FastRandom random, HitObject hitObject, Beatmap beatmap, int availableColumns, Pattern previousPattern)
: base(random, hitObject, beatmap, availableColumns, previousPattern)
{
}

View File

@ -29,8 +29,8 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
private PatternType convertType;
public DistanceObjectPatternGenerator(FastRandom random, HitObject hitObject, Beatmap beatmap, Pattern previousPattern)
: base(random, hitObject, beatmap, previousPattern)
public DistanceObjectPatternGenerator(FastRandom random, HitObject hitObject, Beatmap beatmap, int availableColumns, Pattern previousPattern)
: base(random, hitObject, beatmap, availableColumns, previousPattern)
{
convertType = PatternType.None;
if (Beatmap.ControlPointInfo.EffectPointAt(hitObject.StartTime).KiaiMode)

View File

@ -15,8 +15,8 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
{
private readonly double endTime;
public EndTimeObjectPatternGenerator(FastRandom random, HitObject hitObject, Beatmap beatmap)
: base(random, hitObject, beatmap, new Pattern())
public EndTimeObjectPatternGenerator(FastRandom random, HitObject hitObject, Beatmap beatmap, int availableColumns)
: base(random, hitObject, beatmap, availableColumns, new Pattern())
{
var endtimeData = HitObject as IHasEndTime;

View File

@ -20,9 +20,12 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
private readonly PatternType convertType;
public HitObjectPatternGenerator(FastRandom random, HitObject hitObject, Beatmap beatmap, Pattern previousPattern, double previousTime, Vector2 previousPosition, double density, PatternType lastStair)
: base(random, hitObject, beatmap, previousPattern)
public HitObjectPatternGenerator(FastRandom random, HitObject hitObject, Beatmap beatmap, int availableColumns, Pattern previousPattern, double previousTime, Vector2 previousPosition, double density, PatternType lastStair)
: base(random, hitObject, beatmap, availableColumns, previousPattern)
{
if (previousTime > hitObject.StartTime) throw new ArgumentOutOfRangeException(nameof(previousTime));
if (density < 0) throw new ArgumentOutOfRangeException(nameof(density));
StairType = lastStair;
TimingControlPoint timingPoint = beatmap.ControlPointInfo.TimingPointAt(hitObject.StartTime);

View File

@ -25,11 +25,15 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
/// </summary>
protected readonly FastRandom Random;
protected PatternGenerator(FastRandom random, HitObject hitObject, Beatmap beatmap, Pattern previousPattern)
: base(hitObject, beatmap, previousPattern)
protected PatternGenerator(FastRandom random, HitObject hitObject, Beatmap beatmap, int availableColumns, Pattern previousPattern)
: base(hitObject, beatmap, availableColumns, previousPattern)
{
Random = random;
if (random == null) throw new ArgumentNullException(nameof(random));
if (beatmap == null) throw new ArgumentNullException(nameof(beatmap));
if (availableColumns <= 0) throw new ArgumentOutOfRangeException(nameof(availableColumns));
if (previousPattern == null) throw new ArgumentNullException(nameof(previousPattern));
Random = random;
RandomStart = AvailableColumns == 8 ? 1 : 0;
}
@ -62,6 +66,12 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
/// <returns>The amount of notes to be generated.</returns>
protected int GetRandomNoteCount(double p2, double p3, double p4 = 0, double p5 = 0, double p6 = 0)
{
if (p2 < 0 || p2 > 1) throw new ArgumentOutOfRangeException(nameof(p2));
if (p3 < 0 || p3 > 1) throw new ArgumentOutOfRangeException(nameof(p3));
if (p4 < 0 || p4 > 1) throw new ArgumentOutOfRangeException(nameof(p4));
if (p5 < 0 || p5 > 1) throw new ArgumentOutOfRangeException(nameof(p5));
if (p6 < 0 || p6 > 1) throw new ArgumentOutOfRangeException(nameof(p6));
double val = Random.NextDouble();
if (val >= 1 - p6)
return 6;

View File

@ -32,13 +32,17 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns
/// </summary>
protected readonly Beatmap Beatmap;
protected PatternGenerator(HitObject hitObject, Beatmap beatmap, Pattern previousPattern)
protected PatternGenerator(HitObject hitObject, Beatmap beatmap, int availableColumns, Pattern previousPattern)
{
PreviousPattern = previousPattern;
if (hitObject == null) throw new ArgumentNullException(nameof(hitObject));
if (beatmap == null) throw new ArgumentNullException(nameof(beatmap));
if (availableColumns <= 0) throw new ArgumentOutOfRangeException(nameof(availableColumns));
if (previousPattern == null) throw new ArgumentNullException(nameof(previousPattern));
HitObject = hitObject;
Beatmap = beatmap;
AvailableColumns = (int)Math.Round(beatmap.BeatmapInfo.Difficulty.CircleSize);
AvailableColumns = availableColumns;
PreviousPattern = previousPattern;
}
/// <summary>

View File

@ -6,6 +6,7 @@ using osu.Game.Rulesets.Beatmaps;
using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.Mania.Objects;
using System.Collections.Generic;
using System;
namespace osu.Game.Rulesets.Mania
{
@ -21,6 +22,6 @@ namespace osu.Game.Rulesets.Mania
return 0;
}
protected override BeatmapConverter<ManiaHitObject> CreateBeatmapConverter() => new ManiaBeatmapConverter();
protected override BeatmapConverter<ManiaHitObject> CreateBeatmapConverter() => new ManiaBeatmapConverter(true, (int)Math.Max(1, Math.Round(Beatmap.BeatmapInfo.Difficulty.CircleSize)));
}
}
}

View File

@ -125,6 +125,7 @@ namespace osu.Game.Rulesets.Mania.UI
for (int i = 0; i < columnCount; i++)
{
var c = new Column();
c.Reversed.BindTo(Reversed);
c.VisibleTimeRange.BindTo(VisibleTimeRange);
columns.Add(c);

View File

@ -33,9 +33,10 @@ namespace osu.Game.Rulesets.Mania.UI
public class ManiaRulesetContainer : ScrollingRulesetContainer<ManiaPlayfield, ManiaHitObject, ManiaJudgement>
{
/// <summary>
/// Preferred column count. This will only have an effect during the initialization of the play field.
/// The number of columns which the <see cref="ManiaPlayfield"/> should display, and which
/// the beatmap converter will attempt to convert beatmaps to use.
/// </summary>
public int PreferredColumns;
private int availableColumns;
public IEnumerable<DrawableBarLine> BarLines;
@ -76,26 +77,35 @@ namespace osu.Game.Rulesets.Mania.UI
BarLines.ForEach(Playfield.Add);
}
protected override void ApplyBeatmap()
{
base.ApplyBeatmap();
PreferredColumns = (int)Math.Max(1, Math.Round(Beatmap.BeatmapInfo.Difficulty.CircleSize));
}
protected sealed override Playfield<ManiaHitObject, ManiaJudgement> CreatePlayfield() => new ManiaPlayfield(PreferredColumns)
protected sealed override Playfield<ManiaHitObject, ManiaJudgement> CreatePlayfield() => new ManiaPlayfield(availableColumns)
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
// Invert by default for now (should be moved to config/skin later)
Scale = new Vector2(1, -1)
};
public override ScoreProcessor CreateScoreProcessor() => new ManiaScoreProcessor(this);
public override PassThroughInputManager CreateInputManager() => new ManiaInputManager(Ruleset.RulesetInfo);
protected override BeatmapConverter<ManiaHitObject> CreateBeatmapConverter() => new ManiaBeatmapConverter();
protected override BeatmapConverter<ManiaHitObject> CreateBeatmapConverter()
{
if (IsForCurrentRuleset)
availableColumns = (int)Math.Max(1, Math.Round(WorkingBeatmap.BeatmapInfo.Difficulty.CircleSize));
else
{
float percentSliderOrSpinner = (float)WorkingBeatmap.Beatmap.HitObjects.Count(h => h is IHasEndTime) / WorkingBeatmap.Beatmap.HitObjects.Count;
if (percentSliderOrSpinner < 0.2)
availableColumns = 7;
else if (percentSliderOrSpinner < 0.3 || Math.Round(WorkingBeatmap.BeatmapInfo.Difficulty.CircleSize) >= 5)
availableColumns = Math.Round(WorkingBeatmap.BeatmapInfo.Difficulty.OverallDifficulty) > 5 ? 7 : 6;
else if (percentSliderOrSpinner > 0.6)
availableColumns = Math.Round(WorkingBeatmap.BeatmapInfo.Difficulty.OverallDifficulty) > 4 ? 5 : 4;
else
availableColumns = Math.Max(4, Math.Min((int)Math.Round(WorkingBeatmap.BeatmapInfo.Difficulty.OverallDifficulty) + 1, 7));
}
return new ManiaBeatmapConverter(IsForCurrentRuleset, availableColumns);
}
protected override DrawableHitObject<ManiaHitObject, ManiaJudgement> GetVisualRepresentation(ManiaHitObject h)
{

View File

@ -39,19 +39,22 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
/// </summary>
private const float taiko_base_distance = 100;
private bool isForCurrentRuleset;
private readonly bool isForCurrentRuleset;
protected override IEnumerable<Type> ValidConversionTypes { get; } = new[] { typeof(HitObject) };
protected override Beatmap<TaikoHitObject> ConvertBeatmap(Beatmap original, bool isForCurrentRuleset)
public TaikoBeatmapConverter(bool isForCurrentRuleset)
{
this.isForCurrentRuleset = isForCurrentRuleset;
}
protected override Beatmap<TaikoHitObject> ConvertBeatmap(Beatmap original)
{
// Rewrite the beatmap info to add the slider velocity multiplier
BeatmapInfo info = original.BeatmapInfo.DeepClone();
info.Difficulty.SliderMultiplier *= legacy_velocity_multiplier;
Beatmap<TaikoHitObject> converted = base.ConvertBeatmap(original, isForCurrentRuleset);
Beatmap<TaikoHitObject> converted = base.ConvertBeatmap(original);
// Post processing step to transform hit objects with the same start time into strong hits
converted.HitObjects = converted.HitObjects.GroupBy(t => t.StartTime).Select(x =>

View File

@ -135,6 +135,6 @@ namespace osu.Game.Rulesets.Taiko
return difficulty;
}
protected override BeatmapConverter<TaikoHitObject> CreateBeatmapConverter() => new TaikoBeatmapConverter();
protected override BeatmapConverter<TaikoHitObject> CreateBeatmapConverter() => new TaikoBeatmapConverter(true);
}
}
}

View File

@ -91,7 +91,7 @@ namespace osu.Game.Rulesets.Taiko.UI
public override ScoreProcessor CreateScoreProcessor() => new TaikoScoreProcessor(this);
protected override BeatmapConverter<TaikoHitObject> CreateBeatmapConverter() => new TaikoBeatmapConverter();
protected override BeatmapConverter<TaikoHitObject> CreateBeatmapConverter() => new TaikoBeatmapConverter(IsForCurrentRuleset);
public override PassThroughInputManager CreateInputManager() => new TaikoInputManager(Ruleset.RulesetInfo);

View File

@ -30,11 +30,15 @@ namespace osu.Game.Beatmaps
public abstract class DifficultyCalculator<T> : DifficultyCalculator where T : HitObject
{
protected readonly Beatmap Beatmap;
protected List<T> Objects;
protected DifficultyCalculator(Beatmap beatmap)
{
Objects = CreateBeatmapConverter().Convert(beatmap, true).HitObjects;
Beatmap = beatmap;
Objects = CreateBeatmapConverter().Convert(beatmap).HitObjects;
foreach (var h in Objects)
h.ApplyDefaults(beatmap.ControlPointInfo, beatmap.BeatmapInfo.Difficulty);

View File

@ -11,6 +11,7 @@ using osu.Framework.Graphics.Sprites;
using osu.Framework.Input;
using osu.Game.Configuration;
using System;
using System.Diagnostics;
using osu.Framework.Graphics.Textures;
namespace osu.Game.Graphics.Cursor
@ -21,20 +22,31 @@ namespace osu.Game.Graphics.Cursor
private bool dragging;
private bool startRotation;
protected override bool OnMouseMove(InputState state)
{
if (dragging)
{
Vector2 offset = state.Mouse.Position - state.Mouse.PositionMouseDown ?? state.Mouse.Delta;
float degrees = (float)MathHelper.RadiansToDegrees(Math.Atan2(-offset.X, offset.Y)) + 24.3f;
Debug.Assert(state.Mouse.PositionMouseDown != null);
// Always rotate in the direction of least distance
float diff = (degrees - ActiveCursor.Rotation) % 360;
if (diff < -180) diff += 360;
if (diff > 180) diff -= 360;
degrees = ActiveCursor.Rotation + diff;
// don't start rotating until we're moved a minimum distance away from the mouse down location,
// else it can have an annoying effect.
startRotation |= Vector2.Distance(state.Mouse.Position, state.Mouse.PositionMouseDown.Value) > 30;
ActiveCursor.RotateTo(degrees, 600, Easing.OutQuint);
if (startRotation)
{
Vector2 offset = state.Mouse.Position - state.Mouse.PositionMouseDown.Value;
float degrees = (float)MathHelper.RadiansToDegrees(Math.Atan2(-offset.X, offset.Y)) + 24.3f;
// Always rotate in the direction of least distance
float diff = (degrees - ActiveCursor.Rotation) % 360;
if (diff < -180) diff += 360;
if (diff > 180) diff -= 360;
degrees = ActiveCursor.Rotation + diff;
ActiveCursor.RotateTo(degrees, 600, Easing.OutQuint);
}
}
return base.OnMouseMove(state);
@ -61,6 +73,7 @@ namespace osu.Game.Graphics.Cursor
if (!state.Mouse.HasMainButtonPressed)
{
dragging = false;
startRotation = false;
((Cursor)ActiveCursor).AdditiveLayer.FadeOut(500, Easing.OutQuint);
ActiveCursor.RotateTo(0, 600 * (1 + Math.Abs(ActiveCursor.Rotation / 720)), Easing.OutElasticHalf);

View File

@ -3,11 +3,11 @@
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Input;
using osu.Framework.Threading;
using OpenTK;
using osu.Framework.Audio;
using osu.Framework.Allocation;
using osu.Game.Input.Bindings;
namespace osu.Game.Graphics.UserInterface.Volume
{
@ -64,15 +64,25 @@ namespace osu.Game.Graphics.UserInterface.Volume
volumeMeterMusic.Bindable.ValueChanged -= volumeChanged;
}
public void Adjust(InputState state)
public bool Adjust(GlobalAction action)
{
if (State == Visibility.Hidden)
switch (action)
{
Show();
return;
case GlobalAction.DecreaseVolume:
if (State == Visibility.Hidden)
Show();
else
volumeMeterMaster.Decrease();
return true;
case GlobalAction.IncreaseVolume:
if (State == Visibility.Hidden)
Show();
else
volumeMeterMaster.Increase();
return true;
}
volumeMeterMaster.TriggerOnWheel(state);
return false;
}
[BackgroundDependencyLoader]

View File

@ -3,32 +3,16 @@
using System;
using osu.Framework.Graphics.Containers;
using osu.Framework.Input;
using OpenTK.Input;
using osu.Framework.Input.Bindings;
using osu.Game.Input.Bindings;
namespace osu.Game.Graphics.UserInterface.Volume
{
internal class VolumeControlReceptor : Container
internal class VolumeControlReceptor : Container, IKeyBindingHandler<GlobalAction>
{
public Action<InputState> ActionRequested;
public Func<GlobalAction, bool> ActionRequested;
protected override bool OnWheel(InputState state)
{
ActionRequested?.Invoke(state);
return true;
}
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
{
switch (args.Key)
{
case Key.Up:
case Key.Down:
ActionRequested?.Invoke(state);
return true;
}
return base.OnKeyDown(state, args);
}
public bool OnPressed(GlobalAction action) => ActionRequested?.Invoke(action) ?? false;
public bool OnReleased(GlobalAction action) => false;
}
}

View File

@ -4,15 +4,16 @@
using osu.Framework.Configuration;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Input;
using osu.Game.Graphics.Sprites;
using OpenTK;
using OpenTK.Graphics;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Input.Bindings;
using osu.Game.Input.Bindings;
namespace osu.Game.Graphics.UserInterface.Volume
{
internal class VolumeMeter : Container
internal class VolumeMeter : Container, IKeyBindingHandler<GlobalAction>
{
private readonly Box meterFill;
public BindableDouble Bindable { get; } = new BindableDouble();
@ -76,12 +77,35 @@ namespace osu.Game.Graphics.UserInterface.Volume
}
}
protected override bool OnWheel(InputState state)
public void Increase()
{
Volume += 0.05f * state.Mouse.WheelDelta;
return true;
Volume += 0.05f;
}
public void Decrease()
{
Volume -= 0.05f;
}
private void updateFill() => meterFill.ScaleTo(new Vector2(1, (float)Volume), 300, Easing.OutQuint);
public bool OnPressed(GlobalAction action)
{
if (!IsHovered) return false;
switch (action)
{
case GlobalAction.DecreaseVolume:
Decrease();
return true;
case GlobalAction.IncreaseVolume:
Increase();
return true;
}
return false;
}
public bool OnReleased(GlobalAction action) => false;
}
}

View File

@ -26,7 +26,10 @@ namespace osu.Game.Input.Bindings
new KeyBinding(new[] { InputKey.Control, InputKey.Alt, InputKey.R }, GlobalAction.ResetInputSettings),
new KeyBinding(new[] { InputKey.Control, InputKey.T }, GlobalAction.ToggleToolbar),
new KeyBinding(new[] { InputKey.Control, InputKey.O }, GlobalAction.ToggleSettings),
new KeyBinding(new[] { InputKey.Control, InputKey.D }, GlobalAction.ToggleDirect),
new KeyBinding(new[] { InputKey.Up }, GlobalAction.IncreaseVolume),
new KeyBinding(new[] { InputKey.MouseWheelUp }, GlobalAction.IncreaseVolume),
new KeyBinding(new[] { InputKey.Down }, GlobalAction.DecreaseVolume),
new KeyBinding(new[] { InputKey.MouseWheelDown }, GlobalAction.DecreaseVolume),
};
protected override IEnumerable<Drawable> KeyBindingInputQueue =>
@ -47,5 +50,9 @@ namespace osu.Game.Input.Bindings
ToggleSettings,
[Description("Toggle osu!direct")]
ToggleDirect,
[Description("Increase Volume")]
IncreaseVolume,
[Description("Decrease Volume")]
DecreaseVolume,
}
}

View File

@ -8,7 +8,6 @@ using osu.Game.Configuration;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Overlays;
using osu.Framework.Input;
using osu.Framework.Logging;
using osu.Game.Graphics.UserInterface.Volume;
using osu.Framework.Allocation;
@ -160,7 +159,7 @@ namespace osu.Game
new VolumeControlReceptor
{
RelativeSizeAxes = Axes.Both,
ActionRequested = delegate(InputState state) { volume.Adjust(state); }
ActionRequested = action => volume.Adjust(action)
},
mainContent = new Container
{

View File

@ -136,40 +136,49 @@ namespace osu.Game.Overlays.KeyBinding
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
{
if (HasFocus)
{
if (bindTarget.IsHovered)
{
if (!AllowMainMouseButtons)
{
switch (args.Button)
{
case MouseButton.Left:
case MouseButton.Right:
return true;
}
}
if (!HasFocus || !bindTarget.IsHovered)
return base.OnMouseDown(state, args);
bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(state));
return true;
if (!AllowMainMouseButtons)
{
switch (args.Button)
{
case MouseButton.Left:
case MouseButton.Right:
return true;
}
}
return base.OnMouseDown(state, args);
bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(state));
return true;
}
protected override bool OnMouseUp(InputState state, MouseUpEventArgs args)
{
if (HasFocus && !state.Mouse.Buttons.Any())
// don't do anything until the last button is released.
if (!HasFocus || state.Mouse.Buttons.Any())
return base.OnMouseUp(state, args);
if (bindTarget.IsHovered)
finalise();
else
updateBindTarget();
return true;
}
protected override bool OnWheel(InputState state)
{
if (HasFocus)
{
if (bindTarget.IsHovered)
{
bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(state));
finalise();
else
updateBindTarget();
return true;
return true;
}
}
return base.OnMouseUp(state, args);
return base.OnWheel(state);
}
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
@ -196,13 +205,10 @@ namespace osu.Game.Overlays.KeyBinding
protected override bool OnKeyUp(InputState state, KeyUpEventArgs args)
{
if (HasFocus)
{
finalise();
return true;
}
if (!HasFocus) return base.OnKeyUp(state, args);
return base.OnKeyUp(state, args);
finalise();
return true;
}
private void finalise()

View File

@ -22,7 +22,7 @@ namespace osu.Game.Overlays
private ScrollContainer scrollContainer;
private FlowContainer<NotificationSection> sections;
[BackgroundDependencyLoader(permitNulls: true)]
[BackgroundDependencyLoader]
private void load()
{
Width = width;
@ -72,6 +72,13 @@ namespace osu.Game.Overlays
private int runningDepth;
private void notificationClosed()
{
// hide ourselves if all notifications have been dismissed.
if (sections.Select(c => c.DisplayedCount).Sum() > 0)
State = Visibility.Hidden;
}
public void Post(Notification notification)
{
Schedule(() =>
@ -81,6 +88,8 @@ namespace osu.Game.Overlays
++runningDepth;
notification.Depth = notification.DisplayOnTop ? runningDepth : -runningDepth;
notification.Closed += notificationClosed;
var hasCompletionTarget = notification as IHasCompletionTarget;
if (hasCompletionTarget != null)
hasCompletionTarget.CompletionTarget = Post;

View File

@ -19,9 +19,9 @@ namespace osu.Game.Overlays.Notifications
public abstract class Notification : Container
{
/// <summary>
/// Use requested close.
/// User requested close.
/// </summary>
public Action Closed;
public event Action Closed;
/// <summary>
/// Run on user activating the notification. Return true to close.

View File

@ -24,6 +24,8 @@ namespace osu.Game.Overlays.Notifications
private FlowContainer<Notification> notifications;
public int DisplayedCount => notifications.Count;
public void Add(Notification notification)
{
notifications.Add(notification);

View File

@ -26,21 +26,19 @@ namespace osu.Game.Rulesets.Beatmaps
/// Converts a Beatmap using this Beatmap Converter.
/// </summary>
/// <param name="original">The un-converted Beatmap.</param>
/// <param name="isForCurrentRuleset">Whether to assume the beatmap is for the current ruleset.</param>
/// <returns>The converted Beatmap.</returns>
public Beatmap<T> Convert(Beatmap original, bool isForCurrentRuleset)
public Beatmap<T> Convert(Beatmap original)
{
// We always operate on a clone of the original beatmap, to not modify it game-wide
return ConvertBeatmap(new Beatmap(original), isForCurrentRuleset);
return ConvertBeatmap(new Beatmap(original));
}
/// <summary>
/// Performs the conversion of a Beatmap using this Beatmap Converter.
/// </summary>
/// <param name="original">The un-converted Beatmap.</param>
/// <param name="isForCurrentRuleset">Whether to assume the beatmap is for the current ruleset.</param>
/// <returns>The converted Beatmap.</returns>
protected virtual Beatmap<T> ConvertBeatmap(Beatmap original, bool isForCurrentRuleset)
protected virtual Beatmap<T> ConvertBeatmap(Beatmap original)
{
return new Beatmap<T>
{

View File

@ -139,16 +139,30 @@ namespace osu.Game.Rulesets.UI
protected IEnumerable<Mod> Mods;
/// <summary>
/// The <see cref="WorkingBeatmap"/> this <see cref="RulesetContainer{TObject}"/> was created with.
/// </summary>
protected readonly WorkingBeatmap WorkingBeatmap;
/// <summary>
/// Whether the specified beatmap is assumed to be specific to the current ruleset.
/// </summary>
protected readonly bool IsForCurrentRuleset;
/// <summary>
/// Whether to assume the beatmap passed into this <see cref="RulesetContainer{TObject}"/> is for the current ruleset.
/// Creates a hit renderer for a beatmap.
/// </summary>
/// <param name="ruleset">The ruleset being repesented.</param>
/// <param name="beatmap">The beatmap to create the hit renderer for.</param>
/// <param name="workingBeatmap">The beatmap to create the hit renderer for.</param>
/// <param name="isForCurrentRuleset">Whether to assume the beatmap is for the current ruleset.</param>
internal RulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap, bool isForCurrentRuleset) : base(ruleset)
internal RulesetContainer(Ruleset ruleset, WorkingBeatmap workingBeatmap, bool isForCurrentRuleset)
: base(ruleset)
{
Debug.Assert(beatmap != null, "RulesetContainer initialized with a null beatmap.");
Debug.Assert(workingBeatmap != null, "RulesetContainer initialized with a null beatmap.");
Mods = beatmap.Mods.Value;
WorkingBeatmap = workingBeatmap;
IsForCurrentRuleset = isForCurrentRuleset;
Mods = workingBeatmap.Mods.Value;
RelativeSizeAxes = Axes.Both;
@ -156,11 +170,11 @@ namespace osu.Game.Rulesets.UI
BeatmapProcessor<TObject> processor = CreateBeatmapProcessor();
// Check if the beatmap can be converted
if (!converter.CanConvert(beatmap.Beatmap))
if (!converter.CanConvert(workingBeatmap.Beatmap))
throw new BeatmapInvalidForRulesetException($"{nameof(Beatmap)} can not be converted for the current ruleset (converter: {converter}).");
// Convert the beatmap
Beatmap = converter.Convert(beatmap.Beatmap, isForCurrentRuleset);
Beatmap = converter.Convert(workingBeatmap.Beatmap);
// Apply difficulty adjustments from mods before using Difficulty.
foreach (var mod in Mods.OfType<IApplicableToDifficulty>())
@ -173,8 +187,6 @@ namespace osu.Game.Rulesets.UI
// Post-process the beatmap
processor.PostProcess(Beatmap);
ApplyBeatmap();
// Add mods, should always be the last thing applied to give full control to mods
applyMods(Mods);
}
@ -192,11 +204,6 @@ namespace osu.Game.Rulesets.UI
mod.ApplyToRulesetContainer(this);
}
/// <summary>
/// Called when the beatmap of this hit renderer has been set. Used to apply any default values from the beatmap.
/// </summary>
protected virtual void ApplyBeatmap() { }
/// <summary>
/// Creates a processor to perform post-processing operations
/// on HitObjects in converted Beatmaps.

View File

@ -173,7 +173,8 @@ namespace osu.Game.Rulesets.UI
}
/// <summary>
/// Adds a <see cref="SpeedAdjustmentContainer"/> to this container.
/// Adds a <see cref="SpeedAdjustmentContainer"/> to this container, re-sorting all hit objects
/// in the last <see cref="SpeedAdjustmentContainer"/> that occurred (time-wise) before it.
/// </summary>
/// <param name="speedAdjustment">The <see cref="SpeedAdjustmentContainer"/>.</param>
public void AddSpeedAdjustment(SpeedAdjustmentContainer speedAdjustment)
@ -184,6 +185,8 @@ namespace osu.Game.Rulesets.UI
if (speedAdjustments.Count > 0)
{
// We need to re-sort all hit objects in the speed adjustment container prior to figure out if they
// should now lie within this one
var existingAdjustment = adjustmentContainerAt(speedAdjustment.ControlPoint.StartTime);
for (int i = 0; i < existingAdjustment.Count; i++)
{

View File

@ -39,17 +39,6 @@ namespace osu.Game.Rulesets.UI
[BackgroundDependencyLoader]
private void load()
{
DefaultControlPoints.ForEach(c => applySpeedAdjustment(c, Playfield));
}
private void applySpeedAdjustment(MultiplierControlPoint controlPoint, ScrollingPlayfield<TObject, TJudgement> playfield)
{
playfield.HitObjects.AddSpeedAdjustment(CreateSpeedAdjustmentContainer(controlPoint));
playfield.NestedPlayfields.ForEach(p => applySpeedAdjustment(controlPoint, p));
}
protected override void ApplyBeatmap()
{
// Calculate default multiplier control points
var lastTimingPoint = new TimingControlPoint();
@ -95,6 +84,14 @@ namespace osu.Game.Rulesets.UI
// If we have no control points, add a default one
if (DefaultControlPoints.Count == 0)
DefaultControlPoints.Add(new MultiplierControlPoint());
DefaultControlPoints.ForEach(c => applySpeedAdjustment(c, Playfield));
}
private void applySpeedAdjustment(MultiplierControlPoint controlPoint, ScrollingPlayfield<TObject, TJudgement> playfield)
{
playfield.HitObjects.AddSpeedAdjustment(CreateSpeedAdjustmentContainer(controlPoint));
playfield.NestedPlayfields.ForEach(p => applySpeedAdjustment(controlPoint, p));
}
/// <summary>