Merge remote-tracking branch 'origin/master' into add-scroll-speed-keybinds

# Conflicts:
#	osu.Game/Rulesets/UI/Scrolling/ScrollingPlayfield.cs
This commit is contained in:
smoogipoo
2018-07-02 17:21:18 +09:00
432 changed files with 12399 additions and 6857 deletions

View File

@ -11,8 +11,8 @@ namespace osu.Game.Rulesets.UI
{
public class HitObjectContainer : CompositeDrawable
{
public virtual IEnumerable<DrawableHitObject> Objects => InternalChildren.Cast<DrawableHitObject>();
public virtual IEnumerable<DrawableHitObject> AliveObjects => AliveInternalChildren.Cast<DrawableHitObject>();
public IEnumerable<DrawableHitObject> Objects => InternalChildren.Cast<DrawableHitObject>().OrderBy(h => h.HitObject.StartTime);
public IEnumerable<DrawableHitObject> AliveObjects => AliveInternalChildren.Cast<DrawableHitObject>().OrderBy(h => h.HitObject.StartTime);
public virtual void Add(DrawableHitObject hitObject) => AddInternal(hitObject);
public virtual bool Remove(DrawableHitObject hitObject) => RemoveInternal(hitObject);

View File

@ -57,6 +57,7 @@ namespace osu.Game.Rulesets.UI
public abstract IEnumerable<HitObject> Objects { get; }
private readonly Lazy<Playfield> playfield;
/// <summary>
/// The playfield.
/// </summary>
@ -72,11 +73,6 @@ namespace osu.Game.Rulesets.UI
private IRulesetConfigManager rulesetConfig;
private OnScreenDisplay onScreenDisplay;
private DependencyContainer dependencies;
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent)
=> dependencies = new DependencyContainer(base.CreateLocalDependencies(parent));
/// <summary>
/// A visual representation of a <see cref="Rulesets.Ruleset"/>.
/// </summary>
@ -89,18 +85,20 @@ namespace osu.Game.Rulesets.UI
Cursor = CreateCursor();
}
[BackgroundDependencyLoader(true)]
private void load(OnScreenDisplay onScreenDisplay, SettingsStore settings)
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent)
{
this.onScreenDisplay = onScreenDisplay;
var dependencies = new DependencyContainer(base.CreateLocalDependencies(parent));
rulesetConfig = CreateConfig(Ruleset, settings);
onScreenDisplay = dependencies.Get<OnScreenDisplay>();
rulesetConfig = dependencies.Get<RulesetConfigCache>().GetConfigFor(Ruleset);
if (rulesetConfig != null)
{
dependencies.Cache(rulesetConfig);
onScreenDisplay?.BeginTracking(this, rulesetConfig);
}
return dependencies;
}
public abstract ScoreProcessor CreateScoreProcessor();
@ -130,14 +128,11 @@ namespace osu.Game.Rulesets.UI
HasReplayLoaded.Value = ReplayInputManager.ReplayInputHandler != null;
}
/// <summary>
/// Creates the cursor. May be null if the <see cref="RulesetContainer"/> doesn't provide a custom cursor.
/// </summary>
protected virtual CursorContainer CreateCursor() => null;
protected virtual IRulesetConfigManager CreateConfig(Ruleset ruleset, SettingsStore settings) => null;
/// <summary>
/// Creates a Playfield.
/// </summary>
@ -160,7 +155,7 @@ namespace osu.Game.Rulesets.UI
/// RulesetContainer that applies conversion to Beatmaps. Does not contain a Playfield
/// and does not load drawable hit objects.
/// <para>
/// Should not be derived - derive <see cref="RulesetContainer{TObject}"/> instead.
/// Should not be derived - derive <see cref="RulesetContainer{TPlayfield, TObject}"/> instead.
/// </para>
/// </summary>
/// <typeparam name="TObject">The type of HitObject contained by this RulesetContainer.</typeparam>
@ -194,6 +189,7 @@ namespace osu.Game.Rulesets.UI
protected override Container<Drawable> Content => content;
private Container content;
private IEnumerable<Mod> mods;
/// <summary>
/// Whether to assume the beatmap passed into this <see cref="RulesetContainer{TObject}"/> is for the current ruleset.
@ -216,13 +212,10 @@ namespace osu.Game.Rulesets.UI
KeyBindingInputManager = CreateInputManager();
KeyBindingInputManager.RelativeSizeAxes = Axes.Both;
// Add mods, should always be the last thing applied to give full control to mods
applyMods(Mods);
}
[BackgroundDependencyLoader]
private void load()
private void load(OsuConfigManager config)
{
KeyBindingInputManager.Add(content = new Container
{
@ -235,6 +228,9 @@ namespace osu.Game.Rulesets.UI
if (Cursor != null)
KeyBindingInputManager.Add(Cursor);
// Apply mods
applyMods(Mods, config);
loadObjects();
}
@ -242,13 +238,16 @@ namespace osu.Game.Rulesets.UI
/// Applies the active mods to this RulesetContainer.
/// </summary>
/// <param name="mods"></param>
private void applyMods(IEnumerable<Mod> mods)
private void applyMods(IEnumerable<Mod> mods, OsuConfigManager config)
{
if (mods == null)
return;
foreach (var mod in mods.OfType<IApplicableToRulesetContainer<TObject>>())
mod.ApplyToRulesetContainer(this);
foreach (var mod in mods.OfType<IReadFromConfig>())
mod.ReadFromConfig(config);
}
public override void SetReplay(Replay replay)

View File

@ -15,6 +15,7 @@ using osu.Game.Input.Bindings;
using osu.Game.Input.Handlers;
using osu.Game.Screens.Play;
using OpenTK.Input;
using static osu.Game.Input.Handlers.ReplayInputHandler;
namespace osu.Game.Rulesets.UI
{
@ -29,26 +30,43 @@ namespace osu.Game.Rulesets.UI
}
}
protected override InputState CreateInitialState()
{
var state = base.CreateInitialState();
return new RulesetInputManagerInputState<T>
{
Mouse = state.Mouse,
Keyboard = state.Keyboard,
Joystick = state.Joystick,
LastReplayState = null
};
}
protected readonly KeyBindingContainer<T> KeyBindingContainer;
protected override Container<Drawable> Content => KeyBindingContainer;
protected RulesetInputManager(RulesetInfo ruleset, int variant, SimultaneousBindingMode unique)
{
InternalChild = KeyBindingContainer = new RulesetKeyBindingContainer(ruleset, variant, unique);
InternalChild = KeyBindingContainer = CreateKeyBindingContainer(ruleset, variant, unique);
}
#region Action mapping (for replays)
private List<T> lastPressedActions = new List<T>();
protected override void HandleNewState(InputState state)
public override void HandleCustomInput(InputState state, IInput input)
{
base.HandleNewState(state);
if (!(input is ReplayState<T> replayState))
{
base.HandleCustomInput(state, input);
return;
}
var replayState = state as ReplayInputHandler.ReplayState<T>;
if (replayState == null) return;
if (state is RulesetInputManagerInputState<T> inputState)
{
inputState.LastReplayState = replayState;
}
// Here we handle states specifically coming from a replay source.
// These have extra action information rather than keyboard keys or mouse buttons.
@ -80,7 +98,7 @@ namespace osu.Game.Rulesets.UI
if (replayInputHandler != null) RemoveHandler(replayInputHandler);
replayInputHandler = value;
UseParentState = replayInputHandler == null;
UseParentInput = replayInputHandler == null;
if (replayInputHandler != null)
AddHandler(replayInputHandler);
@ -123,7 +141,7 @@ namespace osu.Game.Rulesets.UI
protected override bool RequiresChildrenUpdate => base.RequiresChildrenUpdate && validState;
private bool isAttached => replayInputHandler != null && !UseParentState;
private bool isAttached => replayInputHandler != null && !UseParentInput;
private const int max_catch_up_updates_per_frame = 50;
@ -249,6 +267,9 @@ namespace osu.Game.Rulesets.UI
}
#endregion
protected virtual RulesetKeyBindingContainer CreateKeyBindingContainer(RulesetInfo ruleset, int variant, SimultaneousBindingMode unique)
=> new RulesetKeyBindingContainer(ruleset, variant, unique);
}
/// <summary>
@ -267,4 +288,10 @@ namespace osu.Game.Rulesets.UI
{
void Attach(KeyCounterCollection keyCounter);
}
public class RulesetInputManagerInputState<T> : InputState
where T : struct
{
public ReplayState<T> LastReplayState;
}
}

