mirror of
https://github.com/ppy/osu
synced 2025-02-19 03:47:01 +00:00
Move PlayerInputManager logic inside RulesetInputManager
This commit is contained in:
parent
251b325ded
commit
189988236b
@ -9,7 +9,6 @@ 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.Screens.Play;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
@ -43,7 +42,7 @@ namespace osu.Game.Rulesets.UI
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The input manager for this RulesetContainer.
|
/// The input manager for this RulesetContainer.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal readonly PlayerInputManager InputManager = new PlayerInputManager();
|
internal IHasReplayHandler ReplayInputManager => (IHasReplayHandler)KeyBindingInputManager;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The key conversion input manager for this RulesetContainer.
|
/// The key conversion input manager for this RulesetContainer.
|
||||||
@ -58,7 +57,7 @@ namespace osu.Game.Rulesets.UI
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether we have a replay loaded currently.
|
/// Whether we have a replay loaded currently.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool HasReplayLoaded => InputManager.ReplayInputHandler != null;
|
public bool HasReplayLoaded => ReplayInputManager.ReplayInputHandler != null;
|
||||||
|
|
||||||
public abstract IEnumerable<HitObject> Objects { get; }
|
public abstract IEnumerable<HitObject> Objects { get; }
|
||||||
|
|
||||||
@ -76,11 +75,7 @@ namespace osu.Game.Rulesets.UI
|
|||||||
internal RulesetContainer(Ruleset ruleset)
|
internal RulesetContainer(Ruleset ruleset)
|
||||||
{
|
{
|
||||||
Ruleset = ruleset;
|
Ruleset = ruleset;
|
||||||
}
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
|
||||||
private void load()
|
|
||||||
{
|
|
||||||
KeyBindingInputManager = CreateInputManager();
|
KeyBindingInputManager = CreateInputManager();
|
||||||
KeyBindingInputManager.RelativeSizeAxes = Axes.Both;
|
KeyBindingInputManager.RelativeSizeAxes = Axes.Both;
|
||||||
}
|
}
|
||||||
@ -113,7 +108,7 @@ namespace osu.Game.Rulesets.UI
|
|||||||
public virtual void SetReplay(Replay replay)
|
public virtual void SetReplay(Replay replay)
|
||||||
{
|
{
|
||||||
Replay = replay;
|
Replay = replay;
|
||||||
InputManager.ReplayInputHandler = replay != null ? CreateReplayInputHandler(replay) : null;
|
ReplayInputManager.ReplayInputHandler = replay != null ? CreateReplayInputHandler(replay) : null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -267,13 +262,12 @@ namespace osu.Game.Rulesets.UI
|
|||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
{
|
{
|
||||||
InputManager.Add(content = new Container
|
KeyBindingInputManager.Add(content = new Container
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Children = new[] { KeyBindingInputManager }
|
|
||||||
});
|
});
|
||||||
|
|
||||||
AddInternal(InputManager);
|
AddInternal(KeyBindingInputManager);
|
||||||
KeyBindingInputManager.Add(Playfield = CreatePlayfield());
|
KeyBindingInputManager.Add(Playfield = CreatePlayfield());
|
||||||
|
|
||||||
loadObjects();
|
loadObjects();
|
||||||
@ -283,8 +277,8 @@ namespace osu.Game.Rulesets.UI
|
|||||||
{
|
{
|
||||||
base.SetReplay(replay);
|
base.SetReplay(replay);
|
||||||
|
|
||||||
if (InputManager?.ReplayInputHandler != null)
|
if (ReplayInputManager?.ReplayInputHandler != null)
|
||||||
InputManager.ReplayInputHandler.ToScreenSpace = Playfield.ScaledContent.ToScreenSpace;
|
ReplayInputManager.ReplayInputHandler.ToScreenSpace = input => Playfield.ScaledContent.ToScreenSpace(input);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -1,20 +1,176 @@
|
|||||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Configuration;
|
||||||
|
using osu.Framework.Input;
|
||||||
using osu.Framework.Input.Bindings;
|
using osu.Framework.Input.Bindings;
|
||||||
|
using osu.Framework.Timing;
|
||||||
|
using osu.Game.Configuration;
|
||||||
using osu.Game.Input.Bindings;
|
using osu.Game.Input.Bindings;
|
||||||
|
using osu.Game.Input.Handlers;
|
||||||
using osu.Game.Screens.Play;
|
using osu.Game.Screens.Play;
|
||||||
|
using OpenTK.Input;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.UI
|
namespace osu.Game.Rulesets.UI
|
||||||
{
|
{
|
||||||
public abstract class RulesetInputManager<T> : DatabasedKeyBindingInputManager<T>, ICanAttachKeyCounter
|
public abstract class RulesetInputManager<T> : DatabasedKeyBindingInputManager<T>, ICanAttachKeyCounter, IHasReplayHandler
|
||||||
where T : struct
|
where T : struct
|
||||||
{
|
{
|
||||||
protected RulesetInputManager(RulesetInfo ruleset, int variant, SimultaneousBindingMode unique) : base(ruleset, variant, unique)
|
protected RulesetInputManager(RulesetInfo ruleset, int variant, SimultaneousBindingMode unique) : base(ruleset, variant, unique)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<T> lastPressedActions = new List<T>();
|
||||||
|
|
||||||
|
protected override void HandleNewState(InputState state)
|
||||||
|
{
|
||||||
|
base.HandleNewState(state);
|
||||||
|
|
||||||
|
var replayState = state as ReplayInputHandler.ReplayState<T>;
|
||||||
|
|
||||||
|
if (replayState == null) return;
|
||||||
|
|
||||||
|
// Here we handle states specifically coming from a replay source.
|
||||||
|
// These have extra action information rather than keyboard keys or mouse buttons.
|
||||||
|
|
||||||
|
List<T> newActions = replayState.PressedActions;
|
||||||
|
|
||||||
|
foreach (var released in lastPressedActions.Except(newActions))
|
||||||
|
PropagateReleased(KeyBindingInputQueue, released);
|
||||||
|
|
||||||
|
foreach (var pressed in newActions.Except(lastPressedActions))
|
||||||
|
PropagatePressed(KeyBindingInputQueue, pressed);
|
||||||
|
|
||||||
|
lastPressedActions = newActions;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ManualClock clock;
|
||||||
|
private IFrameBasedClock parentClock;
|
||||||
|
|
||||||
|
private ReplayInputHandler replayInputHandler;
|
||||||
|
public ReplayInputHandler ReplayInputHandler
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return replayInputHandler;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (replayInputHandler != null) RemoveHandler(replayInputHandler);
|
||||||
|
|
||||||
|
replayInputHandler = value;
|
||||||
|
UseParentState = replayInputHandler == null;
|
||||||
|
|
||||||
|
if (replayInputHandler != null)
|
||||||
|
AddHandler(replayInputHandler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Bindable<bool> mouseDisabled;
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuConfigManager config)
|
||||||
|
{
|
||||||
|
mouseDisabled = config.GetBindable<bool>(OsuSetting.MouseDisableButtons);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
|
//our clock will now be our parent's clock, but we want to replace this to allow manual control.
|
||||||
|
parentClock = Clock;
|
||||||
|
|
||||||
|
Clock = new FramedClock(clock = new ManualClock
|
||||||
|
{
|
||||||
|
CurrentTime = parentClock.CurrentTime,
|
||||||
|
Rate = parentClock.Rate,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether we running up-to-date with our parent clock.
|
||||||
|
/// If not, we will need to keep processing children until we catch up.
|
||||||
|
/// </summary>
|
||||||
|
private bool requireMoreUpdateLoops;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether we in a valid state (ie. should we keep processing children frames).
|
||||||
|
/// This should be set to false when the replay is, for instance, waiting for future frames to arrive.
|
||||||
|
/// </summary>
|
||||||
|
private bool validState;
|
||||||
|
|
||||||
|
protected override bool RequiresChildrenUpdate => base.RequiresChildrenUpdate && validState;
|
||||||
|
|
||||||
|
private bool isAttached => replayInputHandler != null && !UseParentState;
|
||||||
|
|
||||||
|
private const int max_catch_up_updates_per_frame = 50;
|
||||||
|
|
||||||
|
public override bool UpdateSubTree()
|
||||||
|
{
|
||||||
|
requireMoreUpdateLoops = true;
|
||||||
|
validState = true;
|
||||||
|
|
||||||
|
int loops = 0;
|
||||||
|
|
||||||
|
while (validState && requireMoreUpdateLoops && loops++ < max_catch_up_updates_per_frame)
|
||||||
|
if (!base.UpdateSubTree())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Update()
|
||||||
|
{
|
||||||
|
if (parentClock == null) return;
|
||||||
|
|
||||||
|
clock.Rate = parentClock.Rate;
|
||||||
|
clock.IsRunning = parentClock.IsRunning;
|
||||||
|
|
||||||
|
if (!isAttached)
|
||||||
|
{
|
||||||
|
clock.CurrentTime = parentClock.CurrentTime;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
double? newTime = replayInputHandler.SetFrameFromTime(parentClock.CurrentTime);
|
||||||
|
|
||||||
|
if (newTime == null)
|
||||||
|
{
|
||||||
|
// we shouldn't execute for this time value. probably waiting on more replay data.
|
||||||
|
validState = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
clock.CurrentTime = newTime.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
requireMoreUpdateLoops = clock.CurrentTime != parentClock.CurrentTime;
|
||||||
|
base.Update();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void TransformState(InputState state)
|
||||||
|
{
|
||||||
|
base.TransformState(state);
|
||||||
|
|
||||||
|
// we don't want to transform the state if a replay is present (for now, at least).
|
||||||
|
if (replayInputHandler != null) return;
|
||||||
|
|
||||||
|
var mouse = state.Mouse as Framework.Input.MouseState;
|
||||||
|
|
||||||
|
if (mouse != null)
|
||||||
|
{
|
||||||
|
if (mouseDisabled.Value)
|
||||||
|
{
|
||||||
|
mouse.SetPressed(MouseButton.Left, false);
|
||||||
|
mouse.SetPressed(MouseButton.Right, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void Attach(KeyCounterCollection keyCounter)
|
public void Attach(KeyCounterCollection keyCounter)
|
||||||
{
|
{
|
||||||
var receptor = new ActionReceptor(keyCounter);
|
var receptor = new ActionReceptor(keyCounter);
|
||||||
@ -37,6 +193,11 @@ namespace osu.Game.Rulesets.UI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public interface IHasReplayHandler
|
||||||
|
{
|
||||||
|
ReplayInputHandler ReplayInputHandler { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
public interface ICanAttachKeyCounter
|
public interface ICanAttachKeyCounter
|
||||||
{
|
{
|
||||||
void Attach(KeyCounterCollection keyCounter);
|
void Attach(KeyCounterCollection keyCounter);
|
||||||
|
@ -1,140 +0,0 @@
|
|||||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
|
||||||
|
|
||||||
using OpenTK.Input;
|
|
||||||
using osu.Framework.Allocation;
|
|
||||||
using osu.Framework.Configuration;
|
|
||||||
using osu.Framework.Input;
|
|
||||||
using osu.Framework.Timing;
|
|
||||||
using osu.Game.Configuration;
|
|
||||||
using osu.Game.Input.Handlers;
|
|
||||||
|
|
||||||
namespace osu.Game.Screens.Play
|
|
||||||
{
|
|
||||||
public class PlayerInputManager : PassThroughInputManager
|
|
||||||
{
|
|
||||||
private ManualClock clock;
|
|
||||||
private IFrameBasedClock parentClock;
|
|
||||||
|
|
||||||
private ReplayInputHandler replayInputHandler;
|
|
||||||
public ReplayInputHandler ReplayInputHandler
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return replayInputHandler;
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (replayInputHandler != null) RemoveHandler(replayInputHandler);
|
|
||||||
|
|
||||||
replayInputHandler = value;
|
|
||||||
UseParentState = replayInputHandler == null;
|
|
||||||
|
|
||||||
if (replayInputHandler != null)
|
|
||||||
AddHandler(replayInputHandler);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Bindable<bool> mouseDisabled;
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
|
||||||
private void load(OsuConfigManager config)
|
|
||||||
{
|
|
||||||
mouseDisabled = config.GetBindable<bool>(OsuSetting.MouseDisableButtons);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void LoadComplete()
|
|
||||||
{
|
|
||||||
base.LoadComplete();
|
|
||||||
|
|
||||||
//our clock will now be our parent's clock, but we want to replace this to allow manual control.
|
|
||||||
parentClock = Clock;
|
|
||||||
|
|
||||||
Clock = new FramedClock(clock = new ManualClock
|
|
||||||
{
|
|
||||||
CurrentTime = parentClock.CurrentTime,
|
|
||||||
Rate = parentClock.Rate,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Whether we running up-to-date with our parent clock.
|
|
||||||
/// If not, we will need to keep processing children until we catch up.
|
|
||||||
/// </summary>
|
|
||||||
private bool requireMoreUpdateLoops;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Whether we in a valid state (ie. should we keep processing children frames).
|
|
||||||
/// This should be set to false when the replay is, for instance, waiting for future frames to arrive.
|
|
||||||
/// </summary>
|
|
||||||
private bool validState;
|
|
||||||
|
|
||||||
protected override bool RequiresChildrenUpdate => base.RequiresChildrenUpdate && validState;
|
|
||||||
|
|
||||||
private bool isAttached => replayInputHandler != null && !UseParentState;
|
|
||||||
|
|
||||||
private const int max_catch_up_updates_per_frame = 50;
|
|
||||||
|
|
||||||
public override bool UpdateSubTree()
|
|
||||||
{
|
|
||||||
requireMoreUpdateLoops = true;
|
|
||||||
validState = true;
|
|
||||||
|
|
||||||
int loops = 0;
|
|
||||||
|
|
||||||
while (validState && requireMoreUpdateLoops && loops++ < max_catch_up_updates_per_frame)
|
|
||||||
if (!base.UpdateSubTree())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Update()
|
|
||||||
{
|
|
||||||
if (parentClock == null) return;
|
|
||||||
|
|
||||||
clock.Rate = parentClock.Rate;
|
|
||||||
clock.IsRunning = parentClock.IsRunning;
|
|
||||||
|
|
||||||
if (!isAttached)
|
|
||||||
{
|
|
||||||
clock.CurrentTime = parentClock.CurrentTime;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
double? newTime = replayInputHandler.SetFrameFromTime(parentClock.CurrentTime);
|
|
||||||
|
|
||||||
if (newTime == null)
|
|
||||||
{
|
|
||||||
// we shouldn't execute for this time value. probably waiting on more replay data.
|
|
||||||
validState = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
clock.CurrentTime = newTime.Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
requireMoreUpdateLoops = clock.CurrentTime != parentClock.CurrentTime;
|
|
||||||
base.Update();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void TransformState(InputState state)
|
|
||||||
{
|
|
||||||
base.TransformState(state);
|
|
||||||
|
|
||||||
// we don't want to transform the state if a replay is present (for now, at least).
|
|
||||||
if (replayInputHandler != null) return;
|
|
||||||
|
|
||||||
var mouse = state.Mouse as Framework.Input.MouseState;
|
|
||||||
|
|
||||||
if (mouse != null)
|
|
||||||
{
|
|
||||||
if (mouseDisabled.Value)
|
|
||||||
{
|
|
||||||
mouse.SetPressed(MouseButton.Left, false);
|
|
||||||
mouse.SetPressed(MouseButton.Right, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -321,7 +321,6 @@
|
|||||||
<Compile Include="Screens\Multiplayer\MatchCreate.cs" />
|
<Compile Include="Screens\Multiplayer\MatchCreate.cs" />
|
||||||
<Compile Include="Screens\Play\FailOverlay.cs" />
|
<Compile Include="Screens\Play\FailOverlay.cs" />
|
||||||
<Compile Include="Screens\Play\MenuOverlay.cs" />
|
<Compile Include="Screens\Play\MenuOverlay.cs" />
|
||||||
<Compile Include="Screens\Play\PlayerInputManager.cs" />
|
|
||||||
<Compile Include="Screens\Play\PlayerLoader.cs" />
|
<Compile Include="Screens\Play\PlayerLoader.cs" />
|
||||||
<Compile Include="Screens\Play\ReplayPlayer.cs" />
|
<Compile Include="Screens\Play\ReplayPlayer.cs" />
|
||||||
<Compile Include="Screens\Play\SkipButton.cs" />
|
<Compile Include="Screens\Play\SkipButton.cs" />
|
||||||
|
Loading…
Reference in New Issue
Block a user