1
0
mirror of https://github.com/ppy/osu.git synced 2025-02-16 15:43:18 +08:00

Merge branch 'master' into mask-settings-overlay

This commit is contained in:
Dean Herbert 2017-08-22 00:22:39 +09:00 committed by GitHub
commit 7693fc1382
60 changed files with 552 additions and 335 deletions

@ -1 +1 @@
Subproject commit 825505e788c4f093b269c61b485d38d50cd68096 Subproject commit f1527e5456cd228ddfb68cf6d56eb5d28dc360bf

View File

@ -2,12 +2,8 @@
// 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 osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.MathUtils; using osu.Framework.MathUtils;
using osu.Game.Screens.Play; using osu.Game.Screens.Play;
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Input; using OpenTK.Input;
namespace osu.Desktop.Tests.Visual namespace osu.Desktop.Tests.Visual
@ -41,38 +37,5 @@ namespace osu.Desktop.Tests.Visual
Add(kc); Add(kc);
} }
private class TestSliderBar<T> : SliderBar<T> where T : struct
{
public Color4 Color
{
get { return Box.Colour; }
set { Box.Colour = value; }
}
public Color4 SelectionColor
{
get { return SelectionBox.Colour; }
set { SelectionBox.Colour = value; }
}
protected readonly Box SelectionBox;
protected readonly Box Box;
public TestSliderBar()
{
Children = new Drawable[]
{
Box = new Box { RelativeSizeAxes = Axes.Both },
SelectionBox = new Box { RelativeSizeAxes = Axes.Both }
};
}
protected override void UpdateValue(float value)
{
SelectionBox.ScaleTo(
new Vector2(value, 1),
300, Easing.OutQuint);
}
}
} }
} }

View File

@ -8,6 +8,7 @@ using osu.Desktop.Tests.Beatmaps;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Input;
using osu.Framework.Timing; using osu.Framework.Timing;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Rulesets.Beatmaps; using osu.Game.Rulesets.Beatmaps;
@ -77,6 +78,8 @@ namespace osu.Desktop.Tests.Visual
public override ScoreProcessor CreateScoreProcessor() => new TestScoreProcessor(); public override ScoreProcessor CreateScoreProcessor() => new TestScoreProcessor();
public override PassThroughInputManager CreateInputManager() => new PassThroughInputManager();
protected override BeatmapConverter<TestHitObject> CreateBeatmapConverter() => new TestBeatmapConverter(); protected override BeatmapConverter<TestHitObject> CreateBeatmapConverter() => new TestBeatmapConverter();
protected override Playfield<TestHitObject, TestJudgement> CreatePlayfield() => new TestPlayfield(scrollingAxes); protected override Playfield<TestHitObject, TestJudgement> CreatePlayfield() => new TestPlayfield(scrollingAxes);

View File

@ -16,6 +16,8 @@ using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Desktop.Tests.Beatmaps; using osu.Desktop.Tests.Beatmaps;
using System.Collections.Generic; using System.Collections.Generic;
using osu.Framework.Allocation;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects;
namespace osu.Desktop.Tests.Visual namespace osu.Desktop.Tests.Visual
@ -30,10 +32,11 @@ namespace osu.Desktop.Tests.Visual
protected override double TimePerAction => default_duration * 2; protected override double TimePerAction => default_duration * 2;
private readonly Random rng = new Random(1337); private readonly Random rng = new Random(1337);
private readonly TaikoRulesetContainer rulesetContainer; private TaikoRulesetContainer rulesetContainer;
private readonly Container playfieldContainer; private Container playfieldContainer;
public TestCaseTaikoPlayfield() [BackgroundDependencyLoader]
private void load(RulesetStore rulesets)
{ {
AddStep("Hit!", () => addHitJudgement(false)); AddStep("Hit!", () => addHitJudgement(false));
AddStep("Kiai hit", () => addHitJudgement(true)); AddStep("Kiai hit", () => addHitJudgement(true));
@ -82,7 +85,7 @@ namespace osu.Desktop.Tests.Visual
RelativeSizeAxes = Axes.X, RelativeSizeAxes = Axes.X,
Height = 768, Height = 768,
Clock = new FramedClock(rateAdjustClock), Clock = new FramedClock(rateAdjustClock),
Children = new[] { rulesetContainer = new TaikoRulesetContainer(null, beatmap, true) } Children = new[] { rulesetContainer = new TaikoRulesetContainer(rulesets.GetRuleset(1).CreateInstance(), beatmap, true) }
}); });
} }

View File

@ -3,11 +3,11 @@
using System.ComponentModel; using System.ComponentModel;
using osu.Framework.Input.Bindings; using osu.Framework.Input.Bindings;
using osu.Game.Input.Bindings; using osu.Game.Rulesets.UI;
namespace osu.Game.Rulesets.Catch namespace osu.Game.Rulesets.Catch
{ {
public class CatchInputManager : DatabasedKeyBindingInputManager<CatchAction> public class CatchInputManager : RulesetInputManager<CatchAction>
{ {
public CatchInputManager(RulesetInfo ruleset) public CatchInputManager(RulesetInfo ruleset)
: base(ruleset, 0, SimultaneousBindingMode.Unique) : base(ruleset, 0, SimultaneousBindingMode.Unique)

View File

@ -1,14 +1,12 @@
// 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 OpenTK.Input;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Rulesets.Catch.Mods; using osu.Game.Rulesets.Catch.Mods;
using osu.Game.Rulesets.Catch.UI; using osu.Game.Rulesets.Catch.UI;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI;
using osu.Game.Screens.Play;
using System.Collections.Generic; using System.Collections.Generic;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Game.Rulesets.Catch.Scoring; using osu.Game.Rulesets.Catch.Scoring;
@ -101,13 +99,6 @@ namespace osu.Game.Rulesets.Catch
public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_osu_fruits_o }; public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_osu_fruits_o };
public override IEnumerable<KeyCounter> CreateGameplayKeys() => new KeyCounter[]
{
new KeyCounterKeyboard(Key.ShiftLeft),
new KeyCounterMouse(MouseButton.Left),
new KeyCounterMouse(MouseButton.Right)
};
public override DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap) => new CatchDifficultyCalculator(beatmap); public override DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap) => new CatchDifficultyCalculator(beatmap);
public override ScoreProcessor CreateScoreProcessor() => new CatchScoreProcessor(); public override ScoreProcessor CreateScoreProcessor() => new CatchScoreProcessor();

View File

@ -28,7 +28,7 @@ namespace osu.Game.Rulesets.Catch.UI
protected override Playfield<CatchBaseHit, CatchJudgement> CreatePlayfield() => new CatchPlayfield(); protected override Playfield<CatchBaseHit, CatchJudgement> CreatePlayfield() => new CatchPlayfield();
public override PassThroughInputManager CreateKeyBindingInputManager() => new CatchInputManager(Ruleset?.RulesetInfo); public override PassThroughInputManager CreateInputManager() => new CatchInputManager(Ruleset.RulesetInfo);
protected override DrawableHitObject<CatchBaseHit, CatchJudgement> GetVisualRepresentation(CatchBaseHit h) protected override DrawableHitObject<CatchBaseHit, CatchJudgement> GetVisualRepresentation(CatchBaseHit h)
{ {

View File

@ -47,7 +47,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
// The true distance, accounting for any repeats // The true distance, accounting for any repeats
double distance = (distanceData?.Distance ?? 0) * repeatCount; double distance = (distanceData?.Distance ?? 0) * repeatCount;
// The velocity of the osu! hit object - calculated as the velocity of a slider // The velocity of the osu! hit object - calculated as the velocity of a slider
double osuVelocity = osu_base_scoring_distance * beatmap.BeatmapInfo.Difficulty.SliderMultiplier / (timingPoint.BeatLength * difficultyPoint.SpeedMultiplier); double osuVelocity = osu_base_scoring_distance * beatmap.BeatmapInfo.Difficulty.SliderMultiplier * difficultyPoint.SpeedMultiplier / timingPoint.BeatLength;
// The duration of the osu! hit object // The duration of the osu! hit object
double osuDuration = distance / osuVelocity; double osuDuration = distance / osuVelocity;

View File

@ -0,0 +1,21 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Input.Bindings;
using osu.Game.Rulesets.UI;
namespace osu.Game.Rulesets.Mania
{
public class ManiaInputManager : RulesetInputManager<ManiaAction>
{
public ManiaInputManager(RulesetInfo ruleset)
: base(ruleset, 0, SimultaneousBindingMode.Unique)
{
}
}
public enum ManiaAction
{
// placeholder
}
}

View File

@ -6,7 +6,6 @@ using osu.Game.Rulesets.Mania.Mods;
using osu.Game.Rulesets.Mania.UI; using osu.Game.Rulesets.Mania.UI;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI;
using osu.Game.Screens.Play;
using System.Collections.Generic; using System.Collections.Generic;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Game.Graphics; using osu.Game.Graphics;
@ -111,8 +110,6 @@ namespace osu.Game.Rulesets.Mania
public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_osu_mania_o }; public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_osu_mania_o };
public override IEnumerable<KeyCounter> CreateGameplayKeys() => new KeyCounter[] { /* Todo: Should be keymod specific */ };
public override DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap) => new ManiaDifficultyCalculator(beatmap); public override DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap) => new ManiaDifficultyCalculator(beatmap);
public override ScoreProcessor CreateScoreProcessor() => new ManiaScoreProcessor(); public override ScoreProcessor CreateScoreProcessor() => new ManiaScoreProcessor();

View File

@ -10,6 +10,7 @@ using osu.Framework.Allocation;
using osu.Framework.Configuration; using osu.Framework.Configuration;
using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Input;
using osu.Framework.Lists; using osu.Framework.Lists;
using osu.Framework.MathUtils; using osu.Framework.MathUtils;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
@ -92,6 +93,8 @@ namespace osu.Game.Rulesets.Mania.UI
public override ScoreProcessor CreateScoreProcessor() => new ManiaScoreProcessor(this); 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() => new ManiaBeatmapConverter();
protected override DrawableHitObject<ManiaHitObject, ManiaJudgement> GetVisualRepresentation(ManiaHitObject h) protected override DrawableHitObject<ManiaHitObject, ManiaJudgement> GetVisualRepresentation(ManiaHitObject h)

View File

@ -79,6 +79,7 @@
<Compile Include="Objects\ManiaHitObject.cs" /> <Compile Include="Objects\ManiaHitObject.cs" />
<Compile Include="Objects\Note.cs" /> <Compile Include="Objects\Note.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ManiaInputManager.cs" />
<Compile Include="Timing\GravityScrollingContainer.cs" /> <Compile Include="Timing\GravityScrollingContainer.cs" />
<Compile Include="Timing\ScrollingAlgorithm.cs" /> <Compile Include="Timing\ScrollingAlgorithm.cs" />
<Compile Include="UI\Column.cs" /> <Compile Include="UI\Column.cs" />

View File