View File

@ -29,17 +29,16 @@ namespace osu.Game.Rulesets.UI.Scrolling
/// </summary>
protected readonly SortedList<MultiplierControlPoint> ControlPoints = new SortedList<MultiplierControlPoint>();
private readonly ScrollingDirection direction;
public readonly Bindable<ScrollingDirection> Direction = new Bindable<ScrollingDirection>();
private Cached initialStateCache = new Cached();
public ScrollingHitObjectContainer(ScrollingDirection direction)
public ScrollingHitObjectContainer()
{
this.direction = direction;
RelativeSizeAxes = Axes.Both;
TimeRange.ValueChanged += v => initialStateCache.Invalidate();
TimeRange.ValueChanged += _ => initialStateCache.Invalidate();
Direction.ValueChanged += _ => initialStateCache.Invalidate();
}
private ISpeedChangeVisualiser speedChangeVisualiser;
@ -100,7 +99,7 @@ namespace osu.Game.Rulesets.UI.Scrolling
if (!initialStateCache.IsValid)
{
speedChangeVisualiser.ComputeInitialStates(Objects, direction, TimeRange, DrawSize);
speedChangeVisualiser.ComputeInitialStates(Objects, Direction, TimeRange, DrawSize);
initialStateCache.Validate();
}
}
@ -110,7 +109,7 @@ namespace osu.Game.Rulesets.UI.Scrolling
base.UpdateAfterChildrenLife();
// We need to calculate this as soon as possible after lifetimes so that hitobjects get the final say in their positions
speedChangeVisualiser.UpdatePositions(AliveObjects, direction, Time.Current, TimeRange, DrawSize);
speedChangeVisualiser.UpdatePositions(AliveObjects, Direction, Time.Current, TimeRange, DrawSize);
}
}
}

