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:
commit
7693fc1382
@ -1 +1 @@
|
|||||||
Subproject commit 825505e788c4f093b269c61b485d38d50cd68096
|
Subproject commit f1527e5456cd228ddfb68cf6d56eb5d28dc360bf
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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) }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
@ -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();
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
21
osu.Game.Rulesets.Mania/ManiaInputManager.cs
Normal file
21
osu.Game.Rulesets.Mania/ManiaInputManager.cs
Normal 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
|
||||||
|
}
|
||||||
|
}
|
@ -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();
|
||||||
|
@ -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)
|
||||||
|
@ -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" />
|
||||||
|
@ -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)
|
||||||
|
@ -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;
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
|
@ -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();
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
|
@ -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 });
|
||||||
|
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
29
osu.Game.Rulesets.Taiko/TaikoInputManager.cs
Normal file
29
osu.Game.Rulesets.Taiko/TaikoInputManager.cs
Normal 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
|
||||||
|
}
|
||||||
|
}
|
@ -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();
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
|
@ -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" />
|
||||||
|
@ -10,4 +10,4 @@ namespace osu.Game.Beatmaps.ControlPoints
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public double SpeedMultiplier = 1;
|
public double SpeedMultiplier = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
12
osu.Game/Online/Chat/LocalEchoMessage.cs
Normal file
12
osu.Game/Online/Chat/LocalEchoMessage.cs
Normal 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)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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();
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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>
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
|
|
||||||
|
44
osu.Game/Rulesets/UI/RulesetInputManager.cs
Normal file
44
osu.Game/Rulesets/UI/RulesetInputManager.cs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
30
osu.Game/Screens/Play/KeyCounterAction.cs
Normal file
30
osu.Game/Screens/Play/KeyCounterAction.cs
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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" />
|
||||||
|
Loading…
Reference in New Issue
Block a user