@ -6,6 +6,7 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Input; using osu.Framework.Input;
using OpenTK;
using OpenTK.Graphics; using OpenTK.Graphics;
namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
@ -97,11 +98,14 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
return base.OnMouseMove(state); return base.OnMouseMove(state);
} }
// If the current time is between the start and end of the slider, we should track mouse input regardless of the cursor position.
public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => canCurrentlyTrack || base.ReceiveMouseInputAt(screenSpacePos);
private bool tracking; private bool tracking;
public bool Tracking public bool Tracking
{ {
get { return tracking; } get { return tracking; }
set private set
{ {
if (value == tracking) return; if (value == tracking) return;
@ -118,8 +122,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
{ {
base.Update(); base.Update();
// Make sure to use the base version of ReceiveMouseInputAt so that we correctly check the position.
if (Time.Current < slider.EndTime) if (Time.Current < slider.EndTime)
Tracking = canCurrentlyTrack && lastState != null && ReceiveMouseInputAt(lastState.Mouse.NativeState.Position) && ((Parent as DrawableSlider)?.OsuActionInputManager?.PressedActions.Any(x => x == OsuAction.LeftButton || x == OsuAction.RightButton) ?? false); Tracking = canCurrentlyTrack && lastState != null && base.ReceiveMouseInputAt(lastState.Mouse.NativeState.Position) && ((Parent as DrawableSlider)?.OsuActionInputManager?.PressedActions.Any(x => x == OsuAction.LeftButton || x == OsuAction.RightButton) ?? false);
} }
public void UpdateProgress(double progress, int repeat) public void UpdateProgress(double progress, int repeat)

View File

@ -69,7 +69,7 @@ namespace osu.Game.Rulesets.Osu.Objects
TimingControlPoint timingPoint = controlPointInfo.TimingPointAt(StartTime); TimingControlPoint timingPoint = controlPointInfo.TimingPointAt(StartTime);
DifficultyControlPoint difficultyPoint = controlPointInfo.DifficultyPointAt(StartTime); DifficultyControlPoint difficultyPoint = controlPointInfo.DifficultyPointAt(StartTime);
double scoringDistance = base_scoring_distance * difficulty.SliderMultiplier / difficultyPoint.SpeedMultiplier; double scoringDistance = base_scoring_distance * difficulty.SliderMultiplier * difficultyPoint.SpeedMultiplier;
Velocity = scoringDistance / timingPoint.BeatLength; Velocity = scoringDistance / timingPoint.BeatLength;
TickDistance = scoringDistance / difficulty.SliderTickRate; TickDistance = scoringDistance / difficulty.SliderTickRate;

View File

@ -3,11 +3,11 @@
using System.ComponentModel; using System.ComponentModel;
using osu.Framework.Input.Bindings; using osu.Framework.Input.Bindings;
using osu.Game.Input.Bindings; using osu.Game.Rulesets.UI;
namespace osu.Game.Rulesets.Osu namespace osu.Game.Rulesets.Osu
{ {
public class OsuInputManager : DatabasedKeyBindingInputManager<OsuAction> public class OsuInputManager : RulesetInputManager<OsuAction>
{ {
public OsuInputManager(RulesetInfo ruleset) : base(ruleset, 0, SimultaneousBindingMode.Unique) public OsuInputManager(RulesetInfo ruleset) : base(ruleset, 0, SimultaneousBindingMode.Unique)
{ {

View File

@ -1,7 +1,6 @@
// 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 OpenTK.Input;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
@ -10,7 +9,6 @@ using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.OsuDifficulty; using osu.Game.Rulesets.Osu.OsuDifficulty;
using osu.Game.Rulesets.Osu.UI; using osu.Game.Rulesets.Osu.UI;
using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI;
using osu.Game.Screens.Play;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using osu.Framework.Graphics; using osu.Framework.Graphics;
@ -29,8 +27,8 @@ namespace osu.Game.Rulesets.Osu
{ {
new KeyBinding(InputKey.Z, OsuAction.LeftButton), new KeyBinding(InputKey.Z, OsuAction.LeftButton),
new KeyBinding(InputKey.X, OsuAction.RightButton), new KeyBinding(InputKey.X, OsuAction.RightButton),
new KeyBinding(InputKey.LastKey + 1, OsuAction.LeftButton), new KeyBinding(InputKey.MouseLeft, OsuAction.LeftButton),
new KeyBinding(InputKey.LastKey + 2, OsuAction.RightButton), new KeyBinding(InputKey.MouseRight, OsuAction.RightButton),
}; };
public override IEnumerable<BeatmapStatistic> GetBeatmapStatistics(WorkingBeatmap beatmap) => new[] public override IEnumerable<BeatmapStatistic> GetBeatmapStatistics(WorkingBeatmap beatmap) => new[]
@ -122,14 +120,6 @@ namespace osu.Game.Rulesets.Osu
public override string Description => "osu!"; public override string Description => "osu!";
public override IEnumerable<KeyCounter> CreateGameplayKeys() => new KeyCounter[]
{
new KeyCounterKeyboard(Key.Z),
new KeyCounterKeyboard(Key.X),
new KeyCounterMouse(MouseButton.Left),
new KeyCounterMouse(MouseButton.Right)
};
public override ScoreProcessor CreateScoreProcessor() => new OsuScoreProcessor(); public override ScoreProcessor CreateScoreProcessor() => new OsuScoreProcessor();
public override SettingsSubsection CreateSettings() => new OsuSettings(); public override SettingsSubsection CreateSettings() => new OsuSettings();

View File

@ -31,7 +31,7 @@ namespace osu.Game.Rulesets.Osu.UI
protected override Playfield<OsuHitObject, OsuJudgement> CreatePlayfield() => new OsuPlayfield(); protected override Playfield<OsuHitObject, OsuJudgement> CreatePlayfield() => new OsuPlayfield();
public override PassThroughInputManager CreateKeyBindingInputManager() => new OsuInputManager(Ruleset?.RulesetInfo); public override PassThroughInputManager CreateInputManager() => new OsuInputManager(Ruleset.RulesetInfo);
protected override DrawableHitObject<OsuHitObject, OsuJudgement> GetVisualRepresentation(OsuHitObject h) protected override DrawableHitObject<OsuHitObject, OsuJudgement> GetVisualRepresentation(OsuHitObject h)
{ {

View File

@ -39,10 +39,14 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
/// </summary> /// </summary>
private const float taiko_base_distance = 100; private const float taiko_base_distance = 100;
private bool isForCurrentRuleset;
protected override IEnumerable<Type> ValidConversionTypes { get; } = new[] { typeof(HitObject) }; protected override IEnumerable<Type> ValidConversionTypes { get; } = new[] { typeof(HitObject) };
protected override Beatmap<TaikoHitObject> ConvertBeatmap(Beatmap original, bool isForCurrentRuleset) protected override Beatmap<TaikoHitObject> ConvertBeatmap(Beatmap original, bool isForCurrentRuleset)
{ {
this.isForCurrentRuleset = isForCurrentRuleset;
// Rewrite the beatmap info to add the slider velocity multiplier // Rewrite the beatmap info to add the slider velocity multiplier
BeatmapInfo info = original.BeatmapInfo.DeepClone(); BeatmapInfo info = original.BeatmapInfo.DeepClone();
info.Difficulty.SliderMultiplier *= legacy_velocity_multiplier; info.Difficulty.SliderMultiplier *= legacy_velocity_multiplier;
@ -81,7 +85,7 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
DifficultyControlPoint difficultyPoint = beatmap.ControlPointInfo.DifficultyPointAt(obj.StartTime); DifficultyControlPoint difficultyPoint = beatmap.ControlPointInfo.DifficultyPointAt(obj.StartTime);
double speedAdjustment = difficultyPoint.SpeedMultiplier; double speedAdjustment = difficultyPoint.SpeedMultiplier;
double speedAdjustedBeatLength = timingPoint.BeatLength * speedAdjustment; double speedAdjustedBeatLength = timingPoint.BeatLength / speedAdjustment;
// The true distance, accounting for any repeats. This ends up being the drum roll distance later // The true distance, accounting for any repeats. This ends up being the drum roll distance later
double distance = distanceData.Distance * repeats * legacy_velocity_multiplier; double distance = distanceData.Distance * repeats * legacy_velocity_multiplier;
@ -94,7 +98,7 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
// For some reason, old osu! always uses speedAdjustment to determine the taiko velocity, but // For some reason, old osu! always uses speedAdjustment to determine the taiko velocity, but
// only uses it to determine osu! velocity if beatmap version < 8. Let's account for that here. // only uses it to determine osu! velocity if beatmap version < 8. Let's account for that here.
if (beatmap.BeatmapInfo.BeatmapVersion >= 8) if (beatmap.BeatmapInfo.BeatmapVersion >= 8)
speedAdjustedBeatLength /= speedAdjustment; speedAdjustedBeatLength *= speedAdjustment;
// The velocity of the osu! hit object - calculated as the velocity of a slider // The velocity of the osu! hit object - calculated as the velocity of a slider
double osuVelocity = osu_base_scoring_distance * beatmap.BeatmapInfo.Difficulty.SliderMultiplier * legacy_velocity_multiplier / speedAdjustedBeatLength; double osuVelocity = osu_base_scoring_distance * beatmap.BeatmapInfo.Difficulty.SliderMultiplier * legacy_velocity_multiplier / speedAdjustedBeatLength;
@ -104,7 +108,7 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
// If the drum roll is to be split into hit circles, assume the ticks are 1/8 spaced within the duration of one beat // If the drum roll is to be split into hit circles, assume the ticks are 1/8 spaced within the duration of one beat
double tickSpacing = Math.Min(speedAdjustedBeatLength / beatmap.BeatmapInfo.Difficulty.SliderTickRate, taikoDuration / repeats); double tickSpacing = Math.Min(speedAdjustedBeatLength / beatmap.BeatmapInfo.Difficulty.SliderTickRate, taikoDuration / repeats);
if (tickSpacing > 0 && osuDuration < 2 * speedAdjustedBeatLength) if (!isForCurrentRuleset && tickSpacing > 0 && osuDuration < 2 * speedAdjustedBeatLength)
{ {
List<SampleInfoList> allSamples = curveData != null ? curveData.RepeatSamples : new List<SampleInfoList>(new[] { samples }); List<SampleInfoList> allSamples = curveData != null ? curveData.RepeatSamples : new List<SampleInfoList>(new[] { samples });

View File

@ -58,10 +58,10 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
}; };
} }
protected override TaikoJudgement CreateJudgement() => new TaikoJudgement(); protected override TaikoJudgement CreateJudgement() => null;
protected override void UpdateState(ArmedState state) protected override void UpdateState(ArmedState state)
{ {
} }
} }
} }

View File

@ -20,10 +20,12 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
/// </summary> /// </summary>
private const float triangle_size = 20f; private const float triangle_size = 20f;
private readonly Container triangleContainer;
public DrawableBarLineMajor(BarLine barLine) public DrawableBarLineMajor(BarLine barLine)
: base(barLine) : base(barLine)
{ {
Add(new Container Add(triangleContainer = new Container
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
@ -53,5 +55,13 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
Tracker.Alpha = 1f; Tracker.Alpha = 1f;
} }
protected override void LoadComplete()
{
base.LoadComplete();
using (triangleContainer.BeginAbsoluteSequence(HitObject.StartTime))
triangleContainer.FadeOut(150);
}
} }
} }

View File

@ -4,13 +4,12 @@
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces; using osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces;
using OpenTK.Input;
namespace osu.Game.Rulesets.Taiko.Objects.Drawables namespace osu.Game.Rulesets.Taiko.Objects.Drawables
{ {
public class DrawableCentreHit : DrawableHit public class DrawableCentreHit : DrawableHit
{ {
protected override Key[] HitKeys { get; } = { Key.F, Key.J }; protected override TaikoAction[] HitActions { get; } = { TaikoAction.LeftCentre, TaikoAction.RightCentre };
public DrawableCentreHit(Hit hit) public DrawableCentreHit(Hit hit)
: base(hit) : base(hit)

View File

@ -4,13 +4,12 @@
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces; using osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces;
using OpenTK.Input;
namespace osu.Game.Rulesets.Taiko.Objects.Drawables namespace osu.Game.Rulesets.Taiko.Objects.Drawables
{ {
public class DrawableCentreHitStrong : DrawableHitStrong public class DrawableCentreHitStrong : DrawableHitStrong
{ {
protected override Key[] HitKeys { get; } = { Key.F, Key.J }; protected override TaikoAction[] HitActions { get; } = { TaikoAction.LeftCentre, TaikoAction.RightCentre };
public DrawableCentreHitStrong(Hit hit) public DrawableCentreHitStrong(Hit hit)
: base(hit) : base(hit)

View File

@ -56,6 +56,8 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
protected override TaikoPiece CreateMainPiece() => new ElongatedCirclePiece(); protected override TaikoPiece CreateMainPiece() => new ElongatedCirclePiece();
public override bool OnPressed(TaikoAction action) => false;
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuColour colours) private void load(OsuColour colours)
{ {

View File

@ -5,7 +5,6 @@ using System;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Taiko.Judgements; using osu.Game.Rulesets.Taiko.Judgements;
using OpenTK.Input;
using osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces; using osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces;
namespace osu.Game.Rulesets.Taiko.Objects.Drawables namespace osu.Game.Rulesets.Taiko.Objects.Drawables
@ -59,7 +58,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
} }
} }
protected override bool HandleKeyPress(Key key) public override bool OnPressed(TaikoAction action)
{ {
return Judgement.Result == HitResult.None && UpdateJudgement(true); return Judgement.Result == HitResult.None && UpdateJudgement(true);
} }

View File

@ -7,7 +7,6 @@ using osu.Framework.Graphics;
using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Taiko.Judgements; using osu.Game.Rulesets.Taiko.Judgements;
using osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces; using osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces;
using OpenTK.Input;
namespace osu.Game.Rulesets.Taiko.Objects.Drawables namespace osu.Game.Rulesets.Taiko.Objects.Drawables
{ {
@ -16,7 +15,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
/// <summary> /// <summary>
/// A list of keys which can result in hits for this HitObject. /// A list of keys which can result in hits for this HitObject.
/// </summary> /// </summary>
protected abstract Key[] HitKeys { get; } protected abstract TaikoAction[] HitActions { get; }
/// <summary> /// <summary>
/// Whether the last key pressed is a valid hit key. /// Whether the last key pressed is a valid hit key.
@ -62,12 +61,12 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
Judgement.Result = HitResult.Miss; Judgement.Result = HitResult.Miss;
} }
protected override bool HandleKeyPress(Key key) public override bool OnPressed(TaikoAction action)
{ {
if (Judgement.Result != HitResult.None) if (Judgement.Result != HitResult.None)
return false; return false;
validKeyPressed = HitKeys.Contains(key); validKeyPressed = HitActions.Contains(action);
return UpdateJudgement(true); return UpdateJudgement(true);
} }

View File

@ -3,10 +3,8 @@
using System; using System;
using System.Linq; using System.Linq;
using osu.Framework.Input;
using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Taiko.Judgements; using osu.Game.Rulesets.Taiko.Judgements;
using OpenTK.Input;
namespace osu.Game.Rulesets.Taiko.Objects.Drawables namespace osu.Game.Rulesets.Taiko.Objects.Drawables
{ {
@ -20,7 +18,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
private double firstHitTime; private double firstHitTime;
private bool firstKeyHeld; private bool firstKeyHeld;
private Key firstHitKey; private TaikoAction firstHitAction;
protected DrawableHitStrong(Hit hit) protected DrawableHitStrong(Hit hit)
: base(hit) : base(hit)
@ -46,18 +44,26 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
Judgement.SecondHit = true; Judgement.SecondHit = true;
} }
protected override bool HandleKeyPress(Key key) public override bool OnReleased(TaikoAction action)
{
if (action == firstHitAction)
firstKeyHeld = false;
return base.OnReleased(action);
}
public override bool OnPressed(TaikoAction action)
{ {
// Check if we've handled the first key // Check if we've handled the first key
if (Judgement.Result == HitResult.None) if (Judgement.Result == HitResult.None)
{ {
// First key hasn't been handled yet, attempt to handle it // First key hasn't been handled yet, attempt to handle it
bool handled = base.HandleKeyPress(key); bool handled = base.OnPressed(action);
if (handled) if (handled)
{ {
firstHitTime = Time.Current; firstHitTime = Time.Current;
firstHitKey = key; firstHitAction = action;
firstKeyHeld = true;
} }
return handled; return handled;
@ -68,22 +74,15 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
return false; return false;
// Don't handle represses of the first key // Don't handle represses of the first key
if (firstHitKey == key) if (firstHitAction == action)
return false; return false;
// Don't handle invalid hit key presses // Don't handle invalid hit action presses
if (!HitKeys.Contains(key)) if (!HitActions.Contains(action))
return false; return false;
// Assume the intention was to hit the strong hit with both keys only if the first key is still being held down // Assume the intention was to hit the strong hit with both keys only if the first key is still being held down
return firstKeyHeld && UpdateJudgement(true); return firstKeyHeld && UpdateJudgement(true);
} }
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
{
firstKeyHeld = state.Keyboard.Keys.Contains(firstHitKey);
return base.OnKeyDown(state, args);
}
} }
} }

View File

@ -4,13 +4,12 @@
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces; using osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces;
using OpenTK.Input;
namespace osu.Game.Rulesets.Taiko.Objects.Drawables namespace osu.Game.Rulesets.Taiko.Objects.Drawables
{ {
public class DrawableRimHit : DrawableHit public class DrawableRimHit : DrawableHit
{ {
protected override Key[] HitKeys { get; } = { Key.D, Key.K }; protected override TaikoAction[] HitActions { get; } = { TaikoAction.LeftRim, TaikoAction.RightRim };
public DrawableRimHit(Hit hit) public DrawableRimHit(Hit hit)
: base(hit) : base(hit)

View File

@ -4,13 +4,12 @@
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces; using osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces;
using OpenTK.Input;
namespace osu.Game.Rulesets.Taiko.Objects.Drawables namespace osu.Game.Rulesets.Taiko.Objects.Drawables
{ {
public class DrawableRimHitStrong : DrawableHitStrong public class DrawableRimHitStrong : DrawableHitStrong
{ {
protected override Key[] HitKeys { get; } = { Key.D, Key.K }; protected override TaikoAction[] HitActions { get; } = { TaikoAction.LeftRim, TaikoAction.RightRim };
public DrawableRimHitStrong(Hit hit) public DrawableRimHitStrong(Hit hit)
: base(hit) : base(hit)

View File

@ -13,7 +13,6 @@ using osu.Game.Rulesets.Taiko.Judgements;
using osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces; using osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces;
using OpenTK; using OpenTK;
using OpenTK.Graphics; using OpenTK.Graphics;
using OpenTK.Input;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
namespace osu.Game.Rulesets.Taiko.Objects.Drawables namespace osu.Game.Rulesets.Taiko.Objects.Drawables
@ -35,9 +34,9 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
private readonly CircularContainer targetRing; private readonly CircularContainer targetRing;
private readonly CircularContainer expandingRing; private readonly CircularContainer expandingRing;
private readonly Key[] rimKeys = { Key.D, Key.K }; private readonly TaikoAction[] rimActions = { TaikoAction.LeftRim, TaikoAction.RightRim };
private readonly Key[] centreKeys = { Key.F, Key.J }; private readonly TaikoAction[] centreActions = { TaikoAction.LeftCentre, TaikoAction.RightCentre };
private Key[] lastKeySet; private TaikoAction[] lastAction;
/// <summary> /// <summary>
/// The amount of times the user has hit this swell. /// The amount of times the user has hit this swell.
@ -211,8 +210,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
} }
} }
public override bool OnPressed(TaikoAction action)
protected override bool HandleKeyPress(Key key)
{ {
if (Judgement.Result != HitResult.None) if (Judgement.Result != HitResult.None)
return false; return false;
@ -222,12 +220,12 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
return false; return false;
// Find the keyset which this key corresponds to // Find the keyset which this key corresponds to
var keySet = rimKeys.Contains(key) ? rimKeys : centreKeys; var keySet = rimActions.Contains(action) ? rimActions : centreActions;
// Ensure alternating keysets // Ensure alternating keysets
if (keySet == lastKeySet) if (keySet == lastAction)
return false; return false;
lastKeySet = keySet; lastAction = keySet;
UpdateJudgement(true); UpdateJudgement(true);

View File

@ -1,26 +1,19 @@
// 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 osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Input; using osu.Framework.Input.Bindings;
using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Taiko.Judgements; using osu.Game.Rulesets.Taiko.Judgements;
using osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces; using osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces;
using OpenTK; using OpenTK;
using OpenTK.Input;
namespace osu.Game.Rulesets.Taiko.Objects.Drawables namespace osu.Game.Rulesets.Taiko.Objects.Drawables
{ {
public abstract class DrawableTaikoHitObject<TaikoHitType> : DrawableScrollingHitObject<TaikoHitObject, TaikoJudgement> public abstract class DrawableTaikoHitObject<TaikoHitType>
where TaikoHitType : TaikoHitObject : DrawableScrollingHitObject<TaikoHitObject, TaikoJudgement>, IKeyBindingHandler<TaikoAction>
where TaikoHitType : TaikoHitObject
{ {
/// <summary>
/// A list of keys which this hit object will accept. These are the standard Taiko keys for now.
/// These should be moved to bindings later.
/// </summary>
private readonly List<Key> validKeys = new List<Key>(new[] { Key.D, Key.F, Key.J, Key.K });
public override Vector2 OriginPosition => new Vector2(DrawHeight / 2); public override Vector2 OriginPosition => new Vector2(DrawHeight / 2);
protected readonly TaikoPiece MainPiece; protected readonly TaikoPiece MainPiece;
@ -46,20 +39,8 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
protected virtual TaikoPiece CreateMainPiece() => new CirclePiece(); protected virtual TaikoPiece CreateMainPiece() => new CirclePiece();
protected virtual bool HandleKeyPress(Key key) => false; public abstract bool OnPressed(TaikoAction action);
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) public virtual bool OnReleased(TaikoAction action) => false;
{
// Make sure we don't handle held-down keys
if (args.Repeat)
return false;
// Check if we've pressed a valid taiko key
if (!validKeys.Contains(args.Key))
return false;
// Handle it!
return HandleKeyPress(args.Key);
}
} }
} }

View File

@ -0,0 +1,29 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.ComponentModel;
using osu.Framework.Input.Bindings;
using osu.Game.Rulesets.UI;
namespace osu.Game.Rulesets.Taiko
{
public class TaikoInputManager : RulesetInputManager<TaikoAction>
{
public TaikoInputManager(RulesetInfo ruleset)
: base(ruleset, 0, SimultaneousBindingMode.Unique)
{
}
}
public enum TaikoAction
{
[Description("Left (Rim)")]
LeftRim,
[Description("Left (Centre)")]
LeftCentre,
[Description("Right (Centre)")]
RightCentre,
[Description("Right (Rim)")]
RightRim
}
}

View File

@ -1,18 +1,17 @@
// 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 OpenTK.Input;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Taiko.Mods; using osu.Game.Rulesets.Taiko.Mods;
using osu.Game.Rulesets.Taiko.UI; using osu.Game.Rulesets.Taiko.UI;
using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI;
using osu.Game.Screens.Play;
using System.Collections.Generic; using System.Collections.Generic;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.Taiko.Scoring; using osu.Game.Rulesets.Taiko.Scoring;
using osu.Framework.Input.Bindings;
namespace osu.Game.Rulesets.Taiko namespace osu.Game.Rulesets.Taiko
{ {
@ -20,6 +19,18 @@ namespace osu.Game.Rulesets.Taiko
{ {
public override RulesetContainer CreateRulesetContainerWith(WorkingBeatmap beatmap, bool isForCurrentRuleset) => new TaikoRulesetContainer(this, beatmap, isForCurrentRuleset); public override RulesetContainer CreateRulesetContainerWith(WorkingBeatmap beatmap, bool isForCurrentRuleset) => new TaikoRulesetContainer(this, beatmap, isForCurrentRuleset);
public override IEnumerable<KeyBinding> GetDefaultKeyBindings(int variant = 0) => new[]
{
new KeyBinding(InputKey.D, TaikoAction.LeftRim),
new KeyBinding(InputKey.F, TaikoAction.LeftCentre),
new KeyBinding(InputKey.J, TaikoAction.RightCentre),
new KeyBinding(InputKey.K, TaikoAction.RightRim),
new KeyBinding(InputKey.MouseLeft, TaikoAction.LeftCentre),
new KeyBinding(InputKey.MouseLeft, TaikoAction.RightCentre),
new KeyBinding(InputKey.MouseRight, TaikoAction.LeftRim),
new KeyBinding(InputKey.MouseRight, TaikoAction.RightRim),
};
public override IEnumerable<Mod> GetModsFor(ModType type) public override IEnumerable<Mod> GetModsFor(ModType type)
{ {
switch (type) switch (type)
@ -90,14 +101,6 @@ namespace osu.Game.Rulesets.Taiko
public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_osu_taiko_o }; public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_osu_taiko_o };
public override IEnumerable<KeyCounter> CreateGameplayKeys() => new KeyCounter[]
{
new KeyCounterKeyboard(Key.D),
new KeyCounterKeyboard(Key.F),
new KeyCounterKeyboard(Key.J),
new KeyCounterKeyboard(Key.K)
};
public override DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap) => new TaikoDifficultyCalculator(beatmap); public override DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap) => new TaikoDifficultyCalculator(beatmap);
public override ScoreProcessor CreateScoreProcessor() => new TaikoScoreProcessor(); public override ScoreProcessor CreateScoreProcessor() => new TaikoScoreProcessor();

View File

@ -3,13 +3,12 @@
using System; using System;
using OpenTK; using OpenTK;
using OpenTK.Input;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures; using osu.Framework.Graphics.Textures;
using osu.Framework.Input; using osu.Framework.Input.Bindings;
using osu.Game.Graphics; using osu.Game.Graphics;
namespace osu.Game.Rulesets.Taiko.UI namespace osu.Game.Rulesets.Taiko.UI
@ -36,8 +35,8 @@ namespace osu.Game.Rulesets.Taiko.UI
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
RelativePositionAxes = Axes.X, RelativePositionAxes = Axes.X,
X = -middle_split / 2, X = -middle_split / 2,
RimKey = Key.D, RimAction = TaikoAction.LeftRim,
CentreKey = Key.F CentreAction = TaikoAction.LeftCentre
}, },
new TaikoHalfDrum(true) new TaikoHalfDrum(true)
{ {
@ -47,8 +46,8 @@ namespace osu.Game.Rulesets.Taiko.UI
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
RelativePositionAxes = Axes.X, RelativePositionAxes = Axes.X,
X = middle_split / 2, X = middle_split / 2,
RimKey = Key.K, RimAction = TaikoAction.RightRim,
CentreKey = Key.J CentreAction = TaikoAction.RightCentre
} }
}; };
} }
@ -56,17 +55,17 @@ namespace osu.Game.Rulesets.Taiko.UI
/// <summary> /// <summary>
/// A half-drum. Contains one centre and one rim hit. /// A half-drum. Contains one centre and one rim hit.
/// </summary> /// </summary>
private class TaikoHalfDrum : Container private class TaikoHalfDrum : Container, IKeyBindingHandler<TaikoAction>
{ {
/// <summary> /// <summary>
/// The key to be used for the rim of the half-drum. /// The key to be used for the rim of the half-drum.
/// </summary> /// </summary>
public Key RimKey; public TaikoAction RimAction;
/// <summary> /// <summary>
/// The key to be used for the centre of the half-drum. /// The key to be used for the centre of the half-drum.
/// </summary> /// </summary>
public Key CentreKey; public TaikoAction CentreAction;
private readonly Sprite rim; private readonly Sprite rim;
private readonly Sprite rimHit; private readonly Sprite rimHit;
@ -124,20 +123,17 @@ namespace osu.Game.Rulesets.Taiko.UI
centreHit.Colour = colours.Pink; centreHit.Colour = colours.Pink;
} }
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) public bool OnPressed(TaikoAction action)
{ {
if (args.Repeat)
return false;
Drawable target = null; Drawable target = null;
Drawable back = null; Drawable back = null;
if (args.Key == CentreKey) if (action == CentreAction)
{ {
target = centreHit; target = centreHit;
back = centre; back = centre;
} }
else if (args.Key == RimKey) else if (action == RimAction)
{ {
target = rimHit; target = rimHit;
back = rim; back = rim;
@ -166,6 +162,8 @@ namespace osu.Game.Rulesets.Taiko.UI
return false; return false;
} }
public bool OnReleased(TaikoAction action) => false;
} }
} }
} }

View File

@ -45,6 +45,8 @@ namespace osu.Game.Rulesets.Taiko.UI
private readonly Container topLevelHitContainer; private readonly Container topLevelHitContainer;
private readonly Container barlineContainer;
private readonly Container overlayBackgroundContainer; private readonly Container overlayBackgroundContainer;
private readonly Container backgroundContainer; private readonly Container backgroundContainer;
@ -85,7 +87,7 @@ namespace osu.Game.Rulesets.Taiko.UI
{ {
new Container new Container
{ {
Name = "Masked elements", Name = "Masked elements before hit objects",
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding { Left = HIT_TARGET_OFFSET }, Padding = new MarginPadding { Left = HIT_TARGET_OFFSET },
Masking = true, Masking = true,
@ -103,13 +105,21 @@ namespace osu.Game.Rulesets.Taiko.UI
Origin = Anchor.Centre, Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
FillMode = FillMode.Fit FillMode = FillMode.Fit
}, }
content = new Container
{
RelativeSizeAxes = Axes.Both,
},
} }
}, },
barlineContainer = new Container
{
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding { Left = HIT_TARGET_OFFSET }
},
content = new Container
{
Name = "Hit objects",
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding { Left = HIT_TARGET_OFFSET },
Masking = true
},
kiaiExplosionContainer = new Container<KiaiHitExplosion> kiaiExplosionContainer = new Container<KiaiHitExplosion>
{ {
Name = "Kiai hit explosions", Name = "Kiai hit explosions",
@ -198,6 +208,10 @@ namespace osu.Game.Rulesets.Taiko.UI
base.Add(h); base.Add(h);
var barline = h as DrawableBarLine;
if (barline != null)
barlineContainer.Add(barline.CreateProxy());
// Swells should be moved at the very top of the playfield when they reach the hit target // Swells should be moved at the very top of the playfield when they reach the hit target
var swell = h as DrawableSwell; var swell = h as DrawableSwell;
if (swell != null) if (swell != null)
@ -239,4 +253,4 @@ namespace osu.Game.Rulesets.Taiko.UI
hitExplosionContainer.Children.FirstOrDefault(e => e.Judgement == judgedObject.Judgement)?.VisualiseSecondHit(); hitExplosionContainer.Children.FirstOrDefault(e => e.Judgement == judgedObject.Judgement)?.VisualiseSecondHit();
} }
} }
} }