View File

@ -34,7 +34,7 @@ namespace osu.Game.Rulesets.UI.Scrolling
/// <summary>
/// The step increase/decrease of the span of time visible by the length of the scrolling axes.
/// </summary>
private const double time_span_step = 50;
private const double time_span_step = 200;
/// <summary>
/// The span of time that is visible by the length of the scrolling axes.
@ -57,7 +57,7 @@ namespace osu.Game.Rulesets.UI.Scrolling
/// </summary>
public new ScrollingHitObjectContainer HitObjects => (ScrollingHitObjectContainer)base.HitObjects;
private readonly ScrollingDirection direction;
protected readonly Bindable<ScrollingDirection> Direction = new Bindable<ScrollingDirection>();
/// <summary>
/// Creates a new <see cref="ScrollingPlayfield"/>.
@ -72,7 +72,7 @@ namespace osu.Game.Rulesets.UI.Scrolling
protected ScrollingPlayfield(ScrollingDirection direction, float? customWidth = null, float? customHeight = null)
: base(customWidth, customHeight)
{
this.direction = direction;
Direction.Value = direction;
}
[BackgroundDependencyLoader]
@ -81,8 +81,6 @@ namespace osu.Game.Rulesets.UI.Scrolling
HitObjects.TimeRange.BindTo(VisibleTimeRange);
}
protected sealed override HitObjectContainer CreateHitObjectContainer() => new ScrollingHitObjectContainer(direction);
public bool OnPressed(GlobalAction action)
{
if (!UserScrollSpeedAdjustment)
@ -102,5 +100,12 @@ namespace osu.Game.Rulesets.UI.Scrolling
}
public bool OnReleased(GlobalAction action) => false;
protected sealed override HitObjectContainer CreateHitObjectContainer()
{
var container = new ScrollingHitObjectContainer();
container.Direction.BindTo(Direction);
return container;
}
}
}

View File

@ -93,6 +93,9 @@ namespace osu.Game.Rulesets.UI.Scrolling.Visualisers
/// <returns>A positive value indicating the position at <paramref name="time"/>.</returns>
private double positionAt(double time, double timeRange)
{
if (controlPoints.Count == 0)
return time / timeRange;
double length = 0;
// We need to consider all timing points until the specified time and not just the currently-active one,