View File

@ -18,6 +18,7 @@ using osu.Game.Rulesets.Taiko.Replays;
using OpenTK; using OpenTK;
using osu.Game.Rulesets.Beatmaps; using osu.Game.Rulesets.Beatmaps;
using System.Linq; using System.Linq;
using osu.Framework.Input;
namespace osu.Game.Rulesets.Taiko.UI namespace osu.Game.Rulesets.Taiko.UI
{ {
@ -92,6 +93,8 @@ namespace osu.Game.Rulesets.Taiko.UI
protected override BeatmapConverter<TaikoHitObject> CreateBeatmapConverter() => new TaikoBeatmapConverter(); protected override BeatmapConverter<TaikoHitObject> CreateBeatmapConverter() => new TaikoBeatmapConverter();
public override PassThroughInputManager CreateInputManager() => new TaikoInputManager(Ruleset.RulesetInfo);
protected override Playfield<TaikoHitObject, TaikoJudgement> CreatePlayfield() => new TaikoPlayfield protected override Playfield<TaikoHitObject, TaikoJudgement> CreatePlayfield() => new TaikoPlayfield
{ {
Anchor = Anchor.CentreLeft, Anchor = Anchor.CentreLeft,

View File

@ -86,6 +86,7 @@
<Compile Include="TaikoDifficultyCalculator.cs" /> <Compile Include="TaikoDifficultyCalculator.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Scoring\TaikoScoreProcessor.cs" /> <Compile Include="Scoring\TaikoScoreProcessor.cs" />
<Compile Include="TaikoInputManager.cs" />
<Compile Include="UI\HitTarget.cs" /> <Compile Include="UI\HitTarget.cs" />
<Compile Include="UI\InputDrum.cs" /> <Compile Include="UI\InputDrum.cs" />
<Compile Include="UI\KiaiHitExplosion.cs" /> <Compile Include="UI\KiaiHitExplosion.cs" />

View File

@ -10,4 +10,4 @@ namespace osu.Game.Beatmaps.ControlPoints
/// </summary> /// </summary>
public double SpeedMultiplier = 1; public double SpeedMultiplier = 1;
} }
} }

View File

@ -10,7 +10,6 @@ using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI;
using osu.Game.Screens.Play;
namespace osu.Game.Beatmaps namespace osu.Game.Beatmaps
{ {
@ -76,8 +75,6 @@ namespace osu.Game.Beatmaps
public override string Description => "dummy"; public override string Description => "dummy";
public override IEnumerable<KeyCounter> CreateGameplayKeys() => new List<KeyCounter>();
public DummyRuleset(RulesetInfo rulesetInfo) public DummyRuleset(RulesetInfo rulesetInfo)
: base(rulesetInfo) : base(rulesetInfo)
{ {

View File

@ -280,7 +280,7 @@ namespace osu.Game.Beatmaps.Formats
double time = double.Parse(split[0].Trim(), NumberFormatInfo.InvariantInfo); double time = double.Parse(split[0].Trim(), NumberFormatInfo.InvariantInfo);
double beatLength = double.Parse(split[1].Trim(), NumberFormatInfo.InvariantInfo); double beatLength = double.Parse(split[1].Trim(), NumberFormatInfo.InvariantInfo);
double speedMultiplier = beatLength < 0 ? -beatLength / 100.0 : 1; double speedMultiplier = beatLength < 0 ? 100.0 / -beatLength : 1;
TimeSignatures timeSignature = TimeSignatures.SimpleQuadruple; TimeSignatures timeSignature = TimeSignatures.SimpleQuadruple;
if (split.Length >= 3) if (split.Length >= 3)

View File

@ -18,7 +18,7 @@ namespace osu.Game.Input
public KeyBindingStore(SQLiteConnection connection, RulesetStore rulesets, Storage storage = null) public KeyBindingStore(SQLiteConnection connection, RulesetStore rulesets, Storage storage = null)
: base(connection, storage) : base(connection, storage)
{ {
foreach (var info in rulesets.Query<RulesetInfo>()) foreach (var info in rulesets.AllRulesets)
{ {
var ruleset = info.CreateInstance(); var ruleset = info.CreateInstance();
foreach (var variant in ruleset.AvailableVariants) foreach (var variant in ruleset.AvailableVariants)

View File

@ -26,6 +26,8 @@ namespace osu.Game.Online.Chat
public readonly SortedList<Message> Messages = new SortedList<Message>(Comparer<Message>.Default); public readonly SortedList<Message> Messages = new SortedList<Message>(Comparer<Message>.Default);
private readonly List<LocalEchoMessage> pendingMessages = new List<LocalEchoMessage>();
public Bindable<bool> Joined = new Bindable<bool>(); public Bindable<bool> Joined = new Bindable<bool>();
public bool ReadOnly => Name != "#lazer"; public bool ReadOnly => Name != "#lazer";
@ -38,6 +40,16 @@ namespace osu.Game.Online.Chat
} }
public event Action<IEnumerable<Message>> NewMessagesArrived; public event Action<IEnumerable<Message>> NewMessagesArrived;
public event Action<LocalEchoMessage, Message> PendingMessageResolved;
public event Action<Message> MessageRemoved;
public void AddLocalEcho(LocalEchoMessage message)
{
pendingMessages.Add(message);
Messages.Add(message);
NewMessagesArrived?.Invoke(new[] { message });
}
public void AddNewMessages(params Message[] messages) public void AddNewMessages(params Message[] messages)
{ {
@ -52,11 +64,42 @@ namespace osu.Game.Online.Chat
private void purgeOldMessages() private void purgeOldMessages()
{ {
int messageCount = Messages.Count; // never purge local echos
int messageCount = Messages.Count - pendingMessages.Count;
if (messageCount > MAX_HISTORY) if (messageCount > MAX_HISTORY)
Messages.RemoveRange(0, messageCount - MAX_HISTORY); Messages.RemoveRange(0, messageCount - MAX_HISTORY);
} }
/// <summary>
/// Replace or remove a message from the channel.
/// </summary>
/// <param name="echo">The local echo message (client-side).</param>
/// <param name="final">The response message, or null if the message became invalid.</param>
public void ReplaceMessage(LocalEchoMessage echo, Message final)
{
if (!pendingMessages.Remove(echo))
throw new InvalidOperationException("Attempted to remove echo that wasn't present");
Messages.Remove(echo);
if (final == null)
{
MessageRemoved?.Invoke(echo);
return;
}
if (Messages.Contains(final))
{
// message already inserted, so let's throw away this update.
// we may want to handle this better in the future, but for the time being api requests are single-threaded so order is assumed.
MessageRemoved?.Invoke(echo);
return;
}
Messages.Add(final);
PendingMessageResolved?.Invoke(echo, final);
}
public override string ToString() => Name; public override string ToString() => Name;
} }
} }

View File

@ -0,0 +1,12 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
namespace osu.Game.Online.Chat
{
public class LocalEchoMessage : Message
{
public LocalEchoMessage() : base(null)
{
}
}
}

View File

@ -11,7 +11,7 @@ namespace osu.Game.Online.Chat
public class Message : IComparable<Message>, IEquatable<Message> public class Message : IComparable<Message>, IEquatable<Message>
{ {
[JsonProperty(@"message_id")] [JsonProperty(@"message_id")]
public readonly long Id; public readonly long? Id;
//todo: this should be inside sender. //todo: this should be inside sender.
[JsonProperty(@"sender_id")] [JsonProperty(@"sender_id")]
@ -37,14 +37,22 @@ namespace osu.Game.Online.Chat
{ {
} }
public Message(long id) public Message(long? id)
{ {
Id = id; Id = id;
} }
public int CompareTo(Message other) => Id.CompareTo(other.Id); public int CompareTo(Message other)
{
if (!Id.HasValue)
return other.Id.HasValue ? 1 : Timestamp.CompareTo(other.Timestamp);
if (!other.Id.HasValue)
return -1;
public bool Equals(Message other) => Id == other?.Id; return Id.Value.CompareTo(other.Id.Value);
}
public virtual bool Equals(Message other) => Id == other?.Id;
public override int GetHashCode() => Id.GetHashCode(); public override int GetHashCode() => Id.GetHashCode();
} }

View File

@ -94,13 +94,15 @@ namespace osu.Game
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent) => protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent) =>
dependencies = new DependencyContainer(base.CreateLocalDependencies(parent)); dependencies = new DependencyContainer(base.CreateLocalDependencies(parent));
private SQLiteConnection connection;
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load()
{ {
dependencies.Cache(this); dependencies.Cache(this);
dependencies.Cache(LocalConfig); dependencies.Cache(LocalConfig);
SQLiteConnection connection = Host.Storage.GetDatabase(@"client"); connection = Host.Storage.GetDatabase(@"client");
connection.CreateTable<StoreVersion>(); connection.CreateTable<StoreVersion>();
@ -237,6 +239,8 @@ namespace osu.Game
LocalConfig.Save(); LocalConfig.Save();
} }
connection.Dispose();
base.Dispose(isDisposing); base.Dispose(isDisposing);
} }
} }

View File

@ -2,26 +2,24 @@
// 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; using System;
using OpenTK;
using OpenTK.Graphics;
using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Sprites;
using osu.Game.Online.Chat; using osu.Game.Online.Chat;
using OpenTK;
using OpenTK.Graphics;
using osu.Framework.Graphics.Effects;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Allocation;
using osu.Game.Users; using osu.Game.Users;
using osu.Game.Graphics.Containers;
namespace osu.Game.Overlays.Chat namespace osu.Game.Overlays.Chat
{ {
public class ChatLine : Container public class ChatLine : Container
{ {
public readonly Message Message; private static readonly Color4[] username_colours =
{
private static readonly Color4[] username_colours = {
OsuColour.FromHex("588c7e"), OsuColour.FromHex("588c7e"),
OsuColour.FromHex("b2a367"), OsuColour.FromHex("b2a367"),
OsuColour.FromHex("c98f65"), OsuColour.FromHex("c98f65"),
@ -69,6 +67,8 @@ namespace osu.Game.Overlays.Chat
private Color4 customUsernameColour; private Color4 customUsernameColour;
private OsuSpriteText timestamp;
public ChatLine(Message message) public ChatLine(Message message)
{ {
Message = message; Message = message;
@ -79,6 +79,26 @@ namespace osu.Game.Overlays.Chat
Padding = new MarginPadding { Left = padding, Right = padding }; Padding = new MarginPadding { Left = padding, Right = padding };
} }
private Message message;
private OsuSpriteText username;
private OsuTextFlowContainer contentFlow;
public Message Message
{
get { return message; }
set
{
if (message == value) return;
message = value;
if (!IsLoaded)
return;
updateMessageContent();
}
}
[BackgroundDependencyLoader(true)] [BackgroundDependencyLoader(true)]
private void load(OsuColour colours, UserProfileOverlay profile) private void load(OsuColour colours, UserProfileOverlay profile)
{ {
@ -86,49 +106,54 @@ namespace osu.Game.Overlays.Chat
loadProfile = u => profile?.ShowUser(u); loadProfile = u => profile?.ShowUser(u);
} }
private bool senderHasBackground => !string.IsNullOrEmpty(message.Sender.Colour);
protected override void LoadComplete() protected override void LoadComplete()
{ {
base.LoadComplete(); base.LoadComplete();
bool hasBackground = !string.IsNullOrEmpty(Message.Sender.Colour); bool hasBackground = senderHasBackground;
Drawable username = new OsuSpriteText
Drawable effectedUsername = username = new OsuSpriteText
{ {
Font = @"Exo2.0-BoldItalic", Font = @"Exo2.0-BoldItalic",
Text = $@"{Message.Sender.Username}" + (hasBackground ? "" : ":"), Colour = hasBackground ? customUsernameColour : username_colours[message.Sender.Id % username_colours.Length],
Colour = hasBackground ? customUsernameColour : username_colours[Message.UserId % username_colours.Length],
TextSize = text_size, TextSize = text_size,
}; };
if (hasBackground) if (hasBackground)
{ {
// Background effect // Background effect
username = username.WithEffect(new EdgeEffect effectedUsername = new Container
{ {
AutoSizeAxes = Axes.Both,
Masking = true,
CornerRadius = 4, CornerRadius = 4,
Parameters = new EdgeEffectParameters EdgeEffect = new EdgeEffectParameters
{
Radius = 1,
Colour = OsuColour.FromHex(Message.Sender.Colour),
Type = EdgeEffectType.Shadow,
}
}, d =>
{
d.Padding = new MarginPadding { Left = 3, Right = 3, Bottom = 1, Top = -3 };
d.Y = 3;
})
// Drop shadow effect
.WithEffect(new EdgeEffect
{
CornerRadius = 4,
Parameters = new EdgeEffectParameters
{ {
Roundness = 1, Roundness = 1,
Offset = new Vector2(0, 3), Offset = new Vector2(0, 3),
Radius = 3, Radius = 3,
Colour = Color4.Black.Opacity(0.3f), Colour = Color4.Black.Opacity(0.3f),
Type = EdgeEffectType.Shadow, Type = EdgeEffectType.Shadow,
},
// Drop shadow effect
Child = new Container
{
AutoSizeAxes = Axes.Both,
Masking = true,
CornerRadius = 4,
EdgeEffect = new EdgeEffectParameters
{
Radius = 1,
Colour = OsuColour.FromHex(message.Sender.Colour),
Type = EdgeEffectType.Shadow,
},
Padding = new MarginPadding { Left = 3, Right = 3, Bottom = 1, Top = -3 },
Y = 3,
Child = username,
} }
}); };
} }
Children = new Drawable[] Children = new Drawable[]
@ -138,23 +163,21 @@ namespace osu.Game.Overlays.Chat
Size = new Vector2(message_padding, text_size), Size = new Vector2(message_padding, text_size),
Children = new Drawable[] Children = new Drawable[]
{ {
new OsuSpriteText timestamp = new OsuSpriteText
{ {
Anchor = Anchor.CentreLeft, Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft, Origin = Anchor.CentreLeft,
Font = @"Exo2.0-SemiBold", Font = @"Exo2.0-SemiBold",
Text = $@"{Message.Timestamp.LocalDateTime:HH:mm:ss}",
FixedWidth = true, FixedWidth = true,
TextSize = text_size * 0.75f, TextSize = text_size * 0.75f,
Alpha = 0.4f,
}, },
new ClickableContainer new ClickableContainer
{ {
AutoSizeAxes = Axes.Both, AutoSizeAxes = Axes.Both,
Origin = Anchor.TopRight, Origin = Anchor.TopRight,
Anchor = Anchor.TopRight, Anchor = Anchor.TopRight,
Child = username, Child = effectedUsername,
Action = () => loadProfile(Message.Sender), Action = () => loadProfile(message.Sender),
}, },
} }
}, },
@ -165,18 +188,27 @@ namespace osu.Game.Overlays.Chat
Padding = new MarginPadding { Left = message_padding + padding }, Padding = new MarginPadding { Left = message_padding + padding },
Children = new Drawable[] Children = new Drawable[]
{ {
new OsuTextFlowContainer(t => contentFlow = new OsuTextFlowContainer(t => { t.TextSize = text_size; })
{ {
t.TextSize = text_size;
})
{
Text = Message.Content,
AutoSizeAxes = Axes.Y, AutoSizeAxes = Axes.Y,
RelativeSizeAxes = Axes.X, RelativeSizeAxes = Axes.X,
} }
} }
} }
}; };
updateMessageContent();
FinishTransforms(true);
}
private void updateMessageContent()
{
this.FadeTo(message is LocalEchoMessage ? 0.4f : 1.0f, 500, Easing.OutQuint);
timestamp.FadeTo(message is LocalEchoMessage ? 0 : 1, 500, Easing.OutQuint);
timestamp.Text = $@"{message.Timestamp.LocalDateTime:HH:mm:ss}";
username.Text = $@"{message.Sender.Username}" + (senderHasBackground ? "" : ":");
contentFlow.Text = message.Content;
} }
} }
} }

View File

@ -3,7 +3,9 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.Linq; using System.Linq;
using OpenTK.Graphics;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
@ -14,8 +16,19 @@ namespace osu.Game.Overlays.Chat
{ {
public class DrawableChannel : Container public class DrawableChannel : Container
{ {
private class ChatLineContainer : FillFlowContainer<ChatLine>
{
protected override int Compare(Drawable x, Drawable y)
{
var xC = (ChatLine)x;
var yC = (ChatLine)y;
return xC.Message.CompareTo(yC.Message);
}
}
public readonly Channel Channel; public readonly Channel Channel;
private readonly FillFlowContainer<ChatLine> flow; private readonly ChatLineContainer flow;
private readonly ScrollContainer scroll; private readonly ScrollContainer scroll;
public DrawableChannel(Channel channel) public DrawableChannel(Channel channel)
@ -32,20 +45,19 @@ namespace osu.Game.Overlays.Chat
// Some chat lines have effects that slightly protrude to the bottom, // Some chat lines have effects that slightly protrude to the bottom,
// which we do not want to mask away, hence the padding. // which we do not want to mask away, hence the padding.
Padding = new MarginPadding { Bottom = 5 }, Padding = new MarginPadding { Bottom = 5 },
Children = new Drawable[] Child = flow = new ChatLineContainer
{ {
flow = new FillFlowContainer<ChatLine> Padding = new MarginPadding { Left = 20, Right = 20 },
{ RelativeSizeAxes = Axes.X,
Direction = FillDirection.Vertical, AutoSizeAxes = Axes.Y,
RelativeSizeAxes = Axes.X, Direction = FillDirection.Vertical,
AutoSizeAxes = Axes.Y, },
Padding = new MarginPadding { Left = 20, Right = 20 }
}
}
} }
}; };
channel.NewMessagesArrived += newMessagesArrived; Channel.NewMessagesArrived += newMessagesArrived;
Channel.MessageRemoved += messageRemoved;
Channel.PendingMessageResolved += pendingMessageResolved;
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
@ -63,14 +75,17 @@ namespace osu.Game.Overlays.Chat
protected override void Dispose(bool isDisposing) protected override void Dispose(bool isDisposing)
{ {
base.Dispose(isDisposing); base.Dispose(isDisposing);
Channel.NewMessagesArrived -= newMessagesArrived; Channel.NewMessagesArrived -= newMessagesArrived;
Channel.MessageRemoved -= messageRemoved;
Channel.PendingMessageResolved -= pendingMessageResolved;
} }
private void newMessagesArrived(IEnumerable<Message> newMessages) private void newMessagesArrived(IEnumerable<Message> newMessages)
{ {
// Add up to last Channel.MAX_HISTORY messages
var displayMessages = newMessages.Skip(Math.Max(0, newMessages.Count() - Channel.MAX_HISTORY)); var displayMessages = newMessages.Skip(Math.Max(0, newMessages.Count() - Channel.MAX_HISTORY));
//up to last Channel.MAX_HISTORY messages
flow.AddRange(displayMessages.Select(m => new ChatLine(m))); flow.AddRange(displayMessages.Select(m => new ChatLine(m)));
if (!IsLoaded) return; if (!IsLoaded) return;
@ -90,6 +105,24 @@ namespace osu.Game.Overlays.Chat
} }
} }
private void pendingMessageResolved(Message existing, Message updated)
{
var found = flow.Children.LastOrDefault(c => c.Message == existing);
if (found != null)
{
Trace.Assert(updated.Id.HasValue, "An updated message was returned with no ID.");
flow.Remove(found);
found.Message = updated;
flow.Add(found);
}
}
private void messageRemoved(Message removed)
{
flow.Children.FirstOrDefault(c => c.Message == removed)?.FadeColour(Color4.Red, 400).FadeOut(600).Expire();
}
private void scrollToEnd() => ScheduleAfterChildren(() => scroll.ScrollToEnd()); private void scrollToEnd() => ScheduleAfterChildren(() => scroll.ScrollToEnd());
} }
} }

View File

@ -6,23 +6,23 @@ using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
using OpenTK; using OpenTK;
using OpenTK.Graphics;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Configuration; using osu.Framework.Configuration;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Input;
using osu.Framework.Threading; using osu.Framework.Threading;
using osu.Game.Configuration;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.UserInterface;
using osu.Game.Online.API; using osu.Game.Online.API;
using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests;
using osu.Game.Online.Chat; using osu.Game.Online.Chat;
using osu.Game.Graphics.UserInterface;
using osu.Framework.Graphics.UserInterface;
using OpenTK.Graphics;
using osu.Framework.Input;
using osu.Game.Configuration;
using osu.Game.Graphics;
using osu.Game.Overlays.Chat; using osu.Game.Overlays.Chat;
using osu.Game.Graphics.Containers;
namespace osu.Game.Overlays namespace osu.Game.Overlays
{ {
@ -37,7 +37,7 @@ namespace osu.Game.Overlays
private readonly LoadingAnimation loading; private readonly LoadingAnimation loading;
private readonly FocusedTextBox inputTextBox; private readonly FocusedTextBox textbox;
private APIAccess api; private APIAccess api;
@ -130,7 +130,7 @@ namespace osu.Game.Overlays
}, },
Children = new Drawable[] Children = new Drawable[]
{ {
inputTextBox = new FocusedTextBox textbox = new FocusedTextBox
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Height = 1, Height = 1,
@ -175,7 +175,7 @@ namespace osu.Game.Overlays
if (state == Visibility.Visible) if (state == Visibility.Visible)
{ {
inputTextBox.HoldFocus = false; textbox.HoldFocus = false;
if (1f - chatHeight.Value < channel_selection_min_height) if (1f - chatHeight.Value < channel_selection_min_height)
{ {
chatContainer.ResizeHeightTo(1f - channel_selection_min_height, 800, Easing.OutQuint); chatContainer.ResizeHeightTo(1f - channel_selection_min_height, 800, Easing.OutQuint);
@ -186,7 +186,7 @@ namespace osu.Game.Overlays
} }
else else
{ {
inputTextBox.HoldFocus = true; textbox.HoldFocus = true;
} }
}; };
} }
@ -242,8 +242,8 @@ namespace osu.Game.Overlays
protected override void OnFocus(InputState state) protected override void OnFocus(InputState state)
{ {
//this is necessary as inputTextBox is masked away and therefore can't get focus :( //this is necessary as textbox is masked away and therefore can't get focus :(
GetContainingInputManager().ChangeFocus(inputTextBox); GetContainingInputManager().ChangeFocus(textbox);
base.OnFocus(state); base.OnFocus(state);
} }
@ -252,7 +252,7 @@ namespace osu.Game.Overlays
this.MoveToY(0, transition_length, Easing.OutQuint); this.MoveToY(0, transition_length, Easing.OutQuint);
this.FadeIn(transition_length, Easing.OutQuint); this.FadeIn(transition_length, Easing.OutQuint);
inputTextBox.HoldFocus = true; textbox.HoldFocus = true;
base.PopIn(); base.PopIn();
} }
@ -261,7 +261,7 @@ namespace osu.Game.Overlays
this.MoveToY(Height, transition_length, Easing.InSine); this.MoveToY(Height, transition_length, Easing.InSine);
this.FadeOut(transition_length, Easing.InSine); this.FadeOut(transition_length, Easing.InSine);
inputTextBox.HoldFocus = false; textbox.HoldFocus = false;
base.PopOut(); base.PopOut();
} }
@ -336,7 +336,7 @@ namespace osu.Game.Overlays
currentChannel = value; currentChannel = value;
inputTextBox.Current.Disabled = currentChannel.ReadOnly; textbox.Current.Disabled = currentChannel.ReadOnly;
channelTabs.Current.Value = value; channelTabs.Current.Value = value;
var loaded = loadedChannels.Find(d => d.Channel == value); var loaded = loadedChannels.Find(d => d.Channel == value);
@ -414,6 +414,7 @@ namespace osu.Game.Overlays
if (fetchReq != null) return; if (fetchReq != null) return;
fetchReq = new GetMessagesRequest(careChannels, lastMessageId); fetchReq = new GetMessagesRequest(careChannels, lastMessageId);
fetchReq.Success += delegate (List<Message> messages) fetchReq.Success += delegate (List<Message> messages)
{ {
foreach (var group in messages.Where(m => m.TargetType == TargetType.Channel).GroupBy(m => m.TargetId)) foreach (var group in messages.Where(m => m.TargetType == TargetType.Channel).GroupBy(m => m.TargetId))
@ -424,6 +425,7 @@ namespace osu.Game.Overlays
Debug.Write("success!"); Debug.Write("success!");
fetchReq = null; fetchReq = null;
}; };
fetchReq.Failure += delegate fetchReq.Failure += delegate
{ {
Debug.Write("failure!"); Debug.Write("failure!");
@ -437,51 +439,42 @@ namespace osu.Game.Overlays
{ {
var postText = textbox.Text; var postText = textbox.Text;
textbox.Text = string.Empty;
if (string.IsNullOrEmpty(postText)) if (string.IsNullOrEmpty(postText))
return; return;
var target = currentChannel;
if (target == null) return;
if (!api.IsLoggedIn) if (!api.IsLoggedIn)
{ {
currentChannel?.AddNewMessages(new ErrorMessage("Please login to participate in chat!")); target.AddNewMessages(new ErrorMessage("Please login to participate in chat!"));
textbox.Text = string.Empty;
return; return;
} }
if (currentChannel == null) return;
if (postText[0] == '/') if (postText[0] == '/')
{ {
// TODO: handle commands // TODO: handle commands
currentChannel.AddNewMessages(new ErrorMessage("Chat commands are not supported yet!")); target.AddNewMessages(new ErrorMessage("Chat commands are not supported yet!"));
textbox.Text = string.Empty;
return; return;
} }
var message = new Message var message = new LocalEchoMessage
{ {
Sender = api.LocalUser.Value, Sender = api.LocalUser.Value,
Timestamp = DateTimeOffset.Now, Timestamp = DateTimeOffset.Now,
TargetType = TargetType.Channel, //TODO: read this from currentChannel TargetType = TargetType.Channel, //TODO: read this from channel
TargetId = currentChannel.Id, TargetId = target.Id,
Content = postText Content = postText
}; };
textbox.ReadOnly = true;
var req = new PostMessageRequest(message); var req = new PostMessageRequest(message);
req.Failure += e => target.AddLocalEcho(message);
{ req.Failure += e => target.ReplaceMessage(message, null);
textbox.FlashColour(Color4.Red, 1000); req.Success += m => target.ReplaceMessage(message, m);
textbox.ReadOnly = false;
};
req.Success += m =>
{
currentChannel.AddNewMessages(m);
textbox.ReadOnly = false;
textbox.Text = string.Empty;
};
api.Queue(req); api.Queue(req);
} }

View File

@ -19,7 +19,7 @@ namespace osu.Game.Overlays
{ {
AddSection(new GlobalKeyBindingsSection(global, "Global")); AddSection(new GlobalKeyBindingsSection(global, "Global"));
foreach (var ruleset in rulesets.Query<RulesetInfo>()) foreach (var ruleset in rulesets.AllRulesets)
AddSection(new RulesetBindingsSection(ruleset)); AddSection(new RulesetBindingsSection(ruleset));
} }

View File

@ -106,6 +106,9 @@ namespace osu.Game.Rulesets.Objects.Drawables
/// <returns>Whether a hit was processed.</returns> /// <returns>Whether a hit was processed.</returns>
protected bool UpdateJudgement(bool userTriggered) protected bool UpdateJudgement(bool userTriggered)
{ {
if (Judgement == null)
return false;
var partial = Judgement as IPartialJudgement; var partial = Judgement as IPartialJudgement;
// Never re-process non-partial hits // Never re-process non-partial hits

View File

@ -53,7 +53,7 @@ namespace osu.Game.Rulesets.Objects.Legacy
TimingControlPoint timingPoint = controlPointInfo.TimingPointAt(StartTime); TimingControlPoint timingPoint = controlPointInfo.TimingPointAt(StartTime);
DifficultyControlPoint difficultyPoint = controlPointInfo.DifficultyPointAt(StartTime); DifficultyControlPoint difficultyPoint = controlPointInfo.DifficultyPointAt(StartTime);
double scoringDistance = base_scoring_distance * difficulty.SliderMultiplier / difficultyPoint.SpeedMultiplier; double scoringDistance = base_scoring_distance * difficulty.SliderMultiplier * difficultyPoint.SpeedMultiplier;
Velocity = scoringDistance / timingPoint.BeatLength; Velocity = scoringDistance / timingPoint.BeatLength;
} }

View File

@ -5,7 +5,6 @@ using osu.Game.Beatmaps;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI;
using osu.Game.Screens.Play;
using System.Collections.Generic; using System.Collections.Generic;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Input.Bindings; using osu.Framework.Input.Bindings;
@ -46,8 +45,6 @@ namespace osu.Game.Rulesets
public abstract string Description { get; } public abstract string Description { get; }
public abstract IEnumerable<KeyCounter> CreateGameplayKeys();
public virtual SettingsSubsection CreateSettings() => null; public virtual SettingsSubsection CreateSettings() => null;
/// <summary> /// <summary>

View File

@ -20,7 +20,7 @@ namespace osu.Game.Rulesets.Timing
/// <summary> /// <summary>
/// The multiplier which this <see cref="MultiplierControlPoint"/> provides. /// The multiplier which this <see cref="MultiplierControlPoint"/> provides.
/// </summary> /// </summary>
public double Multiplier => 1000 / TimingPoint.BeatLength / DifficultyPoint.SpeedMultiplier; public double Multiplier => 1000 / TimingPoint.BeatLength * DifficultyPoint.SpeedMultiplier;
/// <summary> /// <summary>
/// The <see cref="TimingControlPoint"/> that provides the timing information for this <see cref="MultiplierControlPoint"/>. /// The <see cref="TimingControlPoint"/> that provides the timing information for this <see cref="MultiplierControlPoint"/>.
@ -62,4 +62,4 @@ namespace osu.Game.Rulesets.Timing
public int CompareTo(MultiplierControlPoint other) => StartTime.CompareTo(other?.StartTime); public int CompareTo(MultiplierControlPoint other) => StartTime.CompareTo(other?.StartTime);
} }
} }

View File

@ -48,7 +48,7 @@ namespace osu.Game.Rulesets.UI
/// <summary> /// <summary>
/// The key conversion input manager for this RulesetContainer. /// The key conversion input manager for this RulesetContainer.
/// </summary> /// </summary>
protected readonly PassThroughInputManager KeyConversionInputManager; public readonly PassThroughInputManager KeyBindingInputManager;
/// <summary> /// <summary>
/// Whether we are currently providing the local user a gameplay cursor. /// Whether we are currently providing the local user a gameplay cursor.
@ -76,8 +76,8 @@ namespace osu.Game.Rulesets.UI
internal RulesetContainer(Ruleset ruleset) internal RulesetContainer(Ruleset ruleset)
{ {
Ruleset = ruleset; Ruleset = ruleset;
KeyConversionInputManager = CreateKeyBindingInputManager(); KeyBindingInputManager = CreateInputManager();
KeyConversionInputManager.RelativeSizeAxes = Axes.Both; KeyBindingInputManager.RelativeSizeAxes = Axes.Both;
} }
/// <summary> /// <summary>
@ -92,10 +92,10 @@ namespace osu.Game.Rulesets.UI
public abstract ScoreProcessor CreateScoreProcessor(); public abstract ScoreProcessor CreateScoreProcessor();
/// <summary> /// <summary>
/// Creates a key conversion input manager. /// Creates a key conversion input manager. An exception will be thrown if a valid <see cref="RulesetInputManager{T}"/> is not returned.
/// </summary> /// </summary>
/// <returns>The input manager.</returns> /// <returns>The input manager.</returns>
public virtual PassThroughInputManager CreateKeyBindingInputManager() => new PassThroughInputManager(); public abstract PassThroughInputManager CreateInputManager();
protected virtual FramedReplayInputHandler CreateReplayInputHandler(Replay replay) => new FramedReplayInputHandler(replay); protected virtual FramedReplayInputHandler CreateReplayInputHandler(Replay replay) => new FramedReplayInputHandler(replay);
@ -253,7 +253,7 @@ namespace osu.Game.Rulesets.UI
InputManager.Add(content = new Container InputManager.Add(content = new Container
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Children = new[] { KeyConversionInputManager } Children = new[] { KeyBindingInputManager }
}); });
AddInternal(InputManager); AddInternal(InputManager);
@ -262,7 +262,7 @@ namespace osu.Game.Rulesets.UI
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load()
{ {
KeyConversionInputManager.Add(Playfield = CreatePlayfield()); KeyBindingInputManager.Add(Playfield = CreatePlayfield());
loadObjects(); loadObjects();

View File

@ -0,0 +1,44 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Linq;
using osu.Framework.Input.Bindings;
using osu.Game.Input.Bindings;
using osu.Game.Screens.Play;
namespace osu.Game.Rulesets.UI
{
public abstract class RulesetInputManager<T> : DatabasedKeyBindingInputManager<T>, ICanAttachKeyCounter
where T : struct
{
protected RulesetInputManager(RulesetInfo ruleset, int variant, SimultaneousBindingMode unique) : base(ruleset, variant, unique)
{
}
public void Attach(KeyCounterCollection keyCounter)
{
var receptor = new ActionReceptor(keyCounter);
Add(receptor);
keyCounter.SetReceptor(receptor);
keyCounter.AddRange(DefaultKeyBindings.Select(b => b.GetAction<T>()).Distinct().Select(b => new KeyCounterAction<T>(b)));
}
public class ActionReceptor : KeyCounterCollection.Receptor, IKeyBindingHandler<T>
{
public ActionReceptor(KeyCounterCollection target)
: base(target)
{
}
public bool OnPressed(T action) => Target.Children.OfType<KeyCounterAction<T>>().Any(c => c.OnPressed(action));
public bool OnReleased(T action) => Target.Children.OfType<KeyCounterAction<T>>().Any(c => c.OnReleased(action));
}
}
public interface ICanAttachKeyCounter
{
void Attach(KeyCounterCollection keyCounter);
}
}

View File

@ -151,10 +151,6 @@ namespace osu.Game.Rulesets.UI
/// </summary> /// </summary>
public readonly BindableBool Reversed = new BindableBool(); public readonly BindableBool Reversed = new BindableBool();
/// <summary>
/// Hit objects that are to be re-processed on the next update.
/// </summary>
private readonly List<DrawableHitObject> queuedHitObjects = new List<DrawableHitObject>();
private readonly Container<SpeedAdjustmentContainer> speedAdjustments; private readonly Container<SpeedAdjustmentContainer> speedAdjustments;
private readonly Axes scrollingAxes; private readonly Axes scrollingAxes;
@ -168,6 +164,9 @@ namespace osu.Game.Rulesets.UI
this.scrollingAxes = scrollingAxes; this.scrollingAxes = scrollingAxes;
AddInternal(speedAdjustments = new Container<SpeedAdjustmentContainer> { RelativeSizeAxes = Axes.Both }); AddInternal(speedAdjustments = new Container<SpeedAdjustmentContainer> { RelativeSizeAxes = Axes.Both });
// Default speed adjustment
AddSpeedAdjustment(new SpeedAdjustmentContainer(new MultiplierControlPoint(0)));
} }
/// <summary> /// <summary>
@ -180,6 +179,21 @@ namespace osu.Game.Rulesets.UI
speedAdjustment.VisibleTimeRange.BindTo(VisibleTimeRange); speedAdjustment.VisibleTimeRange.BindTo(VisibleTimeRange);
speedAdjustment.Reversed.BindTo(Reversed); speedAdjustment.Reversed.BindTo(Reversed);
speedAdjustments.Add(speedAdjustment); speedAdjustments.Add(speedAdjustment);
// We now need to re-sort the hit objects in the last speed adjustment prior to this one, to see if they need a new parent
var previousSpeedAdjustment = speedAdjustments.LastOrDefault(s => s.ControlPoint.StartTime < speedAdjustment.ControlPoint.StartTime);
if (previousSpeedAdjustment == null)
return;
foreach (DrawableHitObject h in previousSpeedAdjustment.Children)
{
var newSpeedAdjustment = adjustmentContainerFor(h);
if (newSpeedAdjustment == previousSpeedAdjustment)
continue;
previousSpeedAdjustment.Remove(h);
newSpeedAdjustment.Add(h);
}
} }
public override IEnumerable<DrawableHitObject> Objects => speedAdjustments.SelectMany(s => s.Children); public override IEnumerable<DrawableHitObject> Objects => speedAdjustments.SelectMany(s => s.Children);
@ -194,30 +208,14 @@ namespace osu.Game.Rulesets.UI
if (!(hitObject is IScrollingHitObject)) if (!(hitObject is IScrollingHitObject))
throw new InvalidOperationException($"Hit objects added to a {nameof(ScrollingHitObjectContainer)} must implement {nameof(IScrollingHitObject)}."); throw new InvalidOperationException($"Hit objects added to a {nameof(ScrollingHitObjectContainer)} must implement {nameof(IScrollingHitObject)}.");
queuedHitObjects.Add(hitObject); var target = adjustmentContainerFor(hitObject);
if (target == null)
throw new InvalidOperationException($"A {nameof(SpeedAdjustmentContainer)} to container {hitObject} could not be found.");
target.Add(hitObject);
} }
public override bool Remove(DrawableHitObject hitObject) => speedAdjustments.Any(s => s.Remove(hitObject)) || queuedHitObjects.Remove(hitObject); public override bool Remove(DrawableHitObject hitObject) => speedAdjustments.Any(s => s.Remove(hitObject));
protected override void Update()
{
base.Update();
// Todo: At the moment this is going to re-process every single Update, however this will only be a null-op
// when there are no SpeedAdjustmentContainers available. This should probably error or something, but it's okay for now.
for (int i = queuedHitObjects.Count - 1; i >= 0; i--)
{
var hitObject = queuedHitObjects[i];
var target = adjustmentContainerFor(hitObject);
if (target == null)
continue;
target.Add(hitObject);
queuedHitObjects.RemoveAt(i);
}
}
/// <summary> /// <summary>
/// Finds the <see cref="SpeedAdjustmentContainer"/> which provides the speed adjustment active at the start time /// Finds the <see cref="SpeedAdjustmentContainer"/> which provides the speed adjustment active at the start time
@ -237,4 +235,4 @@ namespace osu.Game.Rulesets.UI
private SpeedAdjustmentContainer adjustmentContainerAt(double time) => speedAdjustments.FirstOrDefault(c => c.CanContain(time)) ?? speedAdjustments.LastOrDefault(); private SpeedAdjustmentContainer adjustmentContainerAt(double time) => speedAdjustments.FirstOrDefault(c => c.CanContain(time)) ?? speedAdjustments.LastOrDefault();
} }
} }
} }

View File

@ -92,7 +92,7 @@ namespace osu.Game.Screens.Play
public virtual void BindRulesetContainer(RulesetContainer rulesetContainer) public virtual void BindRulesetContainer(RulesetContainer rulesetContainer)
{ {
rulesetContainer.InputManager.Add(KeyCounter.GetReceptor()); (rulesetContainer.KeyBindingInputManager as ICanAttachKeyCounter)?.Attach(KeyCounter);
replayLoaded = rulesetContainer.HasReplayLoaded; replayLoaded = rulesetContainer.HasReplayLoaded;

View File

@ -0,0 +1,30 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Input.Bindings;
namespace osu.Game.Screens.Play
{
public class KeyCounterAction<T> : KeyCounter, IKeyBindingHandler<T>
where T : struct
{
public T Action { get; }
public KeyCounterAction(T action) : base($"B{(int)(object)action + 1}")
{
Action = action;
}
public bool OnPressed(T action)
{
if (action.Equals(Action)) IsLit = true;
return false;
}
public bool OnReleased(T action)
{
if (action.Equals(Action)) IsLit = false;
return false;
}
}
}

View File

@ -1,6 +1,7 @@
// 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;
using System.Linq; using System.Linq;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
@ -117,27 +118,36 @@ namespace osu.Game.Screens.Play
return receptor ?? (receptor = new Receptor(this)); return receptor ?? (receptor = new Receptor(this));
} }
public void SetReceptor(Receptor receptor)
{
if (this.receptor != null)
throw new InvalidOperationException("Cannot set a new receptor when one is already active");
this.receptor = receptor;
}
public class Receptor : Drawable public class Receptor : Drawable
{ {
private readonly KeyCounterCollection target; protected readonly KeyCounterCollection Target;
public Receptor(KeyCounterCollection target) public Receptor(KeyCounterCollection target)
{ {
RelativeSizeAxes = Axes.Both; RelativeSizeAxes = Axes.Both;
this.target = target; Depth = float.MinValue;
Target = target;
} }
public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => true; public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => true;
public override bool HandleInput => true; public override bool HandleInput => true;
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) => target.Children.Any(c => c.TriggerOnKeyDown(state, args)); protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) => Target.Children.Any(c => c.TriggerOnKeyDown(state, args));
protected override bool OnKeyUp(InputState state, KeyUpEventArgs args) => target.Children.Any(c => c.TriggerOnKeyUp(state, args)); protected override bool OnKeyUp(InputState state, KeyUpEventArgs args) => Target.Children.Any(c => c.TriggerOnKeyUp(state, args));
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) => target.Children.Any(c => c.TriggerOnMouseDown(state, args)); protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) => Target.Children.Any(c => c.TriggerOnMouseDown(state, args));
protected override bool OnMouseUp(InputState state, MouseUpEventArgs args) => target.Children.Any(c => c.TriggerOnMouseUp(state, args)); protected override bool OnMouseUp(InputState state, MouseUpEventArgs args) => Target.Children.Any(c => c.TriggerOnMouseUp(state, args));
} }
} }
} }

View File

@ -76,8 +76,6 @@ namespace osu.Game.Screens.Play
sampleRestart = audio.Sample.Get(@"Gameplay/restart"); sampleRestart = audio.Sample.Get(@"Gameplay/restart");
Ruleset rulesetInstance;
WorkingBeatmap working = Beatmap.Value; WorkingBeatmap working = Beatmap.Value;
Beatmap beatmap; Beatmap beatmap;
@ -89,7 +87,7 @@ namespace osu.Game.Screens.Play
throw new InvalidOperationException("Beatmap was not loaded"); throw new InvalidOperationException("Beatmap was not loaded");
ruleset = osu?.Ruleset.Value ?? beatmap.BeatmapInfo.Ruleset; ruleset = osu?.Ruleset.Value ?? beatmap.BeatmapInfo.Ruleset;
rulesetInstance = ruleset.CreateInstance(); var rulesetInstance = ruleset.CreateInstance();
try try
{ {
@ -192,7 +190,6 @@ namespace osu.Game.Screens.Play
scoreProcessor = RulesetContainer.CreateScoreProcessor(); scoreProcessor = RulesetContainer.CreateScoreProcessor();
hudOverlay.KeyCounter.AddRange(rulesetInstance.CreateGameplayKeys());
hudOverlay.BindProcessor(scoreProcessor); hudOverlay.BindProcessor(scoreProcessor);
hudOverlay.BindRulesetContainer(RulesetContainer); hudOverlay.BindRulesetContainer(RulesetContainer);

View File

@ -101,6 +101,7 @@
<Compile Include="Online\API\Requests\GetUsersRequest.cs" /> <Compile Include="Online\API\Requests\GetUsersRequest.cs" />
<Compile Include="Online\API\Requests\PostMessageRequest.cs" /> <Compile Include="Online\API\Requests\PostMessageRequest.cs" />
<Compile Include="Online\Chat\ErrorMessage.cs" /> <Compile Include="Online\Chat\ErrorMessage.cs" />
<Compile Include="Online\Chat\LocalEchoMessage.cs" />
<Compile Include="Overlays\Chat\ChatTabControl.cs" /> <Compile Include="Overlays\Chat\ChatTabControl.cs" />
<Compile Include="Overlays\KeyBinding\GlobalKeyBindingsSection.cs" /> <Compile Include="Overlays\KeyBinding\GlobalKeyBindingsSection.cs" />
<Compile Include="Overlays\KeyBinding\KeyBindingRow.cs" /> <Compile Include="Overlays\KeyBinding\KeyBindingRow.cs" />
@ -128,6 +129,8 @@
<Compile Include="Overlays\Profile\Sections\RecentSection.cs" /> <Compile Include="Overlays\Profile\Sections\RecentSection.cs" />
<Compile Include="Graphics\Containers\ConstrainedIconContainer.cs" /> <Compile Include="Graphics\Containers\ConstrainedIconContainer.cs" />
<Compile Include="Rulesets\Mods\IApplicableToDifficulty.cs" /> <Compile Include="Rulesets\Mods\IApplicableToDifficulty.cs" />
<Compile Include="Rulesets\UI\RulesetInputManager.cs" />
<Compile Include="Screens\Play\KeyCounterAction.cs" />
<Compile Include="Users\UserCoverBackground.cs" /> <Compile Include="Users\UserCoverBackground.cs" />
<Compile Include="Overlays\UserProfileOverlay.cs" /> <Compile Include="Overlays\UserProfileOverlay.cs" />
<Compile Include="Overlays\Profile\ProfileHeader.cs" /> <Compile Include="Overlays\Profile\ProfileHeader.cs" />