mirror of
https://github.com/ppy/osu.git
synced 2025-01-15 09:22:54 +08:00
Merge branch 'master' into leaderboard-scores
This commit is contained in:
commit
a7f874e5b6
@ -1 +1 @@
|
|||||||
Subproject commit 825505e788c4f093b269c61b485d38d50cd68096
|
Subproject commit 5f2d5a57e5d506d7e5d87eeeb442adf10be061f6
|
@ -17,8 +17,8 @@ namespace osu.Desktop.Deploy
|
|||||||
{
|
{
|
||||||
internal static class Program
|
internal static class Program
|
||||||
{
|
{
|
||||||
private const string nuget_path = @"packages\NuGet.CommandLine.3.5.0\tools\NuGet.exe";
|
private const string nuget_path = @"packages\NuGet.CommandLine.4.1.0\tools\NuGet.exe";
|
||||||
private const string squirrel_path = @"packages\squirrel.windows.1.5.2\tools\Squirrel.exe";
|
private const string squirrel_path = @"packages\squirrel.windows.1.7.5\tools\Squirrel.exe";
|
||||||
private const string msbuild_path = @"C:\Program Files (x86)\MSBuild\14.0\Bin\MSBuild.exe";
|
private const string msbuild_path = @"C:\Program Files (x86)\MSBuild\14.0\Bin\MSBuild.exe";
|
||||||
|
|
||||||
public static string StagingFolder = ConfigurationManager.AppSettings["StagingFolder"];
|
public static string StagingFolder = ConfigurationManager.AppSettings["StagingFolder"];
|
||||||
|
@ -1,20 +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 NUnit.Framework;
|
|
||||||
using osu.Framework.Desktop.Platform;
|
using osu.Framework.Desktop.Platform;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Game;
|
using osu.Game;
|
||||||
|
|
||||||
namespace osu.Desktop.Tests.Visual
|
namespace osu.Desktop.Tests.Visual
|
||||||
{
|
{
|
||||||
[TestFixture]
|
|
||||||
public abstract class OsuTestCase : TestCase
|
public abstract class OsuTestCase : TestCase
|
||||||
{
|
{
|
||||||
[Test]
|
|
||||||
public override void RunTest()
|
public override void RunTest()
|
||||||
{
|
{
|
||||||
using (var host = new HeadlessGameHost())
|
using (var host = new HeadlessGameHost(realtime: false))
|
||||||
host.Run(new OsuTestCaseTestRunner(this));
|
host.Run(new OsuTestCaseTestRunner(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,28 +69,28 @@ namespace osu.Desktop.Tests.Visual
|
|||||||
|
|
||||||
private class MyContextMenuContainer : Container, IHasContextMenu
|
private class MyContextMenuContainer : Container, IHasContextMenu
|
||||||
{
|
{
|
||||||
public ContextMenuItem[] ContextMenuItems => new ContextMenuItem[]
|
public MenuItem[] ContextMenuItems => new MenuItem[]
|
||||||
{
|
{
|
||||||
new OsuContextMenuItem(@"Some option"),
|
new OsuMenuItem(@"Some option"),
|
||||||
new OsuContextMenuItem(@"Highlighted option", MenuItemType.Highlighted),
|
new OsuMenuItem(@"Highlighted option", MenuItemType.Highlighted),
|
||||||
new OsuContextMenuItem(@"Another option"),
|
new OsuMenuItem(@"Another option"),
|
||||||
new OsuContextMenuItem(@"Choose me please"),
|
new OsuMenuItem(@"Choose me please"),
|
||||||
new OsuContextMenuItem(@"And me too"),
|
new OsuMenuItem(@"And me too"),
|
||||||
new OsuContextMenuItem(@"Trying to fill"),
|
new OsuMenuItem(@"Trying to fill"),
|
||||||
new OsuContextMenuItem(@"Destructive option", MenuItemType.Destructive),
|
new OsuMenuItem(@"Destructive option", MenuItemType.Destructive),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private class AnotherContextMenuContainer : Container, IHasContextMenu
|
private class AnotherContextMenuContainer : Container, IHasContextMenu
|
||||||
{
|
{
|
||||||
public ContextMenuItem[] ContextMenuItems => new ContextMenuItem[]
|
public MenuItem[] ContextMenuItems => new MenuItem[]
|
||||||
{
|
{
|
||||||
new OsuContextMenuItem(@"Simple option"),
|
new OsuMenuItem(@"Simple option"),
|
||||||
new OsuContextMenuItem(@"Simple very very long option"),
|
new OsuMenuItem(@"Simple very very long option"),
|
||||||
new OsuContextMenuItem(@"Change width", MenuItemType.Highlighted) { Action = () => this.ResizeWidthTo(Width * 2, 100, Easing.OutQuint) },
|
new OsuMenuItem(@"Change width", MenuItemType.Highlighted, () => this.ResizeWidthTo(Width * 2, 100, Easing.OutQuint)),
|
||||||
new OsuContextMenuItem(@"Change height", MenuItemType.Highlighted) { Action = () => this.ResizeHeightTo(Height * 2, 100, Easing.OutQuint) },
|
new OsuMenuItem(@"Change height", MenuItemType.Highlighted, () => this.ResizeHeightTo(Height * 2, 100, Easing.OutQuint)),
|
||||||
new OsuContextMenuItem(@"Change width back", MenuItemType.Destructive) { Action = () => this.ResizeWidthTo(Width / 2, 100, Easing.OutQuint) },
|
new OsuMenuItem(@"Change width back", MenuItemType.Destructive, () => this.ResizeWidthTo(Width / 2, 100, Easing.OutQuint)),
|
||||||
new OsuContextMenuItem(@"Change height back", MenuItemType.Destructive) { Action = () => this.ResizeHeightTo(Height / 2, 100, Easing.OutQuint) },
|
new OsuMenuItem(@"Change height back", MenuItemType.Destructive, () => this.ResizeHeightTo(Height / 2, 100, Easing.OutQuint)),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
84
osu.Desktop.Tests/Visual/TestCaseEditorMenuBar.cs
Normal file
84
osu.Desktop.Tests/Visual/TestCaseEditorMenuBar.cs
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
// 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.Graphics;
|
||||||
|
using osu.Game.Graphics.UserInterface;
|
||||||
|
using osu.Game.Screens.Edit.Menus;
|
||||||
|
|
||||||
|
namespace osu.Desktop.Tests.Visual
|
||||||
|
{
|
||||||
|
public class TestCaseEditorMenuBar : OsuTestCase
|
||||||
|
{
|
||||||
|
public TestCaseEditorMenuBar()
|
||||||
|
{
|
||||||
|
Add(new EditorMenuBar
|
||||||
|
{
|
||||||
|
Anchor = Anchor.TopCentre,
|
||||||
|
Origin = Anchor.TopCentre,
|
||||||
|
Y = 50,
|
||||||
|
Items = new[]
|
||||||
|
{
|
||||||
|
new EditorMenuBarItem("File")
|
||||||
|
{
|
||||||
|
Items = new[]
|
||||||
|
{
|
||||||
|
new EditorMenuItem("Clear All Notes"),
|
||||||
|
new EditorMenuItem("Open Difficulty..."),
|
||||||
|
new EditorMenuItem("Save"),
|
||||||
|
new EditorMenuItem("Create a new Difficulty..."),
|
||||||
|
new EditorMenuItemSpacer(),
|
||||||
|
new EditorMenuItem("Revert to Saved"),
|
||||||
|
new EditorMenuItem("Revert to Saved (Full)"),
|
||||||
|
new EditorMenuItemSpacer(),
|
||||||
|
new EditorMenuItem("Test Beatmap"),
|
||||||
|
new EditorMenuItem("Open AiMod"),
|
||||||
|
new EditorMenuItemSpacer(),
|
||||||
|
new EditorMenuItem("Upload Beatmap..."),
|
||||||
|
new EditorMenuItem("Export Package"),
|
||||||
|
new EditorMenuItem("Export Map Package"),
|
||||||
|
new EditorMenuItem("Import from..."),
|
||||||
|
new EditorMenuItemSpacer(),
|
||||||
|
new EditorMenuItem("Open Song Folder"),
|
||||||
|
new EditorMenuItem("Open .osu in Notepad"),
|
||||||
|
new EditorMenuItem("Open .osb in Notepad"),
|
||||||
|
new EditorMenuItemSpacer(),
|
||||||
|
new EditorMenuItem("Exit"),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new EditorMenuBarItem("Timing")
|
||||||
|
{
|
||||||
|
Items = new[]
|
||||||
|
{
|
||||||
|
new EditorMenuItem("Time Signature"),
|
||||||
|
new EditorMenuItem("Metronome Clicks"),
|
||||||
|
new EditorMenuItemSpacer(),
|
||||||
|
new EditorMenuItem("Add Timing Section"),
|
||||||
|
new EditorMenuItem("Add Inheriting Section"),
|
||||||
|
new EditorMenuItem("Reset Current Section"),
|
||||||
|
new EditorMenuItem("Delete Timing Section"),
|
||||||
|
new EditorMenuItem("Resnap Current Section"),
|
||||||
|
new EditorMenuItemSpacer(),
|
||||||
|
new EditorMenuItem("Timing Setup"),
|
||||||
|
new EditorMenuItemSpacer(),
|
||||||
|
new EditorMenuItem("Resnap All Notes", MenuItemType.Destructive),
|
||||||
|
new EditorMenuItem("Move all notes in time...", MenuItemType.Destructive),
|
||||||
|
new EditorMenuItem("Recalculate Slider Lengths", MenuItemType.Destructive),
|
||||||
|
new EditorMenuItem("Delete All Timing Sections", MenuItemType.Destructive),
|
||||||
|
new EditorMenuItemSpacer(),
|
||||||
|
new EditorMenuItem("Set Current Position as Preview Point"),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new EditorMenuBarItem("Testing")
|
||||||
|
{
|
||||||
|
Items = new[]
|
||||||
|
{
|
||||||
|
new EditorMenuItem("Item 1"),
|
||||||
|
new EditorMenuItem("Item 2"),
|
||||||
|
new EditorMenuItem("Item 3"),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Game.Rulesets.Mania;
|
||||||
using osu.Game.Rulesets.Mania.Objects;
|
using osu.Game.Rulesets.Mania.Objects;
|
||||||
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
@ -40,8 +41,8 @@ namespace osu.Desktop.Tests.Visual
|
|||||||
RelativeChildSize = new Vector2(1, 10000),
|
RelativeChildSize = new Vector2(1, 10000),
|
||||||
Children = new[]
|
Children = new[]
|
||||||
{
|
{
|
||||||
new DrawableNote(new Note { StartTime = 5000 }) { AccentColour = Color4.Red },
|
new DrawableNote(new Note { StartTime = 5000 }, ManiaAction.Key1) { AccentColour = Color4.Red },
|
||||||
new DrawableNote(new Note { StartTime = 6000 }) { AccentColour = Color4.Red }
|
new DrawableNote(new Note { StartTime = 6000 }, ManiaAction.Key1) { AccentColour = Color4.Red }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -66,7 +67,7 @@ namespace osu.Desktop.Tests.Visual
|
|||||||
{
|
{
|
||||||
StartTime = 5000,
|
StartTime = 5000,
|
||||||
Duration = 1000
|
Duration = 1000
|
||||||
}) { AccentColour = Color4.Red }
|
}, ManiaAction.Key1) { AccentColour = Color4.Red }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,111 +1,34 @@
|
|||||||
// 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.Configuration;
|
using osu.Framework.Allocation;
|
||||||
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.Timing;
|
using osu.Framework.Timing;
|
||||||
|
using osu.Game.Rulesets.Mania;
|
||||||
using osu.Game.Rulesets.Mania.Objects;
|
using osu.Game.Rulesets.Mania.Objects;
|
||||||
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Mania.Timing;
|
using osu.Game.Rulesets.Mania.Timing;
|
||||||
using osu.Game.Rulesets.Mania.UI;
|
using osu.Game.Rulesets.Mania.UI;
|
||||||
using osu.Game.Rulesets.Timing;
|
using osu.Game.Rulesets.Timing;
|
||||||
using OpenTK;
|
using osu.Game.Rulesets;
|
||||||
using OpenTK.Input;
|
|
||||||
|
|
||||||
namespace osu.Desktop.Tests.Visual
|
namespace osu.Desktop.Tests.Visual
|
||||||
{
|
{
|
||||||
internal class TestCaseManiaPlayfield : OsuTestCase
|
internal class TestCaseManiaPlayfield : OsuTestCase
|
||||||
{
|
{
|
||||||
|
private const double start_time = 500;
|
||||||
|
private const double duration = 500;
|
||||||
|
|
||||||
public override string Description => @"Mania playfield";
|
public override string Description => @"Mania playfield";
|
||||||
|
|
||||||
protected override double TimePerAction => 200;
|
protected override double TimePerAction => 200;
|
||||||
|
|
||||||
|
private RulesetInfo maniaRuleset;
|
||||||
|
|
||||||
public TestCaseManiaPlayfield()
|
public TestCaseManiaPlayfield()
|
||||||
{
|
{
|
||||||
Action<int, SpecialColumnPosition> createPlayfield = (cols, pos) =>
|
|
||||||
{
|
|
||||||
Clear();
|
|
||||||
Add(new ManiaPlayfield(cols)
|
|
||||||
{
|
|
||||||
Anchor = Anchor.Centre,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
SpecialColumnPosition = pos,
|
|
||||||
Scale = new Vector2(1, -1)
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const double start_time = 500;
|
|
||||||
const double duration = 500;
|
|
||||||
|
|
||||||
Func<double, bool, SpeedAdjustmentContainer> createTimingChange = (time, gravity) => new ManiaSpeedAdjustmentContainer(new MultiplierControlPoint(time)
|
|
||||||
{
|
|
||||||
TimingPoint = { BeatLength = 1000 }
|
|
||||||
}, gravity ? ScrollingAlgorithm.Gravity : ScrollingAlgorithm.Basic);
|
|
||||||
|
|
||||||
Action<bool> createPlayfieldWithNotes = gravity =>
|
|
||||||
{
|
|
||||||
Clear();
|
|
||||||
|
|
||||||
var rateAdjustClock = new StopwatchClock(true) { Rate = 1 };
|
|
||||||
|
|
||||||
ManiaPlayfield playField;
|
|
||||||
Add(playField = new ManiaPlayfield(4)
|
|
||||||
{
|
|
||||||
Anchor = Anchor.Centre,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
Scale = new Vector2(1, -1),
|
|
||||||
Clock = new FramedClock(rateAdjustClock)
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!gravity)
|
|
||||||
playField.Columns.ForEach(c => c.Add(createTimingChange(0, false)));
|
|
||||||
|
|
||||||
for (double t = start_time; t <= start_time + duration; t += 100)
|
|
||||||
{
|
|
||||||
if (gravity)
|
|
||||||
playField.Columns.ElementAt(0).Add(createTimingChange(t, true));
|
|
||||||
|
|
||||||
playField.Add(new DrawableNote(new Note
|
|
||||||
{
|
|
||||||
StartTime = t,
|
|
||||||
Column = 0
|
|
||||||
}, new Bindable<Key>(Key.D)));
|
|
||||||
|
|
||||||
if (gravity)
|
|
||||||
playField.Columns.ElementAt(3).Add(createTimingChange(t, true));
|
|
||||||
|
|
||||||
playField.Add(new DrawableNote(new Note
|
|
||||||
{
|
|
||||||
StartTime = t,
|
|
||||||
Column = 3
|
|
||||||
}, new Bindable<Key>(Key.K)));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gravity)
|
|
||||||
playField.Columns.ElementAt(1).Add(createTimingChange(start_time, true));
|
|
||||||
|
|
||||||
playField.Add(new DrawableHoldNote(new HoldNote
|
|
||||||
{
|
|
||||||
StartTime = start_time,
|
|
||||||
Duration = duration,
|
|
||||||
Column = 1
|
|
||||||
}, new Bindable<Key>(Key.F)));
|
|
||||||
|
|
||||||
if (gravity)
|
|
||||||
playField.Columns.ElementAt(2).Add(createTimingChange(start_time, true));
|
|
||||||
|
|
||||||
playField.Add(new DrawableHoldNote(new HoldNote
|
|
||||||
{
|
|
||||||
StartTime = start_time,
|
|
||||||
Duration = duration,
|
|
||||||
Column = 2
|
|
||||||
}, new Bindable<Key>(Key.J)));
|
|
||||||
};
|
|
||||||
|
|
||||||
AddStep("1 column", () => createPlayfield(1, SpecialColumnPosition.Normal));
|
AddStep("1 column", () => createPlayfield(1, SpecialColumnPosition.Normal));
|
||||||
AddStep("4 columns", () => createPlayfield(4, SpecialColumnPosition.Normal));
|
AddStep("4 columns", () => createPlayfield(4, SpecialColumnPosition.Normal));
|
||||||
AddStep("Left special style", () => createPlayfield(4, SpecialColumnPosition.Left));
|
AddStep("Left special style", () => createPlayfield(4, SpecialColumnPosition.Left));
|
||||||
@ -114,29 +37,105 @@ namespace osu.Desktop.Tests.Visual
|
|||||||
AddStep("8 columns", () => createPlayfield(8, SpecialColumnPosition.Normal));
|
AddStep("8 columns", () => createPlayfield(8, SpecialColumnPosition.Normal));
|
||||||
AddStep("Left special style", () => createPlayfield(8, SpecialColumnPosition.Left));
|
AddStep("Left special style", () => createPlayfield(8, SpecialColumnPosition.Left));
|
||||||
AddStep("Right special style", () => createPlayfield(8, SpecialColumnPosition.Right));
|
AddStep("Right special style", () => createPlayfield(8, SpecialColumnPosition.Right));
|
||||||
|
AddStep("Reversed", () => createPlayfield(4, SpecialColumnPosition.Normal, true));
|
||||||
|
|
||||||
AddStep("Notes with input", () => createPlayfieldWithNotes(false));
|
AddStep("Notes with input", () => createPlayfieldWithNotes(false));
|
||||||
AddWaitStep((int)Math.Ceiling((start_time + duration) / TimePerAction));
|
AddStep("Notes with input (reversed)", () => createPlayfieldWithNotes(false, true));
|
||||||
|
|
||||||
AddStep("Notes with gravity", () => createPlayfieldWithNotes(true));
|
AddStep("Notes with gravity", () => createPlayfieldWithNotes(true));
|
||||||
AddWaitStep((int)Math.Ceiling((start_time + duration) / TimePerAction));
|
AddStep("Notes with gravity (reversed)", () => createPlayfieldWithNotes(true, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void triggerKeyDown(Column column)
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(RulesetStore rulesets)
|
||||||
{
|
{
|
||||||
column.TriggerOnKeyDown(new InputState(), new KeyDownEventArgs
|
maniaRuleset = rulesets.GetRuleset(3);
|
||||||
{
|
|
||||||
Key = column.Key,
|
|
||||||
Repeat = false
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void triggerKeyUp(Column column)
|
private SpeedAdjustmentContainer createTimingChange(double time, bool gravity) => new ManiaSpeedAdjustmentContainer(new MultiplierControlPoint(time)
|
||||||
{
|
{
|
||||||
column.TriggerOnKeyUp(new InputState(), new KeyUpEventArgs
|
TimingPoint = { BeatLength = 1000 }
|
||||||
|
}, gravity ? ScrollingAlgorithm.Gravity : ScrollingAlgorithm.Basic);
|
||||||
|
|
||||||
|
private void createPlayfield(int cols, SpecialColumnPosition specialPos, bool inverted = false)
|
||||||
|
{
|
||||||
|
Clear();
|
||||||
|
|
||||||
|
var inputManager = new ManiaInputManager(maniaRuleset, cols) { RelativeSizeAxes = Axes.Both };
|
||||||
|
Add(inputManager);
|
||||||
|
|
||||||
|
ManiaPlayfield playfield;
|
||||||
|
inputManager.Add(playfield = new ManiaPlayfield(cols)
|
||||||
{
|
{
|
||||||
Key = column.Key
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
SpecialColumnPosition = specialPos
|
||||||
});
|
});
|
||||||
|
|
||||||
|
playfield.Inverted.Value = inverted;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createPlayfieldWithNotes(bool gravity, bool inverted = false)
|
||||||
|
{
|
||||||
|
Clear();
|
||||||
|
|
||||||
|
var rateAdjustClock = new StopwatchClock(true) { Rate = 1 };
|
||||||
|
|
||||||
|
var inputManager = new ManiaInputManager(maniaRuleset, 4) { RelativeSizeAxes = Axes.Both };
|
||||||
|
Add(inputManager);
|
||||||
|
|
||||||
|
ManiaPlayfield playfield;
|
||||||
|
inputManager.Add(playfield = new ManiaPlayfield(4)
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
Clock = new FramedClock(rateAdjustClock)
|
||||||
|
});
|
||||||
|
|
||||||
|
playfield.Inverted.Value = inverted;
|
||||||
|
|
||||||
|
if (!gravity)
|
||||||
|
playfield.Columns.ForEach(c => c.Add(createTimingChange(0, false)));
|
||||||
|
|
||||||
|
for (double t = start_time; t <= start_time + duration; t += 100)
|
||||||
|
{
|
||||||
|
if (gravity)
|
||||||
|
playfield.Columns.ElementAt(0).Add(createTimingChange(t, true));
|
||||||
|
|
||||||
|
playfield.Add(new DrawableNote(new Note
|
||||||
|
{
|
||||||
|
StartTime = t,
|
||||||
|
Column = 0
|
||||||
|
}, ManiaAction.Key1));
|
||||||
|
|
||||||
|
if (gravity)
|
||||||
|
playfield.Columns.ElementAt(3).Add(createTimingChange(t, true));
|
||||||
|
|
||||||
|
playfield.Add(new DrawableNote(new Note
|
||||||
|
{
|
||||||
|
StartTime = t,
|
||||||
|
Column = 3
|
||||||
|
}, ManiaAction.Key4));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gravity)
|
||||||
|
playfield.Columns.ElementAt(1).Add(createTimingChange(start_time, true));
|
||||||
|
|
||||||
|
playfield.Add(new DrawableHoldNote(new HoldNote
|
||||||
|
{
|
||||||
|
StartTime = start_time,
|
||||||
|
Duration = duration,
|
||||||
|
Column = 1
|
||||||
|
}, ManiaAction.Key2));
|
||||||
|
|
||||||
|
if (gravity)
|
||||||
|
playfield.Columns.ElementAt(2).Add(createTimingChange(start_time, true));
|
||||||
|
|
||||||
|
playfield.Add(new DrawableHoldNote(new HoldNote
|
||||||
|
{
|
||||||
|
StartTime = start_time,
|
||||||
|
Duration = duration,
|
||||||
|
Column = 2
|
||||||
|
}, ManiaAction.Key3));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,18 +3,23 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using NUnit.Framework;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using osu.Desktop.Tests.Beatmaps;
|
using osu.Desktop.Tests.Beatmaps;
|
||||||
|
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||||
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.Beatmaps.ControlPoints;
|
||||||
using osu.Game.Rulesets.Beatmaps;
|
using osu.Game.Rulesets.Beatmaps;
|
||||||
using osu.Game.Rulesets.Judgements;
|
using osu.Game.Rulesets.Judgements;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
using osu.Game.Rulesets.Timing;
|
||||||
using osu.Game.Rulesets.UI;
|
using osu.Game.Rulesets.UI;
|
||||||
|
|
||||||
namespace osu.Desktop.Tests.Visual
|
namespace osu.Desktop.Tests.Visual
|
||||||
@ -22,6 +27,7 @@ namespace osu.Desktop.Tests.Visual
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The most minimal implementation of a playfield with scrolling hit objects.
|
/// The most minimal implementation of a playfield with scrolling hit objects.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[TestFixture]
|
||||||
public class TestCaseScrollingPlayfield : OsuTestCase
|
public class TestCaseScrollingPlayfield : OsuTestCase
|
||||||
{
|
{
|
||||||
public TestCaseScrollingPlayfield()
|
public TestCaseScrollingPlayfield()
|
||||||
@ -58,11 +64,71 @@ namespace osu.Desktop.Tests.Visual
|
|||||||
|
|
||||||
AddStep("Reverse direction", () =>
|
AddStep("Reverse direction", () =>
|
||||||
{
|
{
|
||||||
horizontalRulesetContainer.Playfield.Reversed.Toggle();
|
horizontalRulesetContainer.Playfield.Reverse();
|
||||||
verticalRulesetContainer.Playfield.Reversed.Toggle();
|
verticalRulesetContainer.Playfield.Reverse();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestSpeedAdjustmentOrdering()
|
||||||
|
{
|
||||||
|
var hitObjectContainer = new ScrollingPlayfield<TestHitObject, TestJudgement>.ScrollingHitObjectContainer(Axes.X);
|
||||||
|
|
||||||
|
var speedAdjustments = new[]
|
||||||
|
{
|
||||||
|
new SpeedAdjustmentContainer(new MultiplierControlPoint()),
|
||||||
|
new SpeedAdjustmentContainer(new MultiplierControlPoint(1000)
|
||||||
|
{
|
||||||
|
TimingPoint = new TimingControlPoint { BeatLength = 500 }
|
||||||
|
}),
|
||||||
|
new SpeedAdjustmentContainer(new MultiplierControlPoint(2000)
|
||||||
|
{
|
||||||
|
TimingPoint = new TimingControlPoint { BeatLength = 1000 },
|
||||||
|
DifficultyPoint = new DifficultyControlPoint { SpeedMultiplier = 2}
|
||||||
|
}),
|
||||||
|
new SpeedAdjustmentContainer(new MultiplierControlPoint(3000)
|
||||||
|
{
|
||||||
|
TimingPoint = new TimingControlPoint { BeatLength = 1000 },
|
||||||
|
DifficultyPoint = new DifficultyControlPoint { SpeedMultiplier = 1}
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
var hitObjects = new[]
|
||||||
|
{
|
||||||
|
new DrawableTestHitObject(Axes.X, new TestHitObject { StartTime = -1000 }),
|
||||||
|
new DrawableTestHitObject(Axes.X, new TestHitObject()),
|
||||||
|
new DrawableTestHitObject(Axes.X, new TestHitObject { StartTime = 1000 }),
|
||||||
|
new DrawableTestHitObject(Axes.X, new TestHitObject { StartTime = 2000 }),
|
||||||
|
new DrawableTestHitObject(Axes.X, new TestHitObject { StartTime = 3000 }),
|
||||||
|
new DrawableTestHitObject(Axes.X, new TestHitObject { StartTime = 4000 }),
|
||||||
|
};
|
||||||
|
|
||||||
|
hitObjects.ForEach(h => hitObjectContainer.Add(h));
|
||||||
|
speedAdjustments.ForEach(hitObjectContainer.AddSpeedAdjustment);
|
||||||
|
|
||||||
|
// The 0th index in hitObjectContainer.SpeedAdjustments is the "default" control point
|
||||||
|
// Check multiplier of the default speed adjustment
|
||||||
|
Assert.AreEqual(1, hitObjectContainer.SpeedAdjustments[0].ControlPoint.Multiplier);
|
||||||
|
Assert.AreEqual(1, speedAdjustments[0].ControlPoint.Multiplier);
|
||||||
|
Assert.AreEqual(2, speedAdjustments[1].ControlPoint.Multiplier);
|
||||||
|
Assert.AreEqual(2, speedAdjustments[2].ControlPoint.Multiplier);
|
||||||
|
Assert.AreEqual(1, speedAdjustments[3].ControlPoint.Multiplier);
|
||||||
|
|
||||||
|
// Check insertion of hit objects
|
||||||
|
Assert.IsTrue(hitObjectContainer.SpeedAdjustments[4].Contains(hitObjects[0]));
|
||||||
|
Assert.IsTrue(hitObjectContainer.SpeedAdjustments[3].Contains(hitObjects[1]));
|
||||||
|
Assert.IsTrue(hitObjectContainer.SpeedAdjustments[2].Contains(hitObjects[2]));
|
||||||
|
Assert.IsTrue(hitObjectContainer.SpeedAdjustments[1].Contains(hitObjects[3]));
|
||||||
|
Assert.IsTrue(hitObjectContainer.SpeedAdjustments[0].Contains(hitObjects[4]));
|
||||||
|
Assert.IsTrue(hitObjectContainer.SpeedAdjustments[0].Contains(hitObjects[5]));
|
||||||
|
|
||||||
|
hitObjectContainer.RemoveSpeedAdjustment(hitObjectContainer.SpeedAdjustments[3]);
|
||||||
|
|
||||||
|
// The hit object contained in this speed adjustment should be resorted into the one occuring before it
|
||||||
|
|
||||||
|
Assert.IsTrue(hitObjectContainer.SpeedAdjustments[3].Contains(hitObjects[1]));
|
||||||
|
}
|
||||||
|
|
||||||
private class TestRulesetContainer : ScrollingRulesetContainer<TestPlayfield, TestHitObject, TestJudgement>
|
private class TestRulesetContainer : ScrollingRulesetContainer<TestPlayfield, TestHitObject, TestJudgement>
|
||||||
{
|
{
|
||||||
private readonly Axes scrollingAxes;
|
private readonly Axes scrollingAxes;
|
||||||
@ -77,6 +143,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);
|
||||||
@ -142,6 +210,8 @@ namespace osu.Desktop.Tests.Visual
|
|||||||
content = new Container { RelativeSizeAxes = Axes.Both }
|
content = new Container { RelativeSizeAxes = Axes.Both }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Reverse() => Reversed.Toggle();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -155,4 +225,4 @@ namespace osu.Desktop.Tests.Visual
|
|||||||
public override string MaxResultString { get { throw new NotImplementedException(); } }
|
public override string MaxResultString { get { throw new NotImplementedException(); } }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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) }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,6 +87,7 @@
|
|||||||
<Compile Include="Visual\TestCaseManiaHitObjects.cs" />
|
<Compile Include="Visual\TestCaseManiaHitObjects.cs" />
|
||||||
<Compile Include="Visual\TestCaseManiaPlayfield.cs" />
|
<Compile Include="Visual\TestCaseManiaPlayfield.cs" />
|
||||||
<Compile Include="Visual\TestCaseMedalOverlay.cs" />
|
<Compile Include="Visual\TestCaseMedalOverlay.cs" />
|
||||||
|
<Compile Include="Visual\TestCaseEditorMenuBar.cs" />
|
||||||
<Compile Include="Visual\TestCaseMenuButtonSystem.cs" />
|
<Compile Include="Visual\TestCaseMenuButtonSystem.cs" />
|
||||||
<Compile Include="Visual\TestCaseMenuOverlays.cs" />
|
<Compile Include="Visual\TestCaseMenuOverlays.cs" />
|
||||||
<Compile Include="Visual\TestCaseMods.cs" />
|
<Compile Include="Visual\TestCaseMods.cs" />
|
||||||
|
@ -20,16 +20,11 @@ namespace osu.Desktop
|
|||||||
{
|
{
|
||||||
internal class OsuGameDesktop : OsuGame
|
internal class OsuGameDesktop : OsuGame
|
||||||
{
|
{
|
||||||
private readonly VersionManager versionManager;
|
private VersionManager versionManager;
|
||||||
|
|
||||||
public OsuGameDesktop(string[] args = null)
|
public OsuGameDesktop(string[] args = null)
|
||||||
: base(args)
|
: base(args)
|
||||||
{
|
{
|
||||||
versionManager = new VersionManager
|
|
||||||
{
|
|
||||||
Depth = int.MinValue,
|
|
||||||
State = Visibility.Hidden
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Storage GetStorageForStableInstall()
|
public override Storage GetStorageForStableInstall()
|
||||||
@ -88,11 +83,15 @@ namespace osu.Desktop
|
|||||||
{
|
{
|
||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
|
|
||||||
LoadComponentAsync(versionManager, Add);
|
LoadComponentAsync(versionManager = new VersionManager { Depth = int.MinValue });
|
||||||
|
|
||||||
ScreenChanged += s =>
|
ScreenChanged += s =>
|
||||||
{
|
{
|
||||||
if (!versionManager.IsPresent && s is Intro)
|
if (s is Intro && s.ChildScreen == null)
|
||||||
|
{
|
||||||
|
Add(versionManager);
|
||||||
versionManager.State = Visibility.Visible;
|
versionManager.State = Visibility.Visible;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
// 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 System.Diagnostics;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Colour;
|
using osu.Framework.Graphics.Colour;
|
||||||
@ -19,6 +20,7 @@ using OpenTK.Graphics;
|
|||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using osu.Framework.Logging;
|
using osu.Framework.Logging;
|
||||||
using osu.Game;
|
using osu.Game;
|
||||||
|
using osu.Game.Configuration;
|
||||||
|
|
||||||
namespace osu.Desktop.Overlays
|
namespace osu.Desktop.Overlays
|
||||||
{
|
{
|
||||||
@ -26,17 +28,22 @@ namespace osu.Desktop.Overlays
|
|||||||
{
|
{
|
||||||
private UpdateManager updateManager;
|
private UpdateManager updateManager;
|
||||||
private NotificationOverlay notificationOverlay;
|
private NotificationOverlay notificationOverlay;
|
||||||
|
private OsuConfigManager config;
|
||||||
|
private OsuGameBase game;
|
||||||
|
|
||||||
public override bool HandleInput => false;
|
public override bool HandleInput => false;
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(NotificationOverlay notification, OsuColour colours, TextureStore textures, OsuGameBase game)
|
private void load(NotificationOverlay notification, OsuColour colours, TextureStore textures, OsuGameBase game, OsuConfigManager config)
|
||||||
{
|
{
|
||||||
notificationOverlay = notification;
|
notificationOverlay = notification;
|
||||||
|
this.config = config;
|
||||||
|
this.game = game;
|
||||||
|
|
||||||
AutoSizeAxes = Axes.Both;
|
AutoSizeAxes = Axes.Both;
|
||||||
Anchor = Anchor.BottomCentre;
|
Anchor = Anchor.BottomCentre;
|
||||||
Origin = Anchor.BottomCentre;
|
Origin = Anchor.BottomCentre;
|
||||||
|
|
||||||
Alpha = 0;
|
Alpha = 0;
|
||||||
|
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
@ -91,6 +98,42 @@ namespace osu.Desktop.Overlays
|
|||||||
checkForUpdateAsync();
|
checkForUpdateAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
|
var version = game.Version;
|
||||||
|
var lastVersion = config.Get<string>(OsuSetting.Version);
|
||||||
|
if (game.IsDeployedBuild && version != lastVersion)
|
||||||
|
{
|
||||||
|
config.Set(OsuSetting.Version, version);
|
||||||
|
|
||||||
|
// only show a notification if we've previously saved a version to the config file (ie. not the first run).
|
||||||
|
if (!string.IsNullOrEmpty(lastVersion))
|
||||||
|
Scheduler.AddDelayed(() => notificationOverlay.Post(new UpdateCompleteNotification(version)), 5000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class UpdateCompleteNotification : SimpleNotification
|
||||||
|
{
|
||||||
|
public UpdateCompleteNotification(string version)
|
||||||
|
{
|
||||||
|
Text = $"You are now running osu!lazer {version}.\nClick to see what's new!";
|
||||||
|
Icon = FontAwesome.fa_check_square;
|
||||||
|
Activated = delegate
|
||||||
|
{
|
||||||
|
Process.Start($"https://github.com/ppy/osu/releases/tag/v{version}");
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuColour colours)
|
||||||
|
{
|
||||||
|
IconBackgound.Colour = colours.BlueDark;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected override void Dispose(bool isDisposing)
|
protected override void Dispose(bool isDisposing)
|
||||||
{
|
{
|
||||||
base.Dispose(isDisposing);
|
base.Dispose(isDisposing);
|
||||||
|
@ -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;
|
||||||
@ -99,13 +97,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)
|
||||||
{
|
{
|
||||||
|
@ -28,12 +28,20 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
|
|||||||
private Pattern lastPattern = new Pattern();
|
private Pattern lastPattern = new Pattern();
|
||||||
private FastRandom random;
|
private FastRandom random;
|
||||||
private Beatmap beatmap;
|
private Beatmap beatmap;
|
||||||
private bool isForCurrentRuleset;
|
|
||||||
|
|
||||||
protected override Beatmap<ManiaHitObject> ConvertBeatmap(Beatmap original, bool isForCurrentRuleset)
|
private readonly int availableColumns;
|
||||||
|
private readonly bool isForCurrentRuleset;
|
||||||
|
|
||||||
|
public ManiaBeatmapConverter(bool isForCurrentRuleset, int availableColumns)
|
||||||
{
|
{
|
||||||
this.isForCurrentRuleset = isForCurrentRuleset;
|
if (availableColumns <= 0) throw new ArgumentOutOfRangeException(nameof(availableColumns));
|
||||||
|
|
||||||
|
this.isForCurrentRuleset = isForCurrentRuleset;
|
||||||
|
this.availableColumns = availableColumns;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Beatmap<ManiaHitObject> ConvertBeatmap(Beatmap original)
|
||||||
|
{
|
||||||
beatmap = original;
|
beatmap = original;
|
||||||
|
|
||||||
BeatmapDifficulty difficulty = original.BeatmapInfo.Difficulty;
|
BeatmapDifficulty difficulty = original.BeatmapInfo.Difficulty;
|
||||||
@ -41,7 +49,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
|
|||||||
int seed = (int)Math.Round(difficulty.DrainRate + difficulty.CircleSize) * 20 + (int)(difficulty.OverallDifficulty * 41.2) + (int)Math.Round(difficulty.ApproachRate);
|
int seed = (int)Math.Round(difficulty.DrainRate + difficulty.CircleSize) * 20 + (int)(difficulty.OverallDifficulty * 41.2) + (int)Math.Round(difficulty.ApproachRate);
|
||||||
random = new FastRandom(seed);
|
random = new FastRandom(seed);
|
||||||
|
|
||||||
return base.ConvertBeatmap(original, isForCurrentRuleset);
|
return base.ConvertBeatmap(original);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override IEnumerable<ManiaHitObject> ConvertHitObject(HitObject original, Beatmap beatmap)
|
protected override IEnumerable<ManiaHitObject> ConvertHitObject(HitObject original, Beatmap beatmap)
|
||||||
@ -89,7 +97,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
|
|||||||
/// <returns>The hit objects generated.</returns>
|
/// <returns>The hit objects generated.</returns>
|
||||||
private IEnumerable<ManiaHitObject> generateSpecific(HitObject original)
|
private IEnumerable<ManiaHitObject> generateSpecific(HitObject original)
|
||||||
{
|
{
|
||||||
var generator = new SpecificBeatmapPatternGenerator(random, original, beatmap, lastPattern);
|
var generator = new SpecificBeatmapPatternGenerator(random, original, beatmap, availableColumns, lastPattern);
|
||||||
|
|
||||||
Pattern newPattern = generator.Generate();
|
Pattern newPattern = generator.Generate();
|
||||||
lastPattern = newPattern;
|
lastPattern = newPattern;
|
||||||
@ -113,14 +121,14 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
|
|||||||
Patterns.PatternGenerator conversion = null;
|
Patterns.PatternGenerator conversion = null;
|
||||||
|
|
||||||
if (distanceData != null)
|
if (distanceData != null)
|
||||||
conversion = new DistanceObjectPatternGenerator(random, original, beatmap, lastPattern);
|
conversion = new DistanceObjectPatternGenerator(random, original, beatmap, availableColumns, lastPattern);
|
||||||
else if (endTimeData != null)
|
else if (endTimeData != null)
|
||||||
conversion = new EndTimeObjectPatternGenerator(random, original, beatmap);
|
conversion = new EndTimeObjectPatternGenerator(random, original, beatmap, availableColumns);
|
||||||
else if (positionData != null)
|
else if (positionData != null)
|
||||||
{
|
{
|
||||||
computeDensity(original.StartTime);
|
computeDensity(original.StartTime);
|
||||||
|
|
||||||
conversion = new HitObjectPatternGenerator(random, original, beatmap, lastPattern, lastTime, lastPosition, density, lastStair);
|
conversion = new HitObjectPatternGenerator(random, original, beatmap, availableColumns, lastPattern, lastTime, lastPosition, density, lastStair);
|
||||||
|
|
||||||
recordNote(original.StartTime, positionData.Position);
|
recordNote(original.StartTime, positionData.Position);
|
||||||
}
|
}
|
||||||
@ -142,8 +150,8 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private class SpecificBeatmapPatternGenerator : Patterns.Legacy.PatternGenerator
|
private class SpecificBeatmapPatternGenerator : Patterns.Legacy.PatternGenerator
|
||||||
{
|
{
|
||||||
public SpecificBeatmapPatternGenerator(FastRandom random, HitObject hitObject, Beatmap beatmap, Pattern previousPattern)
|
public SpecificBeatmapPatternGenerator(FastRandom random, HitObject hitObject, Beatmap beatmap, int availableColumns, Pattern previousPattern)
|
||||||
: base(random, hitObject, beatmap, previousPattern)
|
: base(random, hitObject, beatmap, availableColumns, previousPattern)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,8 +29,8 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
|
|
||||||
private PatternType convertType;
|
private PatternType convertType;
|
||||||
|
|
||||||
public DistanceObjectPatternGenerator(FastRandom random, HitObject hitObject, Beatmap beatmap, Pattern previousPattern)
|
public DistanceObjectPatternGenerator(FastRandom random, HitObject hitObject, Beatmap beatmap, int availableColumns, Pattern previousPattern)
|
||||||
: base(random, hitObject, beatmap, previousPattern)
|
: base(random, hitObject, beatmap, availableColumns, previousPattern)
|
||||||
{
|
{
|
||||||
convertType = PatternType.None;
|
convertType = PatternType.None;
|
||||||
if (Beatmap.ControlPointInfo.EffectPointAt(hitObject.StartTime).KiaiMode)
|
if (Beatmap.ControlPointInfo.EffectPointAt(hitObject.StartTime).KiaiMode)
|
||||||
@ -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;
|
||||||
|
|
||||||
|
@ -15,8 +15,8 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
{
|
{
|
||||||
private readonly double endTime;
|
private readonly double endTime;
|
||||||
|
|
||||||
public EndTimeObjectPatternGenerator(FastRandom random, HitObject hitObject, Beatmap beatmap)
|
public EndTimeObjectPatternGenerator(FastRandom random, HitObject hitObject, Beatmap beatmap, int availableColumns)
|
||||||
: base(random, hitObject, beatmap, new Pattern())
|
: base(random, hitObject, beatmap, availableColumns, new Pattern())
|
||||||
{
|
{
|
||||||
var endtimeData = HitObject as IHasEndTime;
|
var endtimeData = HitObject as IHasEndTime;
|
||||||
|
|
||||||
|
@ -20,9 +20,12 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
|
|
||||||
private readonly PatternType convertType;
|
private readonly PatternType convertType;
|
||||||
|
|
||||||
public HitObjectPatternGenerator(FastRandom random, HitObject hitObject, Beatmap beatmap, Pattern previousPattern, double previousTime, Vector2 previousPosition, double density, PatternType lastStair)
|
public HitObjectPatternGenerator(FastRandom random, HitObject hitObject, Beatmap beatmap, int availableColumns, Pattern previousPattern, double previousTime, Vector2 previousPosition, double density, PatternType lastStair)
|
||||||
: base(random, hitObject, beatmap, previousPattern)
|
: base(random, hitObject, beatmap, availableColumns, previousPattern)
|
||||||
{
|
{
|
||||||
|
if (previousTime > hitObject.StartTime) throw new ArgumentOutOfRangeException(nameof(previousTime));
|
||||||
|
if (density < 0) throw new ArgumentOutOfRangeException(nameof(density));
|
||||||
|
|
||||||
StairType = lastStair;
|
StairType = lastStair;
|
||||||
|
|
||||||
TimingControlPoint timingPoint = beatmap.ControlPointInfo.TimingPointAt(hitObject.StartTime);
|
TimingControlPoint timingPoint = beatmap.ControlPointInfo.TimingPointAt(hitObject.StartTime);
|
||||||
|
@ -25,11 +25,15 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
protected readonly FastRandom Random;
|
protected readonly FastRandom Random;
|
||||||
|
|
||||||
protected PatternGenerator(FastRandom random, HitObject hitObject, Beatmap beatmap, Pattern previousPattern)
|
protected PatternGenerator(FastRandom random, HitObject hitObject, Beatmap beatmap, int availableColumns, Pattern previousPattern)
|
||||||
: base(hitObject, beatmap, previousPattern)
|
: base(hitObject, beatmap, availableColumns, previousPattern)
|
||||||
{
|
{
|
||||||
Random = random;
|
if (random == null) throw new ArgumentNullException(nameof(random));
|
||||||
|
if (beatmap == null) throw new ArgumentNullException(nameof(beatmap));
|
||||||
|
if (availableColumns <= 0) throw new ArgumentOutOfRangeException(nameof(availableColumns));
|
||||||
|
if (previousPattern == null) throw new ArgumentNullException(nameof(previousPattern));
|
||||||
|
|
||||||
|
Random = random;
|
||||||
RandomStart = AvailableColumns == 8 ? 1 : 0;
|
RandomStart = AvailableColumns == 8 ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,6 +66,12 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
/// <returns>The amount of notes to be generated.</returns>
|
/// <returns>The amount of notes to be generated.</returns>
|
||||||
protected int GetRandomNoteCount(double p2, double p3, double p4 = 0, double p5 = 0, double p6 = 0)
|
protected int GetRandomNoteCount(double p2, double p3, double p4 = 0, double p5 = 0, double p6 = 0)
|
||||||
{
|
{
|
||||||
|
if (p2 < 0 || p2 > 1) throw new ArgumentOutOfRangeException(nameof(p2));
|
||||||
|
if (p3 < 0 || p3 > 1) throw new ArgumentOutOfRangeException(nameof(p3));
|
||||||
|
if (p4 < 0 || p4 > 1) throw new ArgumentOutOfRangeException(nameof(p4));
|
||||||
|
if (p5 < 0 || p5 > 1) throw new ArgumentOutOfRangeException(nameof(p5));
|
||||||
|
if (p6 < 0 || p6 > 1) throw new ArgumentOutOfRangeException(nameof(p6));
|
||||||
|
|
||||||
double val = Random.NextDouble();
|
double val = Random.NextDouble();
|
||||||
if (val >= 1 - p6)
|
if (val >= 1 - p6)
|
||||||
return 6;
|
return 6;
|
||||||
|
@ -32,13 +32,17 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
protected readonly Beatmap Beatmap;
|
protected readonly Beatmap Beatmap;
|
||||||
|
|
||||||
protected PatternGenerator(HitObject hitObject, Beatmap beatmap, Pattern previousPattern)
|
protected PatternGenerator(HitObject hitObject, Beatmap beatmap, int availableColumns, Pattern previousPattern)
|
||||||
{
|
{
|
||||||
PreviousPattern = previousPattern;
|
if (hitObject == null) throw new ArgumentNullException(nameof(hitObject));
|
||||||
|
if (beatmap == null) throw new ArgumentNullException(nameof(beatmap));
|
||||||
|
if (availableColumns <= 0) throw new ArgumentOutOfRangeException(nameof(availableColumns));
|
||||||
|
if (previousPattern == null) throw new ArgumentNullException(nameof(previousPattern));
|
||||||
|
|
||||||
HitObject = hitObject;
|
HitObject = hitObject;
|
||||||
Beatmap = beatmap;
|
Beatmap = beatmap;
|
||||||
|
AvailableColumns = availableColumns;
|
||||||
AvailableColumns = (int)Math.Round(beatmap.BeatmapInfo.Difficulty.CircleSize);
|
PreviousPattern = previousPattern;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -6,6 +6,7 @@ using osu.Game.Rulesets.Beatmaps;
|
|||||||
using osu.Game.Rulesets.Mania.Beatmaps;
|
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||||
using osu.Game.Rulesets.Mania.Objects;
|
using osu.Game.Rulesets.Mania.Objects;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania
|
namespace osu.Game.Rulesets.Mania
|
||||||
{
|
{
|
||||||
@ -21,6 +22,6 @@ namespace osu.Game.Rulesets.Mania
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override BeatmapConverter<ManiaHitObject> CreateBeatmapConverter() => new ManiaBeatmapConverter();
|
protected override BeatmapConverter<ManiaHitObject> CreateBeatmapConverter() => new ManiaBeatmapConverter(true, (int)Math.Max(1, Math.Round(Beatmap.BeatmapInfo.Difficulty.CircleSize)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
41
osu.Game.Rulesets.Mania/ManiaInputManager.cs
Normal file
41
osu.Game.Rulesets.Mania/ManiaInputManager.cs
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
// 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.Mania
|
||||||
|
{
|
||||||
|
public class ManiaInputManager : RulesetInputManager<ManiaAction>
|
||||||
|
{
|
||||||
|
public ManiaInputManager(RulesetInfo ruleset, int variant)
|
||||||
|
: base(ruleset, variant, SimultaneousBindingMode.Unique)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum ManiaAction
|
||||||
|
{
|
||||||
|
[Description("Special")]
|
||||||
|
Special,
|
||||||
|
[Description("Key 1")]
|
||||||
|
Key1 = 10,
|
||||||
|
[Description("Key 2")]
|
||||||
|
Key2,
|
||||||
|
[Description("Key 3")]
|
||||||
|
Key3,
|
||||||
|
[Description("Key 4")]
|
||||||
|
Key4,
|
||||||
|
[Description("Key 5")]
|
||||||
|
Key5,
|
||||||
|
[Description("Key 6")]
|
||||||
|
Key6,
|
||||||
|
[Description("Key 7")]
|
||||||
|
Key7,
|
||||||
|
[Description("Key 8")]
|
||||||
|
Key8,
|
||||||
|
[Description("Key 9")]
|
||||||
|
Key9
|
||||||
|
}
|
||||||
|
}
|
@ -6,9 +6,9 @@ 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.Framework.Input.Bindings;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Rulesets.Mania.Scoring;
|
using osu.Game.Rulesets.Mania.Scoring;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
@ -109,8 +109,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();
|
||||||
@ -121,5 +119,43 @@ namespace osu.Game.Rulesets.Mania
|
|||||||
: base(rulesetInfo)
|
: base(rulesetInfo)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override IEnumerable<int> AvailableVariants => new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
|
||||||
|
|
||||||
|
public override IEnumerable<KeyBinding> GetDefaultKeyBindings(int variant = 0)
|
||||||
|
{
|
||||||
|
var leftKeys = new[]
|
||||||
|
{
|
||||||
|
InputKey.A,
|
||||||
|
InputKey.S,
|
||||||
|
InputKey.D,
|
||||||
|
InputKey.F
|
||||||
|
};
|
||||||
|
|
||||||
|
var rightKeys = new[]
|
||||||
|
{
|
||||||
|
InputKey.J,
|
||||||
|
InputKey.K,
|
||||||
|
InputKey.L,
|
||||||
|
InputKey.Semicolon
|
||||||
|
};
|
||||||
|
|
||||||
|
ManiaAction currentKey = ManiaAction.Key1;
|
||||||
|
|
||||||
|
var bindings = new List<KeyBinding>();
|
||||||
|
|
||||||
|
for (int i = leftKeys.Length - variant / 2; i < leftKeys.Length; i++)
|
||||||
|
bindings.Add(new KeyBinding(leftKeys[i], currentKey++));
|
||||||
|
|
||||||
|
for (int i = 0; i < variant / 2; i++)
|
||||||
|
bindings.Add(new KeyBinding(rightKeys[i], currentKey++));
|
||||||
|
|
||||||
|
if (variant % 2 == 1)
|
||||||
|
bindings.Add(new KeyBinding(InputKey.Space, ManiaAction.Special));
|
||||||
|
|
||||||
|
return bindings;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string GetVariantName(int variant) => $"{variant}K";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,20 +5,18 @@ using osu.Game.Rulesets.Objects.Drawables;
|
|||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
|
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
using osu.Framework.Configuration;
|
|
||||||
using OpenTK.Input;
|
|
||||||
using osu.Framework.Input;
|
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Game.Rulesets.Mania.Judgements;
|
using osu.Game.Rulesets.Mania.Judgements;
|
||||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||||
|
using osu.Framework.Input.Bindings;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Visualises a <see cref="HoldNote"/> hit object.
|
/// Visualises a <see cref="HoldNote"/> hit object.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class DrawableHoldNote : DrawableManiaHitObject<HoldNote>
|
public class DrawableHoldNote : DrawableManiaHitObject<HoldNote>, IKeyBindingHandler<ManiaAction>
|
||||||
{
|
{
|
||||||
private readonly DrawableNote head;
|
private readonly DrawableNote head;
|
||||||
private readonly DrawableNote tail;
|
private readonly DrawableNote tail;
|
||||||
@ -36,8 +34,8 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private bool hasBroken;
|
private bool hasBroken;
|
||||||
|
|
||||||
public DrawableHoldNote(HoldNote hitObject, Bindable<Key> key = null)
|
public DrawableHoldNote(HoldNote hitObject, ManiaAction action)
|
||||||
: base(hitObject, key)
|
: base(hitObject, action)
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both;
|
RelativeSizeAxes = Axes.Both;
|
||||||
Height = (float)HitObject.Duration;
|
Height = (float)HitObject.Duration;
|
||||||
@ -58,12 +56,12 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
RelativeChildOffset = new Vector2(0, (float)HitObject.StartTime),
|
RelativeChildOffset = new Vector2(0, (float)HitObject.StartTime),
|
||||||
RelativeChildSize = new Vector2(1, (float)HitObject.Duration)
|
RelativeChildSize = new Vector2(1, (float)HitObject.Duration)
|
||||||
},
|
},
|
||||||
head = new DrawableHeadNote(this, key)
|
head = new DrawableHeadNote(this, action)
|
||||||
{
|
{
|
||||||
Anchor = Anchor.TopCentre,
|
Anchor = Anchor.TopCentre,
|
||||||
Origin = Anchor.TopCentre
|
Origin = Anchor.TopCentre
|
||||||
},
|
},
|
||||||
tail = new DrawableTailNote(this, key)
|
tail = new DrawableTailNote(this, action)
|
||||||
{
|
{
|
||||||
Anchor = Anchor.BottomCentre,
|
Anchor = Anchor.BottomCentre,
|
||||||
Origin = Anchor.TopCentre
|
Origin = Anchor.TopCentre
|
||||||
@ -106,16 +104,13 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
|
public bool OnPressed(ManiaAction action)
|
||||||
{
|
{
|
||||||
// Make sure the keypress happened within the body of the hold note
|
// Make sure the action happened within the body of the hold note
|
||||||
if (Time.Current < HitObject.StartTime || Time.Current > HitObject.EndTime)
|
if (Time.Current < HitObject.StartTime || Time.Current > HitObject.EndTime)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (args.Key != Key)
|
if (action != Action)
|
||||||
return false;
|
|
||||||
|
|
||||||
if (args.Repeat)
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// The user has pressed during the body of the hold note, after the head note and its hit windows have passed
|
// The user has pressed during the body of the hold note, after the head note and its hit windows have passed
|
||||||
@ -126,13 +121,13 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnKeyUp(InputState state, KeyUpEventArgs args)
|
public bool OnReleased(ManiaAction action)
|
||||||
{
|
{
|
||||||
// Make sure that the user started holding the key during the hold note
|
// Make sure that the user started holding the key during the hold note
|
||||||
if (!holdStartTime.HasValue)
|
if (!holdStartTime.HasValue)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (args.Key != Key)
|
if (action != Action)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
holdStartTime = null;
|
holdStartTime = null;
|
||||||
@ -151,8 +146,8 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
{
|
{
|
||||||
private readonly DrawableHoldNote holdNote;
|
private readonly DrawableHoldNote holdNote;
|
||||||
|
|
||||||
public DrawableHeadNote(DrawableHoldNote holdNote, Bindable<Key> key = null)
|
public DrawableHeadNote(DrawableHoldNote holdNote, ManiaAction action)
|
||||||
: base(holdNote.HitObject.Head, key)
|
: base(holdNote.HitObject.Head, action)
|
||||||
{
|
{
|
||||||
this.holdNote = holdNote;
|
this.holdNote = holdNote;
|
||||||
|
|
||||||
@ -160,9 +155,9 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
Y = 0;
|
Y = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
|
public override bool OnPressed(ManiaAction action)
|
||||||
{
|
{
|
||||||
if (!base.OnKeyDown(state, args))
|
if (!base.OnPressed(action))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// We only want to trigger a holding state from the head if the head has received a judgement
|
// We only want to trigger a holding state from the head if the head has received a judgement
|
||||||
@ -188,8 +183,8 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
{
|
{
|
||||||
private readonly DrawableHoldNote holdNote;
|
private readonly DrawableHoldNote holdNote;
|
||||||
|
|
||||||
public DrawableTailNote(DrawableHoldNote holdNote, Bindable<Key> key = null)
|
public DrawableTailNote(DrawableHoldNote holdNote, ManiaAction action)
|
||||||
: base(holdNote.HitObject.Tail, key)
|
: base(holdNote.HitObject.Tail, action)
|
||||||
{
|
{
|
||||||
this.holdNote = holdNote;
|
this.holdNote = holdNote;
|
||||||
|
|
||||||
@ -210,7 +205,9 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
tailJudgement.HasBroken = holdNote.hasBroken;
|
tailJudgement.HasBroken = holdNote.hasBroken;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnKeyUp(InputState state, KeyUpEventArgs args)
|
public override bool OnPressed(ManiaAction action) => false; // Tail doesn't handle key down
|
||||||
|
|
||||||
|
public override bool OnReleased(ManiaAction action)
|
||||||
{
|
{
|
||||||
// Make sure that the user started holding the key during the hold note
|
// Make sure that the user started holding the key during the hold note
|
||||||
if (!holdNote.holdStartTime.HasValue)
|
if (!holdNote.holdStartTime.HasValue)
|
||||||
@ -219,7 +216,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
if (Judgement.Result != HitResult.None)
|
if (Judgement.Result != HitResult.None)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (args.Key != Key)
|
if (action != Action)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
UpdateJudgement(true);
|
UpdateJudgement(true);
|
||||||
@ -227,12 +224,6 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
// Handled by the hold note, which will set holding = false
|
// Handled by the hold note, which will set holding = false
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
|
|
||||||
{
|
|
||||||
// Tail doesn't handle key down
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,8 +2,6 @@
|
|||||||
// 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.Graphics;
|
using OpenTK.Graphics;
|
||||||
using OpenTK.Input;
|
|
||||||
using osu.Framework.Configuration;
|
|
||||||
using osu.Game.Rulesets.Mania.Judgements;
|
using osu.Game.Rulesets.Mania.Judgements;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
|
|
||||||
@ -15,17 +13,17 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The key that will trigger input for this hit object.
|
/// The key that will trigger input for this hit object.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected Bindable<Key> Key { get; private set; } = new Bindable<Key>();
|
protected ManiaAction Action { get; }
|
||||||
|
|
||||||
public new TObject HitObject;
|
public new TObject HitObject;
|
||||||
|
|
||||||
protected DrawableManiaHitObject(TObject hitObject, Bindable<Key> key = null)
|
protected DrawableManiaHitObject(TObject hitObject, ManiaAction? action = null)
|
||||||
: base(hitObject)
|
: base(hitObject)
|
||||||
{
|
{
|
||||||
HitObject = hitObject;
|
HitObject = hitObject;
|
||||||
|
|
||||||
if (key != null)
|
if (action != null)
|
||||||
Key.BindTo(key);
|
Action = action.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Color4 AccentColour
|
public override Color4 AccentColour
|
||||||
|
@ -3,10 +3,8 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
using OpenTK.Input;
|
|
||||||
using osu.Framework.Configuration;
|
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Input;
|
using osu.Framework.Input.Bindings;
|
||||||
using osu.Game.Rulesets.Mania.Judgements;
|
using osu.Game.Rulesets.Mania.Judgements;
|
||||||
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
|
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
@ -16,12 +14,12 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Visualises a <see cref="Note"/> hit object.
|
/// Visualises a <see cref="Note"/> hit object.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class DrawableNote : DrawableManiaHitObject<Note>
|
public class DrawableNote : DrawableManiaHitObject<Note>, IKeyBindingHandler<ManiaAction>
|
||||||
{
|
{
|
||||||
private readonly NotePiece headPiece;
|
private readonly NotePiece headPiece;
|
||||||
|
|
||||||
public DrawableNote(Note hitObject, Bindable<Key> key = null)
|
public DrawableNote(Note hitObject, ManiaAction action)
|
||||||
: base(hitObject, key)
|
: base(hitObject, action)
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X;
|
RelativeSizeAxes = Axes.X;
|
||||||
Height = 100;
|
Height = 100;
|
||||||
@ -81,18 +79,14 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
|
public virtual bool OnPressed(ManiaAction action)
|
||||||
{
|
{
|
||||||
if (Judgement.Result != HitResult.None)
|
if (action != Action)
|
||||||
return false;
|
|
||||||
|
|
||||||
if (args.Key != Key)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (args.Repeat)
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return UpdateJudgement(true);
|
return UpdateJudgement(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public virtual bool OnReleased(ManiaAction action) => false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,17 +3,15 @@
|
|||||||
|
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
using OpenTK.Input;
|
|
||||||
using osu.Framework.Extensions.Color4Extensions;
|
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.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Graphics.Colour;
|
using osu.Framework.Graphics.Colour;
|
||||||
using osu.Framework.Input;
|
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using System;
|
using System;
|
||||||
using osu.Framework.Configuration;
|
using osu.Framework.Input.Bindings;
|
||||||
using osu.Game.Rulesets.UI;
|
using osu.Game.Rulesets.UI;
|
||||||
using osu.Game.Rulesets.Mania.Objects;
|
using osu.Game.Rulesets.Mania.Objects;
|
||||||
using osu.Game.Rulesets.Mania.Judgements;
|
using osu.Game.Rulesets.Mania.Judgements;
|
||||||
@ -32,10 +30,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
private const float column_width = 45;
|
private const float column_width = 45;
|
||||||
private const float special_column_width = 70;
|
private const float special_column_width = 70;
|
||||||
|
|
||||||
/// <summary>
|
public ManiaAction Action;
|
||||||
/// The key that will trigger input actions for this column and hit objects contained inside it.
|
|
||||||
/// </summary>
|
|
||||||
public Bindable<Key> Key = new Bindable<Key>();
|
|
||||||
|
|
||||||
private readonly Box background;
|
private readonly Box background;
|
||||||
private readonly Container hitTargetBar;
|
private readonly Container hitTargetBar;
|
||||||
@ -101,8 +96,8 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
// For column lighting, we need to capture input events before the notes
|
// For column lighting, we need to capture input events before the notes
|
||||||
new InputTarget
|
new InputTarget
|
||||||
{
|
{
|
||||||
KeyDown = onKeyDown,
|
Pressed = onPressed,
|
||||||
KeyUp = onKeyUp
|
Released = onReleased
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -199,23 +194,20 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
HitObjects.Add(hitObject);
|
HitObjects.Add(hitObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool onKeyDown(InputState state, KeyDownEventArgs args)
|
private bool onPressed(ManiaAction action)
|
||||||
{
|
{
|
||||||
if (args.Repeat)
|
if (action == Action)
|
||||||
return false;
|
|
||||||
|
|
||||||
if (args.Key == Key)
|
|
||||||
{
|
{
|
||||||
background.FadeTo(background.Alpha + 0.2f, 50, Easing.OutQuint);
|
background.FadeTo(0.6f, 50, Easing.OutQuint);
|
||||||
keyIcon.ScaleTo(1.4f, 50, Easing.OutQuint);
|
keyIcon.ScaleTo(1.4f, 50, Easing.OutQuint);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool onKeyUp(InputState state, KeyUpEventArgs args)
|
private bool onReleased(ManiaAction action)
|
||||||
{
|
{
|
||||||
if (args.Key == Key)
|
if (action == Action)
|
||||||
{
|
{
|
||||||
background.FadeTo(0.2f, 800, Easing.OutQuart);
|
background.FadeTo(0.2f, 800, Easing.OutQuart);
|
||||||
keyIcon.ScaleTo(1f, 400, Easing.OutQuart);
|
keyIcon.ScaleTo(1f, 400, Easing.OutQuart);
|
||||||
@ -227,10 +219,10 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// This is a simple container which delegates various input events that have to be captured before the notes.
|
/// This is a simple container which delegates various input events that have to be captured before the notes.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private class InputTarget : Container
|
private class InputTarget : Container, IKeyBindingHandler<ManiaAction>
|
||||||
{
|
{
|
||||||
public Func<InputState, KeyDownEventArgs, bool> KeyDown;
|
public Func<ManiaAction, bool> Pressed;
|
||||||
public Func<InputState, KeyUpEventArgs, bool> KeyUp;
|
public Func<ManiaAction, bool> Released;
|
||||||
|
|
||||||
public InputTarget()
|
public InputTarget()
|
||||||
{
|
{
|
||||||
@ -239,8 +231,8 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
Alpha = 0;
|
Alpha = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) => KeyDown?.Invoke(state, args) ?? false;
|
public bool OnPressed(ManiaAction action) => Pressed?.Invoke(action) ?? false;
|
||||||
protected override bool OnKeyUp(InputState state, KeyUpEventArgs args) => KeyUp?.Invoke(state, args) ?? false;
|
public bool OnReleased(ManiaAction action) => Released?.Invoke(action) ?? false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,9 +11,9 @@ using osu.Framework.Graphics.Containers;
|
|||||||
using System;
|
using System;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using OpenTK.Input;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using osu.Framework.Configuration;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
@ -24,12 +24,6 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
{
|
{
|
||||||
public const float HIT_TARGET_POSITION = 50;
|
public const float HIT_TARGET_POSITION = 50;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Default column keys, expanding outwards from the middle as more column are added.
|
|
||||||
/// E.g. 2 columns use FJ, 4 columns use DFJK, 6 use SDFJKL, etc...
|
|
||||||
/// </summary>
|
|
||||||
private static readonly Key[] default_keys = { Key.A, Key.S, Key.D, Key.F, Key.J, Key.K, Key.L, Key.Semicolon };
|
|
||||||
|
|
||||||
private SpecialColumnPosition specialColumnPosition;
|
private SpecialColumnPosition specialColumnPosition;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The style to use for the special column.
|
/// The style to use for the special column.
|
||||||
@ -45,6 +39,11 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether this playfield should be inverted. This flips everything inside the playfield.
|
||||||
|
/// </summary>
|
||||||
|
public readonly Bindable<bool> Inverted = new Bindable<bool>(true);
|
||||||
|
|
||||||
private readonly FlowContainer<Column> columns;
|
private readonly FlowContainer<Column> columns;
|
||||||
public IEnumerable<Column> Columns => columns.Children;
|
public IEnumerable<Column> Columns => columns.Children;
|
||||||
|
|
||||||
@ -64,6 +63,8 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
if (columnCount <= 0)
|
if (columnCount <= 0)
|
||||||
throw new ArgumentException("Can't have zero or fewer columns.");
|
throw new ArgumentException("Can't have zero or fewer columns.");
|
||||||
|
|
||||||
|
Inverted.Value = true;
|
||||||
|
|
||||||
InternalChildren = new Drawable[]
|
InternalChildren = new Drawable[]
|
||||||
{
|
{
|
||||||
new Container
|
new Container
|
||||||
@ -122,14 +123,26 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var currentAction = ManiaAction.Key1;
|
||||||
for (int i = 0; i < columnCount; i++)
|
for (int i = 0; i < columnCount; i++)
|
||||||
{
|
{
|
||||||
var c = new Column();
|
var c = new Column();
|
||||||
c.VisibleTimeRange.BindTo(VisibleTimeRange);
|
c.VisibleTimeRange.BindTo(VisibleTimeRange);
|
||||||
|
|
||||||
|
c.IsSpecial = isSpecialColumn(i);
|
||||||
|
c.Action = c.IsSpecial ? ManiaAction.Special : currentAction++;
|
||||||
|
|
||||||
columns.Add(c);
|
columns.Add(c);
|
||||||
AddNested(c);
|
AddNested(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Inverted.ValueChanged += invertedChanged;
|
||||||
|
Inverted.TriggerChange();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void invertedChanged(bool newValue)
|
||||||
|
{
|
||||||
|
Scale = new Vector2(1, newValue ? -1 : 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
@ -144,15 +157,11 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
specialColumnColour = colours.BlueDark;
|
specialColumnColour = colours.BlueDark;
|
||||||
|
|
||||||
// Set the special column + colour + key
|
// Set the special column + colour + key
|
||||||
for (int i = 0; i < columnCount; i++)
|
foreach (var column in Columns)
|
||||||
{
|
{
|
||||||
Column column = Columns.ElementAt(i);
|
|
||||||
column.IsSpecial = isSpecialColumn(i);
|
|
||||||
|
|
||||||
if (!column.IsSpecial)
|
if (!column.IsSpecial)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
column.Key.Value = Key.Space;
|
|
||||||
column.AccentColour = specialColumnColour;
|
column.AccentColour = specialColumnColour;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -166,21 +175,6 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
nonSpecialColumns[i].AccentColour = colour;
|
nonSpecialColumns[i].AccentColour = colour;
|
||||||
nonSpecialColumns[nonSpecialColumns.Count - 1 - i].AccentColour = colour;
|
nonSpecialColumns[nonSpecialColumns.Count - 1 - i].AccentColour = colour;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We'll set the keys for non-special columns in another separate loop because it's not mirrored like the above colours
|
|
||||||
// Todo: This needs to go when we get to bindings and use Button1, ..., ButtonN instead
|
|
||||||
for (int i = 0; i < nonSpecialColumns.Count; i++)
|
|
||||||
{
|
|
||||||
Column column = nonSpecialColumns[i];
|
|
||||||
|
|
||||||
int keyOffset = default_keys.Length / 2 - nonSpecialColumns.Count / 2 + i;
|
|
||||||
if (keyOffset >= 0 && keyOffset < default_keys.Length)
|
|
||||||
column.Key.Value = default_keys[keyOffset];
|
|
||||||
else
|
|
||||||
// There is no default key defined for this column. Let's set this to Unknown for now
|
|
||||||
// however note that this will be gone after bindings are in place
|
|
||||||
column.Key.Value = Key.Unknown;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -5,11 +5,10 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Input;
|
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
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;
|
||||||
@ -32,9 +31,10 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
public class ManiaRulesetContainer : ScrollingRulesetContainer<ManiaPlayfield, ManiaHitObject, ManiaJudgement>
|
public class ManiaRulesetContainer : ScrollingRulesetContainer<ManiaPlayfield, ManiaHitObject, ManiaJudgement>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Preferred column count. This will only have an effect during the initialization of the play field.
|
/// The number of columns which the <see cref="ManiaPlayfield"/> should display, and which
|
||||||
|
/// the beatmap converter will attempt to convert beatmaps to use.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int PreferredColumns;
|
private int availableColumns;
|
||||||
|
|
||||||
public IEnumerable<DrawableBarLine> BarLines;
|
public IEnumerable<DrawableBarLine> BarLines;
|
||||||
|
|
||||||
@ -75,36 +75,47 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
BarLines.ForEach(Playfield.Add);
|
BarLines.ForEach(Playfield.Add);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void ApplyBeatmap()
|
protected sealed override Playfield<ManiaHitObject, ManiaJudgement> CreatePlayfield() => new ManiaPlayfield(availableColumns)
|
||||||
{
|
|
||||||
base.ApplyBeatmap();
|
|
||||||
|
|
||||||
PreferredColumns = (int)Math.Max(1, Math.Round(Beatmap.BeatmapInfo.Difficulty.CircleSize));
|
|
||||||
}
|
|
||||||
|
|
||||||
protected sealed override Playfield<ManiaHitObject, ManiaJudgement> CreatePlayfield() => new ManiaPlayfield(PreferredColumns)
|
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
// Invert by default for now (should be moved to config/skin later)
|
|
||||||
Scale = new Vector2(1, -1)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
public override ScoreProcessor CreateScoreProcessor() => new ManiaScoreProcessor(this);
|
public override ScoreProcessor CreateScoreProcessor() => new ManiaScoreProcessor(this);
|
||||||
|
|
||||||
protected override BeatmapConverter<ManiaHitObject> CreateBeatmapConverter() => new ManiaBeatmapConverter();
|
public override PassThroughInputManager CreateInputManager() => new ManiaInputManager(Ruleset.RulesetInfo, availableColumns);
|
||||||
|
|
||||||
|
protected override BeatmapConverter<ManiaHitObject> CreateBeatmapConverter()
|
||||||
|
{
|
||||||
|
if (IsForCurrentRuleset)
|
||||||
|
availableColumns = (int)Math.Max(1, Math.Round(WorkingBeatmap.BeatmapInfo.Difficulty.CircleSize));
|
||||||
|
else
|
||||||
|
{
|
||||||
|
float percentSliderOrSpinner = (float)WorkingBeatmap.Beatmap.HitObjects.Count(h => h is IHasEndTime) / WorkingBeatmap.Beatmap.HitObjects.Count;
|
||||||
|
if (percentSliderOrSpinner < 0.2)
|
||||||
|
availableColumns = 7;
|
||||||
|
else if (percentSliderOrSpinner < 0.3 || Math.Round(WorkingBeatmap.BeatmapInfo.Difficulty.CircleSize) >= 5)
|
||||||
|
availableColumns = Math.Round(WorkingBeatmap.BeatmapInfo.Difficulty.OverallDifficulty) > 5 ? 7 : 6;
|
||||||
|
else if (percentSliderOrSpinner > 0.6)
|
||||||
|
availableColumns = Math.Round(WorkingBeatmap.BeatmapInfo.Difficulty.OverallDifficulty) > 4 ? 5 : 4;
|
||||||
|
else
|
||||||
|
availableColumns = Math.Max(4, Math.Min((int)Math.Round(WorkingBeatmap.BeatmapInfo.Difficulty.OverallDifficulty) + 1, 7));
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ManiaBeatmapConverter(IsForCurrentRuleset, availableColumns);
|
||||||
|
}
|
||||||
|
|
||||||
protected override DrawableHitObject<ManiaHitObject, ManiaJudgement> GetVisualRepresentation(ManiaHitObject h)
|
protected override DrawableHitObject<ManiaHitObject, ManiaJudgement> GetVisualRepresentation(ManiaHitObject h)
|
||||||
{
|
{
|
||||||
Bindable<Key> key = Playfield.Columns.ElementAt(h.Column).Key;
|
ManiaAction action = Playfield.Columns.ElementAt(h.Column).Action;
|
||||||
|
|
||||||
var holdNote = h as HoldNote;
|
var holdNote = h as HoldNote;
|
||||||
if (holdNote != null)
|
if (holdNote != null)
|
||||||
return new DrawableHoldNote(holdNote, key);
|
return new DrawableHoldNote(holdNote, action);
|
||||||
|
|
||||||
var note = h as Note;
|
var note = h as Note;
|
||||||
if (note != null)
|
if (note != null)
|
||||||
return new DrawableNote(note, key);
|
return new DrawableNote(note, action);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -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" />
|
||||||
|
@ -7,8 +7,13 @@ using osu.Game.Rulesets.Osu.Replays;
|
|||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||||
|
using osu.Game.Rulesets.Osu.UI;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
using osu.Game.Rulesets.UI;
|
||||||
|
using OpenTK;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Mods
|
namespace osu.Game.Rulesets.Osu.Mods
|
||||||
{
|
{
|
||||||
@ -28,10 +33,23 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
public override double ScoreMultiplier => 1.06;
|
public override double ScoreMultiplier => 1.06;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class OsuModHardRock : ModHardRock
|
public class OsuModHardRock : ModHardRock, IApplicableMod<OsuHitObject>
|
||||||
{
|
{
|
||||||
public override double ScoreMultiplier => 1.06;
|
public override double ScoreMultiplier => 1.06;
|
||||||
public override bool Ranked => true;
|
public override bool Ranked => true;
|
||||||
|
|
||||||
|
public void ApplyToRulesetContainer(RulesetContainer<OsuHitObject> rulesetContainer)
|
||||||
|
{
|
||||||
|
rulesetContainer.Objects.OfType<OsuHitObject>().ForEach(h => h.Position = new Vector2(h.Position.X, OsuPlayfield.BASE_SIZE.Y - h.Y));
|
||||||
|
rulesetContainer.Objects.OfType<Slider>().ForEach(s =>
|
||||||
|
{
|
||||||
|
var newControlPoints = new List<Vector2>();
|
||||||
|
s.ControlPoints.ForEach(c => newControlPoints.Add(new Vector2(c.X, OsuPlayfield.BASE_SIZE.Y - c.Y)));
|
||||||
|
|
||||||
|
s.ControlPoints = newControlPoints;
|
||||||
|
s.Curve?.Calculate(); // Recalculate the slider curve
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class OsuModSuddenDeath : ModSuddenDeath
|
public class OsuModSuddenDeath : ModSuddenDeath
|
||||||
|
@ -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;
|
||||||
|
@ -2,36 +2,15 @@
|
|||||||
// 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.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Linq;
|
|
||||||
using osu.Framework.Input;
|
|
||||||
using osu.Framework.Input.Bindings;
|
using osu.Framework.Input.Bindings;
|
||||||
using osu.Game.Input.Bindings;
|
using osu.Game.Rulesets.UI;
|
||||||
using OpenTK.Input;
|
|
||||||
using KeyboardState = osu.Framework.Input.KeyboardState;
|
|
||||||
using MouseState = osu.Framework.Input.MouseState;
|
|
||||||
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
|
||||||
protected override void TransformState(InputState state)
|
|
||||||
{
|
|
||||||
base.TransformState(state);
|
|
||||||
|
|
||||||
var mouse = state.Mouse as MouseState;
|
|
||||||
var keyboard = state.Keyboard as KeyboardState;
|
|
||||||
|
|
||||||
if (mouse != null && keyboard != null)
|
|
||||||
{
|
|
||||||
if (mouse.IsPressed(MouseButton.Left))
|
|
||||||
keyboard.Keys = keyboard.Keys.Concat(new[] { Key.LastKey + 1 });
|
|
||||||
if (mouse.IsPressed(MouseButton.Right))
|
|
||||||
keyboard.Keys = keyboard.Keys.Concat(new[] { Key.LastKey + 2 });
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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[]
|
||||||
@ -120,14 +118,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();
|
||||||
|
35
osu.Game.Rulesets.Osu/Replays/OsuReplayInputHandler.cs
Normal file
35
osu.Game.Rulesets.Osu/Replays/OsuReplayInputHandler.cs
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
// 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.Collections.Generic;
|
||||||
|
using osu.Framework.Input;
|
||||||
|
using osu.Game.Rulesets.Replays;
|
||||||
|
using OpenTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Osu.Replays
|
||||||
|
{
|
||||||
|
public class OsuReplayInputHandler : FramedReplayInputHandler
|
||||||
|
{
|
||||||
|
public OsuReplayInputHandler(Replay replay)
|
||||||
|
: base(replay)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override List<InputState> GetPendingStates()
|
||||||
|
{
|
||||||
|
List<OsuAction> actions = new List<OsuAction>();
|
||||||
|
|
||||||
|
if (CurrentFrame?.MouseLeft ?? false) actions.Add(OsuAction.LeftButton);
|
||||||
|
if (CurrentFrame?.MouseRight ?? false) actions.Add(OsuAction.RightButton);
|
||||||
|
|
||||||
|
return new List<InputState>
|
||||||
|
{
|
||||||
|
new ReplayState<OsuAction>
|
||||||
|
{
|
||||||
|
Mouse = new ReplayMouseState(ToScreenSpace(Position ?? Vector2.Zero)),
|
||||||
|
PressedActions = actions
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,8 +1,11 @@
|
|||||||
// 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.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using osu.Framework.Configuration;
|
||||||
using osu.Framework.Extensions;
|
using osu.Framework.Extensions;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Osu.Judgements;
|
using osu.Game.Rulesets.Osu.Judgements;
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
@ -14,6 +17,8 @@ namespace osu.Game.Rulesets.Osu.Scoring
|
|||||||
{
|
{
|
||||||
internal class OsuScoreProcessor : ScoreProcessor<OsuHitObject, OsuJudgement>
|
internal class OsuScoreProcessor : ScoreProcessor<OsuHitObject, OsuJudgement>
|
||||||
{
|
{
|
||||||
|
public readonly Bindable<ScoringMode> Mode = new Bindable<ScoringMode>(ScoringMode.Exponential);
|
||||||
|
|
||||||
public OsuScoreProcessor()
|
public OsuScoreProcessor()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -23,6 +28,35 @@ namespace osu.Game.Rulesets.Osu.Scoring
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private float hpDrainRate;
|
||||||
|
|
||||||
|
private int totalAccurateJudgements;
|
||||||
|
|
||||||
|
private readonly Dictionary<OsuScoreResult, int> scoreResultCounts = new Dictionary<OsuScoreResult, int>();
|
||||||
|
private readonly Dictionary<ComboResult, int> comboResultCounts = new Dictionary<ComboResult, int>();
|
||||||
|
|
||||||
|
private double comboMaxScore;
|
||||||
|
|
||||||
|
protected override void ComputeTargets(Beatmap<OsuHitObject> beatmap)
|
||||||
|
{
|
||||||
|
hpDrainRate = beatmap.BeatmapInfo.Difficulty.DrainRate;
|
||||||
|
totalAccurateJudgements = beatmap.HitObjects.Count;
|
||||||
|
|
||||||
|
foreach (var h in beatmap.HitObjects)
|
||||||
|
{
|
||||||
|
if (h != null)
|
||||||
|
{
|
||||||
|
// TODO: add support for other object types.
|
||||||
|
AddJudgement(new OsuJudgement
|
||||||
|
{
|
||||||
|
MaxScore = OsuScoreResult.Hit300,
|
||||||
|
Score = OsuScoreResult.Hit300,
|
||||||
|
Result = HitResult.Hit
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected override void Reset()
|
protected override void Reset()
|
||||||
{
|
{
|
||||||
base.Reset();
|
base.Reset();
|
||||||
@ -34,9 +68,6 @@ namespace osu.Game.Rulesets.Osu.Scoring
|
|||||||
comboResultCounts.Clear();
|
comboResultCounts.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly Dictionary<OsuScoreResult, int> scoreResultCounts = new Dictionary<OsuScoreResult, int>();
|
|
||||||
private readonly Dictionary<ComboResult, int> comboResultCounts = new Dictionary<ComboResult, int>();
|
|
||||||
|
|
||||||
public override void PopulateScore(Score score)
|
public override void PopulateScore(Score score)
|
||||||
{
|
{
|
||||||
base.PopulateScore(score);
|
base.PopulateScore(score);
|
||||||
@ -57,28 +88,75 @@ namespace osu.Game.Rulesets.Osu.Scoring
|
|||||||
comboResultCounts[judgement.Combo] = comboResultCounts.GetOrDefault(judgement.Combo) + 1;
|
comboResultCounts[judgement.Combo] = comboResultCounts.GetOrDefault(judgement.Combo) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (judgement.Result)
|
switch (judgement.Score)
|
||||||
{
|
{
|
||||||
case HitResult.Hit:
|
case OsuScoreResult.Hit300:
|
||||||
Health.Value += 0.1f;
|
Health.Value += (10.2 - hpDrainRate) * 0.02;
|
||||||
break;
|
break;
|
||||||
case HitResult.Miss:
|
|
||||||
Health.Value -= 0.2f;
|
case OsuScoreResult.Hit100:
|
||||||
|
Health.Value += (8 - hpDrainRate) * 0.02;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OsuScoreResult.Hit50:
|
||||||
|
Health.Value += (4 - hpDrainRate) * 0.02;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OsuScoreResult.SliderTick:
|
||||||
|
Health.Value += Math.Max(7 - hpDrainRate, 0) * 0.01;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OsuScoreResult.Miss:
|
||||||
|
Health.Value -= hpDrainRate * 0.04;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int score = 0;
|
calculateScore();
|
||||||
int maxScore = 0;
|
}
|
||||||
|
|
||||||
|
private void calculateScore()
|
||||||
|
{
|
||||||
|
int baseScore = 0;
|
||||||
|
double comboScore = 0;
|
||||||
|
|
||||||
|
int baseMaxScore = 0;
|
||||||
|
|
||||||
foreach (var j in Judgements)
|
foreach (var j in Judgements)
|
||||||
{
|
{
|
||||||
score += j.ScoreValue;
|
baseScore += j.ScoreValue;
|
||||||
maxScore += j.MaxScoreValue;
|
baseMaxScore += j.MaxScoreValue;
|
||||||
|
|
||||||
|
comboScore += j.ScoreValue * (1 + Combo.Value / 10d);
|
||||||
}
|
}
|
||||||
|
|
||||||
TotalScore.Value = score;
|
Accuracy.Value = (double)baseScore / baseMaxScore;
|
||||||
Accuracy.Value = (double)score / maxScore;
|
|
||||||
|
if (comboScore > comboMaxScore)
|
||||||
|
comboMaxScore = comboScore;
|
||||||
|
|
||||||
|
if (baseScore == 0)
|
||||||
|
TotalScore.Value = 0;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// temporary to make scoring feel more like score v1 without being score v1.
|
||||||
|
float exponentialFactor = Mode.Value == ScoringMode.Exponential ? (float)Judgements.Count / 100 : 1;
|
||||||
|
|
||||||
|
TotalScore.Value =
|
||||||
|
(int)
|
||||||
|
(
|
||||||
|
exponentialFactor *
|
||||||
|
700000 * comboScore / comboMaxScore +
|
||||||
|
300000 * Math.Pow(Accuracy.Value, 10) * ((double)Judgements.Count / totalAccurateJudgements) +
|
||||||
|
0 /* bonusScore */
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum ScoringMode
|
||||||
|
{
|
||||||
|
Standardised,
|
||||||
|
Exponential
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,9 +10,11 @@ using osu.Game.Rulesets.Osu.Beatmaps;
|
|||||||
using osu.Game.Rulesets.Osu.Judgements;
|
using osu.Game.Rulesets.Osu.Judgements;
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||||
|
using osu.Game.Rulesets.Osu.Replays;
|
||||||
using osu.Game.Rulesets.Osu.Scoring;
|
using osu.Game.Rulesets.Osu.Scoring;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Rulesets.UI;
|
using osu.Game.Rulesets.UI;
|
||||||
|
using osu.Game.Rulesets.Replays;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.UI
|
namespace osu.Game.Rulesets.Osu.UI
|
||||||
{
|
{
|
||||||
@ -31,7 +33,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)
|
||||||
{
|
{
|
||||||
@ -49,6 +51,8 @@ namespace osu.Game.Rulesets.Osu.UI
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override FramedReplayInputHandler CreateReplayInputHandler(Replay replay) => new OsuReplayInputHandler(replay);
|
||||||
|
|
||||||
protected override Vector2 GetPlayfieldAspectAdjust() => new Vector2(0.75f);
|
protected override Vector2 GetPlayfieldAspectAdjust() => new Vector2(0.75f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -78,6 +78,7 @@
|
|||||||
<Compile Include="OsuDifficulty\Skills\Speed.cs" />
|
<Compile Include="OsuDifficulty\Skills\Speed.cs" />
|
||||||
<Compile Include="OsuDifficulty\Utils\History.cs" />
|
<Compile Include="OsuDifficulty\Utils\History.cs" />
|
||||||
<Compile Include="OsuInputManager.cs" />
|
<Compile Include="OsuInputManager.cs" />
|
||||||
|
<Compile Include="Replays\OsuReplayInputHandler.cs" />
|
||||||
<Compile Include="UI\Cursor\CursorTrail.cs" />
|
<Compile Include="UI\Cursor\CursorTrail.cs" />
|
||||||
<Compile Include="UI\Cursor\GameplayCursor.cs" />
|
<Compile Include="UI\Cursor\GameplayCursor.cs" />
|
||||||
<Compile Include="UI\OsuSettings.cs" />
|
<Compile Include="UI\OsuSettings.cs" />
|
||||||
|
@ -39,15 +39,22 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private const float taiko_base_distance = 100;
|
private const float taiko_base_distance = 100;
|
||||||
|
|
||||||
|
private readonly 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)
|
public TaikoBeatmapConverter(bool isForCurrentRuleset)
|
||||||
|
{
|
||||||
|
this.isForCurrentRuleset = isForCurrentRuleset;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Beatmap<TaikoHitObject> ConvertBeatmap(Beatmap original)
|
||||||
{
|
{
|
||||||
// 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;
|
||||||
|
|
||||||
Beatmap<TaikoHitObject> converted = base.ConvertBeatmap(original, isForCurrentRuleset);
|
Beatmap<TaikoHitObject> converted = base.ConvertBeatmap(original);
|
||||||
|
|
||||||
// Post processing step to transform hit objects with the same start time into strong hits
|
// Post processing step to transform hit objects with the same start time into strong hits
|
||||||
converted.HitObjects = converted.HitObjects.GroupBy(t => t.StartTime).Select(x =>
|
converted.HitObjects = converted.HitObjects.GroupBy(t => t.StartTime).Select(x =>
|
||||||
@ -81,7 +88,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 +101,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 +111,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.
|
||||||
@ -29,14 +28,6 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|||||||
FillMode = FillMode.Fit;
|
FillMode = FillMode.Fit;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void LoadComplete()
|
|
||||||
{
|
|
||||||
base.LoadComplete();
|
|
||||||
|
|
||||||
// We need to set this here because RelativeSizeAxes won't/can't set our size by default with a different RelativeChildSize
|
|
||||||
Width *= Parent.RelativeChildSize.X;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void CheckJudgement(bool userTriggered)
|
protected override void CheckJudgement(bool userTriggered)
|
||||||
{
|
{
|
||||||
if (!userTriggered)
|
if (!userTriggered)
|
||||||
@ -62,16 +53,23 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void Update()
|
||||||
|
{
|
||||||
|
base.Update();
|
||||||
|
|
||||||
|
Size = BaseSize * Parent.RelativeChildSize;
|
||||||
|
}
|
||||||
|
|
||||||
protected override void UpdateState(ArmedState state)
|
protected override void UpdateState(ArmedState state)
|
||||||
{
|
{
|
||||||
var circlePiece = MainPiece as CirclePiece;
|
var circlePiece = MainPiece as CirclePiece;
|
||||||
|
@ -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.
|
||||||
@ -200,6 +199,8 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|||||||
{
|
{
|
||||||
base.Update();
|
base.Update();
|
||||||
|
|
||||||
|
Size = BaseSize * Parent.RelativeChildSize;
|
||||||
|
|
||||||
// Make the swell stop at the hit target
|
// Make the swell stop at the hit target
|
||||||
X = (float)Math.Max(Time.Current, HitObject.StartTime);
|
X = (float)Math.Max(Time.Current, HitObject.StartTime);
|
||||||
|
|
||||||
@ -211,8 +212,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 +222,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,28 +1,23 @@
|
|||||||
// 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 Vector2 BaseSize;
|
||||||
|
|
||||||
protected readonly TaikoPiece MainPiece;
|
protected readonly TaikoPiece MainPiece;
|
||||||
|
|
||||||
public new TaikoHitType HitObject;
|
public new TaikoHitType HitObject;
|
||||||
@ -36,7 +31,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|||||||
Origin = Anchor.Custom;
|
Origin = Anchor.Custom;
|
||||||
|
|
||||||
RelativeSizeAxes = Axes.Both;
|
RelativeSizeAxes = Axes.Both;
|
||||||
Size = new Vector2(HitObject.IsStrong ? TaikoHitObject.DEFAULT_STRONG_SIZE : TaikoHitObject.DEFAULT_SIZE);
|
Size = BaseSize = new Vector2(HitObject.IsStrong ? TaikoHitObject.DEFAULT_STRONG_SIZE : TaikoHitObject.DEFAULT_SIZE);
|
||||||
|
|
||||||
Add(MainPiece = CreateMainPiece());
|
Add(MainPiece = CreateMainPiece());
|
||||||
MainPiece.KiaiMode = HitObject.Kiai;
|
MainPiece.KiaiMode = HitObject.Kiai;
|
||||||
@ -46,20 +41,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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
using osu.Game.Rulesets.Replays;
|
using osu.Game.Rulesets.Replays;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
using OpenTK.Input;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Taiko.Replays
|
namespace osu.Game.Rulesets.Taiko.Replays
|
||||||
{
|
{
|
||||||
@ -17,21 +16,18 @@ namespace osu.Game.Rulesets.Taiko.Replays
|
|||||||
|
|
||||||
public override List<InputState> GetPendingStates()
|
public override List<InputState> GetPendingStates()
|
||||||
{
|
{
|
||||||
var keys = new List<Key>();
|
var actions = new List<TaikoAction>();
|
||||||
|
|
||||||
if (CurrentFrame?.MouseRight1 == true)
|
if (CurrentFrame?.MouseRight1 == true)
|
||||||
keys.Add(Key.F);
|
actions.Add(TaikoAction.LeftCentre);
|
||||||
if (CurrentFrame?.MouseRight2 == true)
|
if (CurrentFrame?.MouseRight2 == true)
|
||||||
keys.Add(Key.J);
|
actions.Add(TaikoAction.RightCentre);
|
||||||
if (CurrentFrame?.MouseLeft1 == true)
|
if (CurrentFrame?.MouseLeft1 == true)
|
||||||
keys.Add(Key.D);
|
actions.Add(TaikoAction.LeftRim);
|
||||||
if (CurrentFrame?.MouseLeft2 == true)
|
if (CurrentFrame?.MouseLeft2 == true)
|
||||||
keys.Add(Key.K);
|
actions.Add(TaikoAction.RightRim);
|
||||||
|
|
||||||
return new List<InputState>
|
return new List<InputState> { new ReplayState<TaikoAction> { PressedActions = actions } };
|
||||||
{
|
|
||||||
new InputState { Keyboard = new ReplayKeyboardState(keys) }
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -268,6 +268,7 @@ namespace osu.Game.Rulesets.Taiko.Scoring
|
|||||||
base.Reset();
|
base.Reset();
|
||||||
|
|
||||||
Health.Value = 0;
|
Health.Value = 0;
|
||||||
|
Accuracy.Value = 1;
|
||||||
|
|
||||||
bonusScore = 0;
|
bonusScore = 0;
|
||||||
comboPortion = 0;
|
comboPortion = 0;
|
||||||
|
@ -135,6 +135,6 @@ namespace osu.Game.Rulesets.Taiko
|
|||||||
return difficulty;
|
return difficulty;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override BeatmapConverter<TaikoHitObject> CreateBeatmapConverter() => new TaikoBeatmapConverter();
|
protected override BeatmapConverter<TaikoHitObject> CreateBeatmapConverter() => new TaikoBeatmapConverter(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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)
|
||||||
@ -88,14 +99,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
|
||||||
{
|
{
|
||||||
@ -90,7 +91,9 @@ namespace osu.Game.Rulesets.Taiko.UI
|
|||||||
|
|
||||||
public override ScoreProcessor CreateScoreProcessor() => new TaikoScoreProcessor(this);
|
public override ScoreProcessor CreateScoreProcessor() => new TaikoScoreProcessor(this);
|
||||||
|
|
||||||
protected override BeatmapConverter<TaikoHitObject> CreateBeatmapConverter() => new TaikoBeatmapConverter();
|
protected override BeatmapConverter<TaikoHitObject> CreateBeatmapConverter() => new TaikoBeatmapConverter(IsForCurrentRuleset);
|
||||||
|
|
||||||
|
public override PassThroughInputManager CreateInputManager() => new TaikoInputManager(Ruleset.RulesetInfo);
|
||||||
|
|
||||||
protected override Playfield<TaikoHitObject, TaikoJudgement> CreatePlayfield() => new TaikoPlayfield
|
protected override Playfield<TaikoHitObject, TaikoJudgement> CreatePlayfield() => new TaikoPlayfield
|
||||||
{
|
{
|
||||||
|
@ -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" />
|
||||||
|
@ -13,7 +13,6 @@ using osu.Framework.Platform;
|
|||||||
using osu.Game.IPC;
|
using osu.Game.IPC;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets;
|
|
||||||
|
|
||||||
namespace osu.Game.Tests.Beatmaps.IO
|
namespace osu.Game.Tests.Beatmaps.IO
|
||||||
{
|
{
|
||||||
@ -98,16 +97,14 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
|
|
||||||
private OsuGameBase loadOsu(GameHost host)
|
private OsuGameBase loadOsu(GameHost host)
|
||||||
{
|
{
|
||||||
|
host.Storage.DeleteDatabase(@"client");
|
||||||
|
|
||||||
var osu = new OsuGameBase();
|
var osu = new OsuGameBase();
|
||||||
Task.Run(() => host.Run(osu));
|
Task.Run(() => host.Run(osu));
|
||||||
|
|
||||||
while (!osu.IsLoaded)
|
while (!osu.IsLoaded)
|
||||||
Thread.Sleep(1);
|
Thread.Sleep(1);
|
||||||
|
|
||||||
//reset beatmap database (sqlite and storage backing)
|
|
||||||
osu.Dependencies.Get<RulesetStore>().Reset();
|
|
||||||
osu.Dependencies.Get<BeatmapManager>().Reset();
|
|
||||||
|
|
||||||
return osu;
|
return osu;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,9 +49,18 @@ namespace osu.Game.Beatmaps
|
|||||||
|
|
||||||
public string Path { get; set; }
|
public string Path { get; set; }
|
||||||
|
|
||||||
[JsonProperty("file_md5")]
|
[JsonProperty("file_sha2")]
|
||||||
public string Hash { get; set; }
|
public string Hash { get; set; }
|
||||||
|
|
||||||
|
public bool Hidden { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// MD5 is kept for legacy support (matching against replays, osu-web-10 etc.).
|
||||||
|
/// </summary>
|
||||||
|
[Indexed]
|
||||||
|
[JsonProperty("file_md5")]
|
||||||
|
public string MD5Hash { get; set; }
|
||||||
|
|
||||||
// General
|
// General
|
||||||
public int AudioLeadIn { get; set; }
|
public int AudioLeadIn { get; set; }
|
||||||
public bool Countdown { get; set; }
|
public bool Countdown { get; set; }
|
||||||
|
@ -33,11 +33,21 @@ namespace osu.Game.Beatmaps
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public event Action<BeatmapSetInfo> BeatmapSetAdded;
|
public event Action<BeatmapSetInfo> BeatmapSetAdded;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Fired when a single difficulty has been hidden.
|
||||||
|
/// </summary>
|
||||||
|
public event Action<BeatmapInfo> BeatmapHidden;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Fired when a <see cref="BeatmapSetInfo"/> is removed from the database.
|
/// Fired when a <see cref="BeatmapSetInfo"/> is removed from the database.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public event Action<BeatmapSetInfo> BeatmapSetRemoved;
|
public event Action<BeatmapSetInfo> BeatmapSetRemoved;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Fired when a single difficulty has been restored.
|
||||||
|
/// </summary>
|
||||||
|
public event Action<BeatmapInfo> BeatmapRestored;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A default representation of a WorkingBeatmap to use when no beatmap is available.
|
/// A default representation of a WorkingBeatmap to use when no beatmap is available.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -71,6 +81,8 @@ namespace osu.Game.Beatmaps
|
|||||||
beatmaps = new BeatmapStore(connection);
|
beatmaps = new BeatmapStore(connection);
|
||||||
beatmaps.BeatmapSetAdded += s => BeatmapSetAdded?.Invoke(s);
|
beatmaps.BeatmapSetAdded += s => BeatmapSetAdded?.Invoke(s);
|
||||||
beatmaps.BeatmapSetRemoved += s => BeatmapSetRemoved?.Invoke(s);
|
beatmaps.BeatmapSetRemoved += s => BeatmapSetRemoved?.Invoke(s);
|
||||||
|
beatmaps.BeatmapHidden += b => BeatmapHidden?.Invoke(b);
|
||||||
|
beatmaps.BeatmapRestored += b => BeatmapRestored?.Invoke(b);
|
||||||
|
|
||||||
this.storage = storage;
|
this.storage = storage;
|
||||||
this.files = files;
|
this.files = files;
|
||||||
@ -162,24 +174,34 @@ namespace osu.Game.Beatmaps
|
|||||||
// If we have an ID then we already exist in the database.
|
// If we have an ID then we already exist in the database.
|
||||||
if (beatmapSetInfo.ID != 0) return;
|
if (beatmapSetInfo.ID != 0) return;
|
||||||
|
|
||||||
lock (beatmaps)
|
beatmaps.Add(beatmapSetInfo);
|
||||||
beatmaps.Add(beatmapSetInfo);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Delete a beatmap from the manager.
|
/// Delete a beatmap from the manager.
|
||||||
/// Is a no-op for already deleted beatmaps.
|
/// Is a no-op for already deleted beatmaps.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="beatmapSet">The beatmap to delete.</param>
|
/// <param name="beatmapSet">The beatmap set to delete.</param>
|
||||||
public void Delete(BeatmapSetInfo beatmapSet)
|
public void Delete(BeatmapSetInfo beatmapSet)
|
||||||
{
|
{
|
||||||
lock (beatmaps)
|
if (!beatmaps.Delete(beatmapSet)) return;
|
||||||
if (!beatmaps.Delete(beatmapSet)) return;
|
|
||||||
|
|
||||||
if (!beatmapSet.Protected)
|
if (!beatmapSet.Protected)
|
||||||
files.Dereference(beatmapSet.Files.Select(f => f.FileInfo).ToArray());
|
files.Dereference(beatmapSet.Files.Select(f => f.FileInfo).ToArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Delete a beatmap difficulty.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="beatmap">The beatmap difficulty to hide.</param>
|
||||||
|
public void Hide(BeatmapInfo beatmap) => beatmaps.Hide(beatmap);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Restore a beatmap difficulty.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="beatmap">The beatmap difficulty to restore.</param>
|
||||||
|
public void Restore(BeatmapInfo beatmap) => beatmaps.Restore(beatmap);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns a <see cref="BeatmapSetInfo"/> to a usable state if it has previously been deleted but not yet purged.
|
/// Returns a <see cref="BeatmapSetInfo"/> to a usable state if it has previously been deleted but not yet purged.
|
||||||
/// Is a no-op for already usable beatmaps.
|
/// Is a no-op for already usable beatmaps.
|
||||||
@ -187,8 +209,7 @@ namespace osu.Game.Beatmaps
|
|||||||
/// <param name="beatmapSet">The beatmap to restore.</param>
|
/// <param name="beatmapSet">The beatmap to restore.</param>
|
||||||
public void Undelete(BeatmapSetInfo beatmapSet)
|
public void Undelete(BeatmapSetInfo beatmapSet)
|
||||||
{
|
{
|
||||||
lock (beatmaps)
|
if (!beatmaps.Undelete(beatmapSet)) return;
|
||||||
if (!beatmaps.Undelete(beatmapSet)) return;
|
|
||||||
|
|
||||||
if (!beatmapSet.Protected)
|
if (!beatmapSet.Protected)
|
||||||
files.Reference(beatmapSet.Files.Select(f => f.FileInfo).ToArray());
|
files.Reference(beatmapSet.Files.Select(f => f.FileInfo).ToArray());
|
||||||
@ -248,6 +269,13 @@ namespace osu.Game.Beatmaps
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Refresh an existing instance of a <see cref="BeatmapSetInfo"/> from the store.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="beatmapSet">A stale instance.</param>
|
||||||
|
/// <returns>A fresh instance.</returns>
|
||||||
|
public BeatmapSetInfo Refresh(BeatmapSetInfo beatmapSet) => QueryBeatmapSet(s => s.ID == beatmapSet.ID);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Perform a lookup query on available <see cref="BeatmapSetInfo"/>s.
|
/// Perform a lookup query on available <see cref="BeatmapSetInfo"/>s.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -255,7 +283,7 @@ namespace osu.Game.Beatmaps
|
|||||||
/// <returns>Results from the provided query.</returns>
|
/// <returns>Results from the provided query.</returns>
|
||||||
public List<BeatmapSetInfo> QueryBeatmapSets(Expression<Func<BeatmapSetInfo, bool>> query)
|
public List<BeatmapSetInfo> QueryBeatmapSets(Expression<Func<BeatmapSetInfo, bool>> query)
|
||||||
{
|
{
|
||||||
lock (beatmaps) return beatmaps.QueryAndPopulate(query);
|
return beatmaps.QueryAndPopulate(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -265,15 +293,12 @@ namespace osu.Game.Beatmaps
|
|||||||
/// <returns>The first result for the provided query, or null if no results were found.</returns>
|
/// <returns>The first result for the provided query, or null if no results were found.</returns>
|
||||||
public BeatmapInfo QueryBeatmap(Func<BeatmapInfo, bool> query)
|
public BeatmapInfo QueryBeatmap(Func<BeatmapInfo, bool> query)
|
||||||
{
|
{
|
||||||
lock (beatmaps)
|
BeatmapInfo set = beatmaps.Query<BeatmapInfo>().FirstOrDefault(query);
|
||||||
{
|
|
||||||
BeatmapInfo set = beatmaps.Query<BeatmapInfo>().FirstOrDefault(query);
|
|
||||||
|
|
||||||
if (set != null)
|
if (set != null)
|
||||||
beatmaps.Populate(set);
|
beatmaps.Populate(set);
|
||||||
|
|
||||||
return set;
|
return set;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -372,6 +397,7 @@ namespace osu.Game.Beatmaps
|
|||||||
|
|
||||||
beatmap.BeatmapInfo.Path = name;
|
beatmap.BeatmapInfo.Path = name;
|
||||||
beatmap.BeatmapInfo.Hash = ms.ComputeSHA2Hash();
|
beatmap.BeatmapInfo.Hash = ms.ComputeSHA2Hash();
|
||||||
|
beatmap.BeatmapInfo.MD5Hash = ms.ComputeMD5Hash();
|
||||||
|
|
||||||
// TODO: Diff beatmap metadata with set metadata and leave it here if necessary
|
// TODO: Diff beatmap metadata with set metadata and leave it here if necessary
|
||||||
beatmap.BeatmapInfo.Metadata = null;
|
beatmap.BeatmapInfo.Metadata = null;
|
||||||
|
@ -16,11 +16,14 @@ namespace osu.Game.Beatmaps
|
|||||||
public event Action<BeatmapSetInfo> BeatmapSetAdded;
|
public event Action<BeatmapSetInfo> BeatmapSetAdded;
|
||||||
public event Action<BeatmapSetInfo> BeatmapSetRemoved;
|
public event Action<BeatmapSetInfo> BeatmapSetRemoved;
|
||||||
|
|
||||||
|
public event Action<BeatmapInfo> BeatmapHidden;
|
||||||
|
public event Action<BeatmapInfo> BeatmapRestored;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The current version of this store. Used for migrations (see <see cref="PerformMigration(int, int)"/>).
|
/// The current version of this store. Used for migrations (see <see cref="PerformMigration(int, int)"/>).
|
||||||
/// The initial version is 1.
|
/// The initial version is 1.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected override int StoreVersion => 2;
|
protected override int StoreVersion => 4;
|
||||||
|
|
||||||
public BeatmapStore(SQLiteConnection connection)
|
public BeatmapStore(SQLiteConnection connection)
|
||||||
: base(connection)
|
: base(connection)
|
||||||
@ -77,6 +80,14 @@ namespace osu.Game.Beatmaps
|
|||||||
// cannot migrate; breaking underlying changes.
|
// cannot migrate; breaking underlying changes.
|
||||||
Reset();
|
Reset();
|
||||||
break;
|
break;
|
||||||
|
case 3:
|
||||||
|
// Added MD5Hash column to BeatmapInfo
|
||||||
|
Connection.MigrateTable<BeatmapInfo>();
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
// Added Hidden column to BeatmapInfo
|
||||||
|
Connection.MigrateTable<BeatmapInfo>();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -96,7 +107,7 @@ namespace osu.Game.Beatmaps
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Delete a <see cref="BeatmapSetInfo"/> to the database.
|
/// Delete a <see cref="BeatmapSetInfo"/> from the database.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="beatmapSet">The beatmap to delete.</param>
|
/// <param name="beatmapSet">The beatmap to delete.</param>
|
||||||
/// <returns>Whether the beatmap's <see cref="BeatmapSetInfo.DeletePending"/> was changed.</returns>
|
/// <returns>Whether the beatmap's <see cref="BeatmapSetInfo.DeletePending"/> was changed.</returns>
|
||||||
@ -127,6 +138,38 @@ namespace osu.Game.Beatmaps
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Hide a <see cref="BeatmapInfo"/> in the database.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="beatmap">The beatmap to hide.</param>
|
||||||
|
/// <returns>Whether the beatmap's <see cref="BeatmapInfo.Hidden"/> was changed.</returns>
|
||||||
|
public bool Hide(BeatmapInfo beatmap)
|
||||||
|
{
|
||||||
|
if (beatmap.Hidden) return false;
|
||||||
|
|
||||||
|
beatmap.Hidden = true;
|
||||||
|
Connection.Update(beatmap);
|
||||||
|
|
||||||
|
BeatmapHidden?.Invoke(beatmap);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Restore a previously hidden <see cref="BeatmapInfo"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="beatmap">The beatmap to restore.</param>
|
||||||
|
/// <returns>Whether the beatmap's <see cref="BeatmapInfo.Hidden"/> was changed.</returns>
|
||||||
|
public bool Restore(BeatmapInfo beatmap)
|
||||||
|
{
|
||||||
|
if (!beatmap.Hidden) return false;
|
||||||
|
|
||||||
|
beatmap.Hidden = false;
|
||||||
|
Connection.Update(beatmap);
|
||||||
|
|
||||||
|
BeatmapRestored?.Invoke(beatmap);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
private void cleanupPendingDeletions()
|
private void cleanupPendingDeletions()
|
||||||
{
|
{
|
||||||
Connection.RunInTransaction(() =>
|
Connection.RunInTransaction(() =>
|
||||||
|
@ -10,4 +10,4 @@ namespace osu.Game.Beatmaps.ControlPoints
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public double SpeedMultiplier = 1;
|
public double SpeedMultiplier = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,11 +30,15 @@ namespace osu.Game.Beatmaps
|
|||||||
|
|
||||||
public abstract class DifficultyCalculator<T> : DifficultyCalculator where T : HitObject
|
public abstract class DifficultyCalculator<T> : DifficultyCalculator where T : HitObject
|
||||||
{
|
{
|
||||||
|
protected readonly Beatmap Beatmap;
|
||||||
|
|
||||||
protected List<T> Objects;
|
protected List<T> Objects;
|
||||||
|
|
||||||
protected DifficultyCalculator(Beatmap beatmap)
|
protected DifficultyCalculator(Beatmap beatmap)
|
||||||
{
|
{
|
||||||
Objects = CreateBeatmapConverter().Convert(beatmap, true).HitObjects;
|
Beatmap = beatmap;
|
||||||
|
|
||||||
|
Objects = CreateBeatmapConverter().Convert(beatmap).HitObjects;
|
||||||
|
|
||||||
foreach (var h in Objects)
|
foreach (var h in Objects)
|
||||||
h.ApplyDefaults(beatmap.ControlPointInfo, beatmap.BeatmapInfo.Difficulty);
|
h.ApplyDefaults(beatmap.ControlPointInfo, beatmap.BeatmapInfo.Difficulty);
|
||||||
|
@ -11,6 +11,8 @@ namespace osu.Game.Beatmaps.Drawables
|
|||||||
{
|
{
|
||||||
public class BeatmapGroup : IStateful<BeatmapGroupState>
|
public class BeatmapGroup : IStateful<BeatmapGroupState>
|
||||||
{
|
{
|
||||||
|
public event Action<BeatmapGroupState> StateChanged;
|
||||||
|
|
||||||
public BeatmapPanel SelectedPanel;
|
public BeatmapPanel SelectedPanel;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -23,19 +25,26 @@ namespace osu.Game.Beatmaps.Drawables
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public Action<BeatmapInfo> StartRequested;
|
public Action<BeatmapInfo> StartRequested;
|
||||||
|
|
||||||
public BeatmapSetHeader Header;
|
public Action<BeatmapSetInfo> DeleteRequested;
|
||||||
|
|
||||||
private BeatmapGroupState state;
|
public Action<BeatmapSetInfo> RestoreHiddenRequested;
|
||||||
|
|
||||||
|
public Action<BeatmapInfo> HideDifficultyRequested;
|
||||||
|
|
||||||
|
public BeatmapSetHeader Header;
|
||||||
|
|
||||||
public List<BeatmapPanel> BeatmapPanels;
|
public List<BeatmapPanel> BeatmapPanels;
|
||||||
|
|
||||||
public BeatmapSetInfo BeatmapSet;
|
public BeatmapSetInfo BeatmapSet;
|
||||||
|
|
||||||
|
private BeatmapGroupState state;
|
||||||
public BeatmapGroupState State
|
public BeatmapGroupState State
|
||||||
{
|
{
|
||||||
get { return state; }
|
get { return state; }
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
|
state = value;
|
||||||
|
|
||||||
switch (value)
|
switch (value)
|
||||||
{
|
{
|
||||||
case BeatmapGroupState.Expanded:
|
case BeatmapGroupState.Expanded:
|
||||||
@ -54,7 +63,8 @@ namespace osu.Game.Beatmaps.Drawables
|
|||||||
panel.State = PanelSelectedState.Hidden;
|
panel.State = PanelSelectedState.Hidden;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
state = value;
|
|
||||||
|
StateChanged?.Invoke(state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,14 +76,17 @@ namespace osu.Game.Beatmaps.Drawables
|
|||||||
Header = new BeatmapSetHeader(beatmap)
|
Header = new BeatmapSetHeader(beatmap)
|
||||||
{
|
{
|
||||||
GainedSelection = headerGainedSelection,
|
GainedSelection = headerGainedSelection,
|
||||||
|
DeleteRequested = b => DeleteRequested(b),
|
||||||
|
RestoreHiddenRequested = b => RestoreHiddenRequested(b),
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
};
|
};
|
||||||
|
|
||||||
BeatmapSet.Beatmaps = BeatmapSet.Beatmaps.OrderBy(b => b.StarDifficulty).ToList();
|
BeatmapSet.Beatmaps = BeatmapSet.Beatmaps.Where(b => !b.Hidden).OrderBy(b => b.StarDifficulty).ToList();
|
||||||
BeatmapPanels = BeatmapSet.Beatmaps.Select(b => new BeatmapPanel(b)
|
BeatmapPanels = BeatmapSet.Beatmaps.Select(b => new BeatmapPanel(b)
|
||||||
{
|
{
|
||||||
Alpha = 0,
|
Alpha = 0,
|
||||||
GainedSelection = panelGainedSelection,
|
GainedSelection = panelGainedSelection,
|
||||||
|
HideRequested = p => HideDifficultyRequested?.Invoke(p),
|
||||||
StartRequested = p => { StartRequested?.Invoke(p.Beatmap); },
|
StartRequested = p => { StartRequested?.Invoke(p.Beatmap); },
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
}).ToList();
|
}).ToList();
|
||||||
@ -81,6 +94,7 @@ namespace osu.Game.Beatmaps.Drawables
|
|||||||
Header.AddDifficultyIcons(BeatmapPanels);
|
Header.AddDifficultyIcons(BeatmapPanels);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void headerGainedSelection(BeatmapSetHeader panel)
|
private void headerGainedSelection(BeatmapSetHeader panel)
|
||||||
{
|
{
|
||||||
State = BeatmapGroupState.Expanded;
|
State = BeatmapGroupState.Expanded;
|
||||||
|
@ -5,6 +5,7 @@ using System;
|
|||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Colour;
|
using osu.Framework.Graphics.Colour;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Cursor;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Graphics.Backgrounds;
|
using osu.Game.Graphics.Backgrounds;
|
||||||
@ -14,16 +15,20 @@ using OpenTK.Graphics;
|
|||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Framework.Graphics.UserInterface;
|
||||||
|
|
||||||
namespace osu.Game.Beatmaps.Drawables
|
namespace osu.Game.Beatmaps.Drawables
|
||||||
{
|
{
|
||||||
public class BeatmapPanel : Panel
|
public class BeatmapPanel : Panel, IHasContextMenu
|
||||||
{
|
{
|
||||||
public BeatmapInfo Beatmap;
|
public BeatmapInfo Beatmap;
|
||||||
private readonly Sprite background;
|
private readonly Sprite background;
|
||||||
|
|
||||||
public Action<BeatmapPanel> GainedSelection;
|
public Action<BeatmapPanel> GainedSelection;
|
||||||
public Action<BeatmapPanel> StartRequested;
|
public Action<BeatmapPanel> StartRequested;
|
||||||
|
public Action<BeatmapPanel> EditRequested;
|
||||||
|
public Action<BeatmapInfo> HideRequested;
|
||||||
|
|
||||||
private readonly Triangles triangles;
|
private readonly Triangles triangles;
|
||||||
private readonly StarCounter starCounter;
|
private readonly StarCounter starCounter;
|
||||||
|
|
||||||
@ -148,5 +153,12 @@ namespace osu.Game.Beatmaps.Drawables
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public MenuItem[] ContextMenuItems => new MenuItem[]
|
||||||
|
{
|
||||||
|
new OsuMenuItem("Play", MenuItemType.Highlighted, () => StartRequested?.Invoke(this)),
|
||||||
|
new OsuMenuItem("Edit", MenuItemType.Standard, () => EditRequested?.Invoke(this)),
|
||||||
|
new OsuMenuItem("Hide", MenuItemType.Destructive, () => HideRequested?.Invoke(Beatmap)),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,22 +3,31 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Colour;
|
using osu.Framework.Graphics.Colour;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Cursor;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Localisation;
|
using osu.Framework.Localisation;
|
||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Framework.Graphics.UserInterface;
|
||||||
|
using osu.Game.Graphics.UserInterface;
|
||||||
|
|
||||||
namespace osu.Game.Beatmaps.Drawables
|
namespace osu.Game.Beatmaps.Drawables
|
||||||
{
|
{
|
||||||
public class BeatmapSetHeader : Panel
|
public class BeatmapSetHeader : Panel, IHasContextMenu
|
||||||
{
|
{
|
||||||
public Action<BeatmapSetHeader> GainedSelection;
|
public Action<BeatmapSetHeader> GainedSelection;
|
||||||
|
|
||||||
|
public Action<BeatmapSetInfo> DeleteRequested;
|
||||||
|
|
||||||
|
public Action<BeatmapSetInfo> RestoreHiddenRequested;
|
||||||
|
|
||||||
private readonly SpriteText title;
|
private readonly SpriteText title;
|
||||||
private readonly SpriteText artist;
|
private readonly SpriteText artist;
|
||||||
|
|
||||||
@ -148,5 +157,23 @@ namespace osu.Game.Beatmaps.Drawables
|
|||||||
foreach (var p in panels)
|
foreach (var p in panels)
|
||||||
difficultyIcons.Add(new DifficultyIcon(p.Beatmap));
|
difficultyIcons.Add(new DifficultyIcon(p.Beatmap));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public MenuItem[] ContextMenuItems
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
List<MenuItem> items = new List<MenuItem>();
|
||||||
|
|
||||||
|
if (State == PanelSelectedState.NotSelected)
|
||||||
|
items.Add(new OsuMenuItem("Expand", MenuItemType.Highlighted, () => State = PanelSelectedState.Selected));
|
||||||
|
|
||||||
|
if (beatmap.BeatmapSetInfo.Beatmaps.Any(b => b.Hidden))
|
||||||
|
items.Add(new OsuMenuItem("Restore all hidden", MenuItemType.Standard, () => RestoreHiddenRequested?.Invoke(beatmap.BeatmapSetInfo)));
|
||||||
|
|
||||||
|
items.Add(new OsuMenuItem("Delete", MenuItemType.Destructive, () => DeleteRequested?.Invoke(beatmap.BeatmapSetInfo)));
|
||||||
|
|
||||||
|
return items.ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -33,7 +33,8 @@ namespace osu.Game.Beatmaps.Drawables
|
|||||||
Normal,
|
Normal,
|
||||||
Hard,
|
Hard,
|
||||||
Insane,
|
Insane,
|
||||||
Expert
|
Expert,
|
||||||
|
ExpertPlus
|
||||||
}
|
}
|
||||||
|
|
||||||
private DifficultyRating getDifficultyRating(BeatmapInfo beatmap)
|
private DifficultyRating getDifficultyRating(BeatmapInfo beatmap)
|
||||||
@ -44,7 +45,8 @@ namespace osu.Game.Beatmaps.Drawables
|
|||||||
if (rating < 2.25) return DifficultyRating.Normal;
|
if (rating < 2.25) return DifficultyRating.Normal;
|
||||||
if (rating < 3.75) return DifficultyRating.Hard;
|
if (rating < 3.75) return DifficultyRating.Hard;
|
||||||
if (rating < 5.25) return DifficultyRating.Insane;
|
if (rating < 5.25) return DifficultyRating.Insane;
|
||||||
return DifficultyRating.Expert;
|
if (rating < 6.75) return DifficultyRating.Expert;
|
||||||
|
return DifficultyRating.ExpertPlus;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Color4 getColour(BeatmapInfo beatmap)
|
private Color4 getColour(BeatmapInfo beatmap)
|
||||||
@ -55,12 +57,14 @@ namespace osu.Game.Beatmaps.Drawables
|
|||||||
return palette.Green;
|
return palette.Green;
|
||||||
default:
|
default:
|
||||||
case DifficultyRating.Normal:
|
case DifficultyRating.Normal:
|
||||||
return palette.Yellow;
|
return palette.Blue;
|
||||||
case DifficultyRating.Hard:
|
case DifficultyRating.Hard:
|
||||||
return palette.Pink;
|
return palette.Yellow;
|
||||||
case DifficultyRating.Insane:
|
case DifficultyRating.Insane:
|
||||||
return palette.Purple;
|
return palette.Pink;
|
||||||
case DifficultyRating.Expert:
|
case DifficultyRating.Expert:
|
||||||
|
return palette.Purple;
|
||||||
|
case DifficultyRating.ExpertPlus:
|
||||||
return palette.Gray0;
|
return palette.Gray0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 osu.Framework;
|
using osu.Framework;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
@ -15,6 +16,8 @@ namespace osu.Game.Beatmaps.Drawables
|
|||||||
{
|
{
|
||||||
public const float MAX_HEIGHT = 80;
|
public const float MAX_HEIGHT = 80;
|
||||||
|
|
||||||
|
public event Action<PanelSelectedState> StateChanged;
|
||||||
|
|
||||||
public override bool RemoveWhenNotAlive => false;
|
public override bool RemoveWhenNotAlive => false;
|
||||||
|
|
||||||
private readonly Container nestedContainer;
|
private readonly Container nestedContainer;
|
||||||
@ -77,11 +80,15 @@ namespace osu.Game.Beatmaps.Drawables
|
|||||||
|
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (state == value) return;
|
if (state == value)
|
||||||
|
return;
|
||||||
|
|
||||||
var last = state;
|
var last = state;
|
||||||
state = value;
|
state = value;
|
||||||
|
|
||||||
ApplyState(last);
|
ApplyState(last);
|
||||||
|
|
||||||
|
StateChanged?.Invoke(State);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
{
|
{
|
||||||
@ -74,8 +73,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)
|
||||||
|
@ -70,6 +70,8 @@ namespace osu.Game.Configuration
|
|||||||
|
|
||||||
// Update
|
// Update
|
||||||
Set(OsuSetting.ReleaseStream, ReleaseStream.Lazer);
|
Set(OsuSetting.ReleaseStream, ReleaseStream.Lazer);
|
||||||
|
|
||||||
|
Set(OsuSetting.Version, string.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
public OsuConfigManager(Storage storage) : base(storage)
|
public OsuConfigManager(Storage storage) : base(storage)
|
||||||
@ -106,6 +108,7 @@ namespace osu.Game.Configuration
|
|||||||
SnakingInSliders,
|
SnakingInSliders,
|
||||||
SnakingOutSliders,
|
SnakingOutSliders,
|
||||||
ShowFpsDisplay,
|
ShowFpsDisplay,
|
||||||
ChatDisplayHeight
|
ChatDisplayHeight,
|
||||||
|
Version
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,12 +19,12 @@ namespace osu.Game.Graphics.Containers
|
|||||||
samplePopIn = audio.Sample.Get(@"UI/melodic-5");
|
samplePopIn = audio.Sample.Get(@"UI/melodic-5");
|
||||||
samplePopOut = audio.Sample.Get(@"UI/melodic-4");
|
samplePopOut = audio.Sample.Get(@"UI/melodic-4");
|
||||||
|
|
||||||
StateChanged += OsuFocusedOverlayContainer_StateChanged;
|
StateChanged += onStateChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OsuFocusedOverlayContainer_StateChanged(VisibilityContainer arg1, Visibility arg2)
|
private void onStateChanged(Visibility visibility)
|
||||||
{
|
{
|
||||||
switch (arg2)
|
switch (visibility)
|
||||||
{
|
{
|
||||||
case Visibility.Visible:
|
case Visibility.Visible:
|
||||||
samplePopIn?.Play();
|
samplePopIn?.Play();
|
||||||
|
@ -11,6 +11,7 @@ using osu.Framework.Graphics.Sprites;
|
|||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
|
|
||||||
namespace osu.Game.Graphics.Cursor
|
namespace osu.Game.Graphics.Cursor
|
||||||
@ -21,20 +22,31 @@ namespace osu.Game.Graphics.Cursor
|
|||||||
|
|
||||||
private bool dragging;
|
private bool dragging;
|
||||||
|
|
||||||
|
private bool startRotation;
|
||||||
|
|
||||||
protected override bool OnMouseMove(InputState state)
|
protected override bool OnMouseMove(InputState state)
|
||||||
{
|
{
|
||||||
if (dragging)
|
if (dragging)
|
||||||
{
|
{
|
||||||
Vector2 offset = state.Mouse.Position - state.Mouse.PositionMouseDown ?? state.Mouse.Delta;
|
Debug.Assert(state.Mouse.PositionMouseDown != null);
|
||||||
float degrees = (float)MathHelper.RadiansToDegrees(Math.Atan2(-offset.X, offset.Y)) + 24.3f;
|
|
||||||
|
|
||||||
// Always rotate in the direction of least distance
|
// don't start rotating until we're moved a minimum distance away from the mouse down location,
|
||||||
float diff = (degrees - ActiveCursor.Rotation) % 360;
|
// else it can have an annoying effect.
|
||||||
if (diff < -180) diff += 360;
|
startRotation |= Vector2.Distance(state.Mouse.Position, state.Mouse.PositionMouseDown.Value) > 30;
|
||||||
if (diff > 180) diff -= 360;
|
|
||||||
degrees = ActiveCursor.Rotation + diff;
|
|
||||||
|
|
||||||
ActiveCursor.RotateTo(degrees, 600, Easing.OutQuint);
|
if (startRotation)
|
||||||
|
{
|
||||||
|
Vector2 offset = state.Mouse.Position - state.Mouse.PositionMouseDown.Value;
|
||||||
|
float degrees = (float)MathHelper.RadiansToDegrees(Math.Atan2(-offset.X, offset.Y)) + 24.3f;
|
||||||
|
|
||||||
|
// Always rotate in the direction of least distance
|
||||||
|
float diff = (degrees - ActiveCursor.Rotation) % 360;
|
||||||
|
if (diff < -180) diff += 360;
|
||||||
|
if (diff > 180) diff -= 360;
|
||||||
|
degrees = ActiveCursor.Rotation + diff;
|
||||||
|
|
||||||
|
ActiveCursor.RotateTo(degrees, 600, Easing.OutQuint);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return base.OnMouseMove(state);
|
return base.OnMouseMove(state);
|
||||||
@ -61,6 +73,7 @@ namespace osu.Game.Graphics.Cursor
|
|||||||
if (!state.Mouse.HasMainButtonPressed)
|
if (!state.Mouse.HasMainButtonPressed)
|
||||||
{
|
{
|
||||||
dragging = false;
|
dragging = false;
|
||||||
|
startRotation = false;
|
||||||
|
|
||||||
((Cursor)ActiveCursor).AdditiveLayer.FadeOut(500, Easing.OutQuint);
|
((Cursor)ActiveCursor).AdditiveLayer.FadeOut(500, Easing.OutQuint);
|
||||||
ActiveCursor.RotateTo(0, 600 * (1 + Math.Abs(ActiveCursor.Rotation / 720)), Easing.OutElasticHalf);
|
ActiveCursor.RotateTo(0, 600 * (1 + Math.Abs(ActiveCursor.Rotation / 720)), Easing.OutElasticHalf);
|
||||||
|
@ -9,6 +9,6 @@ namespace osu.Game.Graphics.Cursor
|
|||||||
{
|
{
|
||||||
public class OsuContextMenuContainer : ContextMenuContainer
|
public class OsuContextMenuContainer : ContextMenuContainer
|
||||||
{
|
{
|
||||||
protected override ContextMenu<ContextMenuItem> CreateContextMenu() => new OsuContextMenu<ContextMenuItem>();
|
protected override Menu CreateMenu() => new OsuContextMenu();
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -44,19 +44,31 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
{
|
{
|
||||||
List<Bar> bars = Children.ToList();
|
List<Bar> bars = Children.ToList();
|
||||||
foreach (var bar in value.Select((length, index) => new { Value = length, Bar = bars.Count > index ? bars[index] : null }))
|
foreach (var bar in value.Select((length, index) => new { Value = length, Bar = bars.Count > index ? bars[index] : null }))
|
||||||
|
{
|
||||||
|
float length = MaxValue ?? value.Max();
|
||||||
|
if (length != 0)
|
||||||
|
length = bar.Value / length;
|
||||||
|
|
||||||
|
float size = value.Count();
|
||||||
|
if (size != 0)
|
||||||
|
size = 1.0f / size;
|
||||||
|
|
||||||
if (bar.Bar != null)
|
if (bar.Bar != null)
|
||||||
{
|
{
|
||||||
bar.Bar.Length = bar.Value / (MaxValue ?? value.Max());
|
bar.Bar.Length = length;
|
||||||
bar.Bar.Size = (direction & BarDirection.Horizontal) > 0 ? new Vector2(1, 1.0f / value.Count()) : new Vector2(1.0f / value.Count(), 1);
|
bar.Bar.Size = (direction & BarDirection.Horizontal) > 0 ? new Vector2(1, size) : new Vector2(size, 1);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
Add(new Bar
|
Add(new Bar
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Size = (direction & BarDirection.Horizontal) > 0 ? new Vector2(1, 1.0f / value.Count()) : new Vector2(1.0f / value.Count(), 1),
|
Size = (direction & BarDirection.Horizontal) > 0 ? new Vector2(1, size) : new Vector2(size, 1),
|
||||||
Length = bar.Value / (MaxValue ?? value.Max()),
|
Length = length,
|
||||||
Direction = Direction,
|
Direction = Direction,
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
//I'm using ToList() here because Where() returns an Enumerable which can change it's elements afterwards
|
//I'm using ToList() here because Where() returns an Enumerable which can change it's elements afterwards
|
||||||
RemoveRange(Children.Where((bar, index) => index >= value.Count()).ToList());
|
RemoveRange(Children.Where((bar, index) => index >= value.Count()).ToList());
|
||||||
}
|
}
|
||||||
|
@ -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 OpenTK;
|
using OpenTK;
|
||||||
using osu.Framework;
|
using osu.Framework;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
@ -35,6 +36,8 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
|
|
||||||
private class BreadcrumbTabItem : OsuTabItem, IStateful<Visibility>
|
private class BreadcrumbTabItem : OsuTabItem, IStateful<Visibility>
|
||||||
{
|
{
|
||||||
|
public event Action<Visibility> StateChanged;
|
||||||
|
|
||||||
public readonly SpriteIcon Chevron;
|
public readonly SpriteIcon Chevron;
|
||||||
|
|
||||||
//don't allow clicking between transitions and don't make the chevron clickable
|
//don't allow clicking between transitions and don't make the chevron clickable
|
||||||
@ -42,6 +45,7 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
public override bool HandleInput => State == Visibility.Visible;
|
public override bool HandleInput => State == Visibility.Visible;
|
||||||
|
|
||||||
private Visibility state;
|
private Visibility state;
|
||||||
|
|
||||||
public Visibility State
|
public Visibility State
|
||||||
{
|
{
|
||||||
get { return state; }
|
get { return state; }
|
||||||
@ -62,6 +66,8 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
this.FadeOut(transition_duration, Easing.OutQuint);
|
this.FadeOut(transition_duration, Easing.OutQuint);
|
||||||
this.ScaleTo(new Vector2(0.8f, 1f), transition_duration, Easing.OutQuint);
|
this.ScaleTo(new Vector2(0.8f, 1f), transition_duration, Easing.OutQuint);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StateChanged?.Invoke(State);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,6 +24,8 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
private SampleChannel sampleClick;
|
private SampleChannel sampleClick;
|
||||||
private SampleChannel sampleHover;
|
private SampleChannel sampleHover;
|
||||||
|
|
||||||
|
protected Triangles Triangles;
|
||||||
|
|
||||||
public OsuButton()
|
public OsuButton()
|
||||||
{
|
{
|
||||||
Height = 40;
|
Height = 40;
|
||||||
@ -52,7 +54,7 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
|
|
||||||
AddRange(new Drawable[]
|
AddRange(new Drawable[]
|
||||||
{
|
{
|
||||||
new Triangles
|
Triangles = new Triangles
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
ColourDark = colours.BlueDarker,
|
ColourDark = colours.BlueDarker,
|
||||||
@ -120,4 +122,4 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,52 +1,39 @@
|
|||||||
// 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;
|
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Extensions.Color4Extensions;
|
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.Framework.Graphics.UserInterface;
|
|
||||||
|
|
||||||
namespace osu.Game.Graphics.UserInterface
|
namespace osu.Game.Graphics.UserInterface
|
||||||
{
|
{
|
||||||
public class OsuContextMenu<TItem> : ContextMenu<TItem>
|
public class OsuContextMenu : OsuMenu
|
||||||
where TItem : ContextMenuItem
|
|
||||||
{
|
{
|
||||||
protected override Menu<TItem> CreateMenu() => new CustomMenu();
|
private const int fade_duration = 250;
|
||||||
|
|
||||||
public class CustomMenu : Menu<TItem>
|
public OsuContextMenu()
|
||||||
|
: base(Direction.Vertical)
|
||||||
{
|
{
|
||||||
private const int fade_duration = 250;
|
MaskingContainer.CornerRadius = 5;
|
||||||
|
MaskingContainer.EdgeEffect = new EdgeEffectParameters
|
||||||
public CustomMenu()
|
|
||||||
{
|
{
|
||||||
CornerRadius = 5;
|
Type = EdgeEffectType.Shadow,
|
||||||
ItemsContainer.Padding = new MarginPadding { Vertical = OsuContextMenuItem.MARGIN_VERTICAL };
|
Colour = Color4.Black.Opacity(0.1f),
|
||||||
Masking = true;
|
Radius = 4,
|
||||||
EdgeEffect = new EdgeEffectParameters
|
};
|
||||||
{
|
|
||||||
Type = EdgeEffectType.Shadow,
|
|
||||||
Colour = Color4.Black.Opacity(0.1f),
|
|
||||||
Radius = 4,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
ItemsContainer.Padding = new MarginPadding { Vertical = DrawableOsuMenuItem.MARGIN_VERTICAL };
|
||||||
private void load(OsuColour colours)
|
|
||||||
{
|
|
||||||
Background.Colour = colours.ContextMenuGray;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void AnimateOpen() => this.FadeIn(fade_duration, Easing.OutQuint);
|
|
||||||
protected override void AnimateClose() => this.FadeOut(fade_duration, Easing.OutQuint);
|
|
||||||
|
|
||||||
protected override void UpdateContentHeight()
|
|
||||||
{
|
|
||||||
var actualHeight = (RelativeSizeAxes & Axes.Y) > 0 ? 1 : ContentHeight;
|
|
||||||
this.ResizeTo(new Vector2(1, State == MenuState.Opened ? actualHeight : 0), 300, Easing.OutQuint);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuColour colours)
|
||||||
|
{
|
||||||
|
BackgroundColour = colours.ContextMenuGray;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void AnimateOpen() => this.FadeIn(fade_duration, Easing.OutQuint);
|
||||||
|
protected override void AnimateClose() => this.FadeOut(fade_duration, Easing.OutQuint);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,114 +0,0 @@
|
|||||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
|
||||||
|
|
||||||
using OpenTK.Graphics;
|
|
||||||
using osu.Framework.Allocation;
|
|
||||||
using osu.Framework.Audio;
|
|
||||||
using osu.Framework.Audio.Sample;
|
|
||||||
using osu.Framework.Graphics;
|
|
||||||
using osu.Framework.Graphics.Containers;
|
|
||||||
using osu.Framework.Graphics.UserInterface;
|
|
||||||
using osu.Framework.Input;
|
|
||||||
using osu.Game.Graphics.Sprites;
|
|
||||||
|
|
||||||
namespace osu.Game.Graphics.UserInterface
|
|
||||||
{
|
|
||||||
public class OsuContextMenuItem : ContextMenuItem
|
|
||||||
{
|
|
||||||
private const int transition_length = 80;
|
|
||||||
private const int margin_horizontal = 17;
|
|
||||||
public const int MARGIN_VERTICAL = 4;
|
|
||||||
private const int text_size = 17;
|
|
||||||
|
|
||||||
private OsuSpriteText text;
|
|
||||||
private OsuSpriteText textBold;
|
|
||||||
|
|
||||||
private SampleChannel sampleClick;
|
|
||||||
private SampleChannel sampleHover;
|
|
||||||
|
|
||||||
private readonly MenuItemType type;
|
|
||||||
|
|
||||||
protected override Container CreateTextContainer(string title) => new Container
|
|
||||||
{
|
|
||||||
AutoSizeAxes = Axes.Both,
|
|
||||||
Anchor = Anchor.CentreLeft,
|
|
||||||
Origin = Anchor.CentreLeft,
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
text = new OsuSpriteText
|
|
||||||
{
|
|
||||||
Anchor = Anchor.CentreLeft,
|
|
||||||
Origin = Anchor.CentreLeft,
|
|
||||||
TextSize = text_size,
|
|
||||||
Text = title,
|
|
||||||
Margin = new MarginPadding { Horizontal = margin_horizontal, Vertical = MARGIN_VERTICAL },
|
|
||||||
},
|
|
||||||
textBold = new OsuSpriteText
|
|
||||||
{
|
|
||||||
AlwaysPresent = true,
|
|
||||||
Alpha = 0,
|
|
||||||
Anchor = Anchor.CentreLeft,
|
|
||||||
Origin = Anchor.CentreLeft,
|
|
||||||
TextSize = text_size,
|
|
||||||
Text = title,
|
|
||||||
Font = @"Exo2.0-Bold",
|
|
||||||
Margin = new MarginPadding { Horizontal = margin_horizontal, Vertical = MARGIN_VERTICAL },
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
public OsuContextMenuItem(string title, MenuItemType type = MenuItemType.Standard) : base(title)
|
|
||||||
{
|
|
||||||
this.type = type;
|
|
||||||
}
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
|
||||||
private void load(AudioManager audio)
|
|
||||||
{
|
|
||||||
sampleHover = audio.Sample.Get(@"UI/generic-hover");
|
|
||||||
sampleClick = audio.Sample.Get(@"UI/generic-click");
|
|
||||||
|
|
||||||
BackgroundColour = Color4.Transparent;
|
|
||||||
BackgroundColourHover = OsuColour.FromHex(@"172023");
|
|
||||||
|
|
||||||
updateTextColour();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateTextColour()
|
|
||||||
{
|
|
||||||
switch (type)
|
|
||||||
{
|
|
||||||
case MenuItemType.Standard:
|
|
||||||
textBold.Colour = text.Colour = Color4.White;
|
|
||||||
break;
|
|
||||||
case MenuItemType.Destructive:
|
|
||||||
textBold.Colour = text.Colour = Color4.Red;
|
|
||||||
break;
|
|
||||||
case MenuItemType.Highlighted:
|
|
||||||
textBold.Colour = text.Colour = OsuColour.FromHex(@"ffcc22");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override bool OnHover(InputState state)
|
|
||||||
{
|
|
||||||
sampleHover.Play();
|
|
||||||
textBold.FadeIn(transition_length, Easing.OutQuint);
|
|
||||||
text.FadeOut(transition_length, Easing.OutQuint);
|
|
||||||
return base.OnHover(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnHoverLost(InputState state)
|
|
||||||
{
|
|
||||||
textBold.FadeOut(transition_length, Easing.OutQuint);
|
|
||||||
text.FadeIn(transition_length, Easing.OutQuint);
|
|
||||||
base.OnHoverLost(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override bool OnClick(InputState state)
|
|
||||||
{
|
|
||||||
sampleClick.Play();
|
|
||||||
return base.OnClick(state);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -14,107 +14,185 @@ using OpenTK;
|
|||||||
|
|
||||||
namespace osu.Game.Graphics.UserInterface
|
namespace osu.Game.Graphics.UserInterface
|
||||||
{
|
{
|
||||||
public class OsuDropdown<T> : Dropdown<T>
|
public class OsuDropdown<T> : Dropdown<T>, IHasAccentColour
|
||||||
{
|
{
|
||||||
protected override DropdownHeader CreateHeader() => new OsuDropdownHeader { AccentColour = AccentColour };
|
private Color4 accentColour;
|
||||||
|
public Color4 AccentColour
|
||||||
protected override Menu CreateMenu() => new OsuMenu();
|
|
||||||
|
|
||||||
private Color4? accentColour;
|
|
||||||
public virtual Color4 AccentColour
|
|
||||||
{
|
{
|
||||||
get { return accentColour.GetValueOrDefault(); }
|
get { return accentColour; }
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
accentColour = value;
|
accentColour = value;
|
||||||
if (Header != null)
|
updateAccentColour();
|
||||||
((OsuDropdownHeader)Header).AccentColour = value;
|
|
||||||
foreach (var item in MenuItems.OfType<OsuDropdownMenuItem>())
|
|
||||||
item.AccentColour = value;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuColour colours)
|
private void load(OsuColour colours)
|
||||||
{
|
{
|
||||||
if (accentColour == null)
|
if (accentColour == default(Color4))
|
||||||
AccentColour = colours.PinkDarker;
|
accentColour = colours.PinkDarker;
|
||||||
|
updateAccentColour();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override DropdownMenuItem<T> CreateMenuItem(string text, T value) => new OsuDropdownMenuItem(text, value) { AccentColour = AccentColour };
|
private void updateAccentColour()
|
||||||
|
|
||||||
public class OsuDropdownMenuItem : DropdownMenuItem<T>
|
|
||||||
{
|
{
|
||||||
public OsuDropdownMenuItem(string text, T current) : base(text, current)
|
var header = Header as IHasAccentColour;
|
||||||
|
if (header != null) header.AccentColour = accentColour;
|
||||||
|
|
||||||
|
var menu = Menu as IHasAccentColour;
|
||||||
|
if (menu != null) menu.AccentColour = accentColour;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override DropdownHeader CreateHeader() => new OsuDropdownHeader();
|
||||||
|
|
||||||
|
protected override DropdownMenu CreateMenu() => new OsuDropdownMenu();
|
||||||
|
|
||||||
|
#region OsuDropdownMenu
|
||||||
|
protected class OsuDropdownMenu : DropdownMenu, IHasAccentColour
|
||||||
|
{
|
||||||
|
// todo: this uses the same styling as OsuMenu. hopefully we can just use OsuMenu in the future with some refactoring
|
||||||
|
public OsuDropdownMenu()
|
||||||
{
|
{
|
||||||
Foreground.Padding = new MarginPadding(2);
|
CornerRadius = 4;
|
||||||
|
BackgroundColour = Color4.Black.Opacity(0.5f);
|
||||||
|
|
||||||
Masking = true;
|
// todo: this uses the same styling as OsuMenu. hopefully we can just use OsuMenu in the future with some refactoring
|
||||||
CornerRadius = 6;
|
ItemsContainer.Padding = new MarginPadding(5);
|
||||||
|
}
|
||||||
|
|
||||||
Children = new[]
|
// todo: this uses the same styling as OsuMenu. hopefully we can just use OsuMenu in the future with some refactoring
|
||||||
|
protected override void AnimateOpen() => this.FadeIn(300, Easing.OutQuint);
|
||||||
|
protected override void AnimateClose() => this.FadeOut(300, Easing.OutQuint);
|
||||||
|
|
||||||
|
// todo: this uses the same styling as OsuMenu. hopefully we can just use OsuMenu in the future with some refactoring
|
||||||
|
protected override void UpdateSize(Vector2 newSize)
|
||||||
|
{
|
||||||
|
if (Direction == Direction.Vertical)
|
||||||
{
|
{
|
||||||
new FillFlowContainer
|
Width = newSize.X;
|
||||||
{
|
this.ResizeHeightTo(newSize.Y, 300, Easing.OutQuint);
|
||||||
Direction = FillDirection.Horizontal,
|
}
|
||||||
RelativeSizeAxes = Axes.X,
|
else
|
||||||
AutoSizeAxes = Axes.Y,
|
{
|
||||||
Children = new Drawable[]
|
Height = newSize.Y;
|
||||||
{
|
this.ResizeWidthTo(newSize.X, 300, Easing.OutQuint);
|
||||||
Chevron = new SpriteIcon
|
|
||||||
{
|
|
||||||
AlwaysPresent = true,
|
|
||||||
Icon = FontAwesome.fa_chevron_right,
|
|
||||||
Colour = Color4.Black,
|
|
||||||
Alpha = 0.5f,
|
|
||||||
Size = new Vector2(8),
|
|
||||||
Margin = new MarginPadding { Left = 3, Right = 3 },
|
|
||||||
Origin = Anchor.CentreLeft,
|
|
||||||
Anchor = Anchor.CentreLeft,
|
|
||||||
},
|
|
||||||
Label = new OsuSpriteText {
|
|
||||||
Text = text,
|
|
||||||
Origin = Anchor.CentreLeft,
|
|
||||||
Anchor = Anchor.CentreLeft,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private Color4? accentColour;
|
|
||||||
|
|
||||||
protected readonly SpriteIcon Chevron;
|
|
||||||
protected readonly OsuSpriteText Label;
|
|
||||||
|
|
||||||
protected override void FormatForeground(bool hover = false)
|
|
||||||
{
|
|
||||||
base.FormatForeground(hover);
|
|
||||||
Chevron.Alpha = hover ? 1 : 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Color4 accentColour;
|
||||||
public Color4 AccentColour
|
public Color4 AccentColour
|
||||||
{
|
{
|
||||||
get { return accentColour.GetValueOrDefault(); }
|
get { return accentColour; }
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
accentColour = value;
|
accentColour = value;
|
||||||
BackgroundColourHover = BackgroundColourSelected = value;
|
foreach (var c in Children.OfType<IHasAccentColour>())
|
||||||
FormatBackground();
|
c.AccentColour = value;
|
||||||
FormatForeground();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
protected override DrawableMenuItem CreateDrawableMenuItem(MenuItem item) => new DrawableOsuDropdownMenuItem(item) { AccentColour = accentColour };
|
||||||
private void load(OsuColour colours)
|
|
||||||
{
|
|
||||||
BackgroundColour = Color4.Transparent;
|
|
||||||
BackgroundColourHover = accentColour ?? colours.PinkDarker;
|
|
||||||
BackgroundColourSelected = Color4.Black.Opacity(0.5f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class OsuDropdownHeader : DropdownHeader
|
#region DrawableOsuDropdownMenuItem
|
||||||
|
protected class DrawableOsuDropdownMenuItem : DrawableDropdownMenuItem, IHasAccentColour
|
||||||
|
{
|
||||||
|
private Color4? accentColour;
|
||||||
|
public Color4 AccentColour
|
||||||
|
{
|
||||||
|
get { return accentColour ?? nonAccentSelectedColour; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
accentColour = value;
|
||||||
|
updateColours();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateColours()
|
||||||
|
{
|
||||||
|
BackgroundColourHover = accentColour ?? nonAccentHoverColour;
|
||||||
|
BackgroundColourSelected = accentColour ?? nonAccentSelectedColour;
|
||||||
|
UpdateBackgroundColour();
|
||||||
|
UpdateForegroundColour();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Color4 nonAccentHoverColour;
|
||||||
|
private Color4 nonAccentSelectedColour;
|
||||||
|
|
||||||
|
public DrawableOsuDropdownMenuItem(MenuItem item)
|
||||||
|
: base(item)
|
||||||
|
{
|
||||||
|
Foreground.Padding = new MarginPadding(2);
|
||||||
|
|
||||||
|
Masking = true;
|
||||||
|
CornerRadius = 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuColour colours)
|
||||||
|
{
|
||||||
|
BackgroundColour = Color4.Transparent;
|
||||||
|
|
||||||
|
nonAccentHoverColour = colours.PinkDarker;
|
||||||
|
nonAccentSelectedColour = Color4.Black.Opacity(0.5f);
|
||||||
|
updateColours();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void UpdateForegroundColour()
|
||||||
|
{
|
||||||
|
base.UpdateForegroundColour();
|
||||||
|
|
||||||
|
var content = Foreground.Children.FirstOrDefault() as Content;
|
||||||
|
if (content != null) content.Chevron.Alpha = IsHovered ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Drawable CreateContent() => new Content();
|
||||||
|
|
||||||
|
protected new class Content : FillFlowContainer, IHasText
|
||||||
|
{
|
||||||
|
public string Text
|
||||||
|
{
|
||||||
|
get { return Label.Text; }
|
||||||
|
set { Label.Text = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public readonly OsuSpriteText Label;
|
||||||
|
public readonly SpriteIcon Chevron;
|
||||||
|
|
||||||
|
public Content()
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X;
|
||||||
|
AutoSizeAxes = Axes.Y;
|
||||||
|
Direction = FillDirection.Horizontal;
|
||||||
|
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
Chevron = new SpriteIcon
|
||||||
|
{
|
||||||
|
AlwaysPresent = true,
|
||||||
|
Icon = FontAwesome.fa_chevron_right,
|
||||||
|
Colour = Color4.Black,
|
||||||
|
Alpha = 0.5f,
|
||||||
|
Size = new Vector2(8),
|
||||||
|
Margin = new MarginPadding { Left = 3, Right = 3 },
|
||||||
|
Origin = Anchor.CentreLeft,
|
||||||
|
Anchor = Anchor.CentreLeft,
|
||||||
|
},
|
||||||
|
Label = new OsuSpriteText
|
||||||
|
{
|
||||||
|
Origin = Anchor.CentreLeft,
|
||||||
|
Anchor = Anchor.CentreLeft,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
public class OsuDropdownHeader : DropdownHeader, IHasAccentColour
|
||||||
{
|
{
|
||||||
protected readonly SpriteText Text;
|
protected readonly SpriteText Text;
|
||||||
protected override string Label
|
protected override string Label
|
||||||
@ -125,14 +203,14 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
|
|
||||||
protected readonly SpriteIcon Icon;
|
protected readonly SpriteIcon Icon;
|
||||||
|
|
||||||
private Color4? accentColour;
|
private Color4 accentColour;
|
||||||
public virtual Color4 AccentColour
|
public virtual Color4 AccentColour
|
||||||
{
|
{
|
||||||
get { return accentColour.GetValueOrDefault(); }
|
get { return accentColour; }
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
accentColour = value;
|
accentColour = value;
|
||||||
BackgroundColourHover = value;
|
BackgroundColourHover = accentColour;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -167,7 +245,7 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
private void load(OsuColour colours)
|
private void load(OsuColour colours)
|
||||||
{
|
{
|
||||||
BackgroundColour = Color4.Black.Opacity(0.5f);
|
BackgroundColour = Color4.Black.Opacity(0.5f);
|
||||||
BackgroundColourHover = accentColour ?? colours.PinkDarker;
|
BackgroundColourHover = colours.PinkDarker;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,32 +1,170 @@
|
|||||||
// 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;
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Audio;
|
||||||
|
using osu.Framework.Audio.Sample;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Graphics.UserInterface;
|
using osu.Framework.Graphics.UserInterface;
|
||||||
|
using osu.Framework.Input;
|
||||||
|
using osu.Game.Graphics.Sprites;
|
||||||
|
using OpenTK;
|
||||||
|
|
||||||
namespace osu.Game.Graphics.UserInterface
|
namespace osu.Game.Graphics.UserInterface
|
||||||
{
|
{
|
||||||
public class OsuMenu : Menu
|
public class OsuMenu : Menu
|
||||||
{
|
{
|
||||||
public OsuMenu()
|
public OsuMenu(Direction direction, bool topLevelMenu = false)
|
||||||
|
: base(direction, topLevelMenu)
|
||||||
{
|
{
|
||||||
CornerRadius = 4;
|
BackgroundColour = Color4.Black.Opacity(0.5f);
|
||||||
Background.Colour = Color4.Black.Opacity(0.5f);
|
|
||||||
|
|
||||||
|
MaskingContainer.CornerRadius = 4;
|
||||||
ItemsContainer.Padding = new MarginPadding(5);
|
ItemsContainer.Padding = new MarginPadding(5);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void AnimateOpen() => this.FadeIn(300, Easing.OutQuint);
|
protected override void AnimateOpen() => this.FadeIn(300, Easing.OutQuint);
|
||||||
|
|
||||||
protected override void AnimateClose() => this.FadeOut(300, Easing.OutQuint);
|
protected override void AnimateClose() => this.FadeOut(300, Easing.OutQuint);
|
||||||
|
|
||||||
protected override void UpdateContentHeight()
|
protected override void UpdateSize(Vector2 newSize)
|
||||||
{
|
{
|
||||||
var actualHeight = (RelativeSizeAxes & Axes.Y) > 0 ? 1 : ContentHeight;
|
if (Direction == Direction.Vertical)
|
||||||
this.ResizeTo(new Vector2(1, State == MenuState.Opened ? actualHeight : 0), 300, Easing.OutQuint);
|
{
|
||||||
|
Width = newSize.X;
|
||||||
|
this.ResizeHeightTo(newSize.Y, 300, Easing.OutQuint);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Height = newSize.Y;
|
||||||
|
this.ResizeWidthTo(newSize.X, 300, Easing.OutQuint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override DrawableMenuItem CreateDrawableMenuItem(MenuItem item) => new DrawableOsuMenuItem(item);
|
||||||
|
|
||||||
|
protected override Menu CreateSubMenu() => new OsuMenu(Direction.Vertical)
|
||||||
|
{
|
||||||
|
Anchor = Direction == Direction.Horizontal ? Anchor.BottomLeft : Anchor.TopRight
|
||||||
|
};
|
||||||
|
|
||||||
|
protected class DrawableOsuMenuItem : DrawableMenuItem
|
||||||
|
{
|
||||||
|
private const int margin_horizontal = 17;
|
||||||
|
private const int text_size = 17;
|
||||||
|
private const int transition_length = 80;
|
||||||
|
public const int MARGIN_VERTICAL = 4;
|
||||||
|
|
||||||
|
private SampleChannel sampleClick;
|
||||||
|
private SampleChannel sampleHover;
|
||||||
|
|
||||||
|
private TextContainer text;
|
||||||
|
|
||||||
|
public DrawableOsuMenuItem(MenuItem item)
|
||||||
|
: base(item)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(AudioManager audio)
|
||||||
|
{
|
||||||
|
sampleHover = audio.Sample.Get(@"UI/generic-hover");
|
||||||
|
sampleClick = audio.Sample.Get(@"UI/generic-click");
|
||||||
|
|
||||||
|
BackgroundColour = Color4.Transparent;
|
||||||
|
BackgroundColourHover = OsuColour.FromHex(@"172023");
|
||||||
|
|
||||||
|
updateTextColour();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateTextColour()
|
||||||
|
{
|
||||||
|
switch ((Item as OsuMenuItem)?.Type)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
case MenuItemType.Standard:
|
||||||
|
text.Colour = Color4.White;
|
||||||
|
break;
|
||||||
|
case MenuItemType.Destructive:
|
||||||
|
text.Colour = Color4.Red;
|
||||||
|
break;
|
||||||
|
case MenuItemType.Highlighted:
|
||||||
|
text.Colour = OsuColour.FromHex(@"ffcc22");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool OnHover(InputState state)
|
||||||
|
{
|
||||||
|
sampleHover.Play();
|
||||||
|
text.BoldText.FadeIn(transition_length, Easing.OutQuint);
|
||||||
|
text.NormalText.FadeOut(transition_length, Easing.OutQuint);
|
||||||
|
return base.OnHover(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnHoverLost(InputState state)
|
||||||
|
{
|
||||||
|
text.BoldText.FadeOut(transition_length, Easing.OutQuint);
|
||||||
|
text.NormalText.FadeIn(transition_length, Easing.OutQuint);
|
||||||
|
base.OnHoverLost(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool OnClick(InputState state)
|
||||||
|
{
|
||||||
|
sampleClick.Play();
|
||||||
|
return base.OnClick(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected sealed override Drawable CreateContent() => text = CreateTextContainer();
|
||||||
|
protected virtual TextContainer CreateTextContainer() => new TextContainer();
|
||||||
|
|
||||||
|
protected class TextContainer : Container, IHasText
|
||||||
|
{
|
||||||
|
public string Text
|
||||||
|
{
|
||||||
|
get { return NormalText.Text; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
NormalText.Text = value;
|
||||||
|
BoldText.Text = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public readonly SpriteText NormalText;
|
||||||
|
public readonly SpriteText BoldText;
|
||||||
|
|
||||||
|
public TextContainer()
|
||||||
|
{
|
||||||
|
Anchor = Anchor.CentreLeft;
|
||||||
|
Origin = Anchor.CentreLeft;
|
||||||
|
|
||||||
|
AutoSizeAxes = Axes.Both;
|
||||||
|
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
NormalText = new OsuSpriteText
|
||||||
|
{
|
||||||
|
Anchor = Anchor.CentreLeft,
|
||||||
|
Origin = Anchor.CentreLeft,
|
||||||
|
TextSize = text_size,
|
||||||
|
Margin = new MarginPadding { Horizontal = margin_horizontal, Vertical = MARGIN_VERTICAL },
|
||||||
|
},
|
||||||
|
BoldText = new OsuSpriteText
|
||||||
|
{
|
||||||
|
AlwaysPresent = true,
|
||||||
|
Alpha = 0,
|
||||||
|
Anchor = Anchor.CentreLeft,
|
||||||
|
Origin = Anchor.CentreLeft,
|
||||||
|
TextSize = text_size,
|
||||||
|
Font = @"Exo2.0-Bold",
|
||||||
|
Margin = new MarginPadding { Horizontal = margin_horizontal, Vertical = MARGIN_VERTICAL },
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
25
osu.Game/Graphics/UserInterface/OsuMenuItem.cs
Normal file
25
osu.Game/Graphics/UserInterface/OsuMenuItem.cs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
// 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;
|
||||||
|
using osu.Framework.Graphics.UserInterface;
|
||||||
|
|
||||||
|
namespace osu.Game.Graphics.UserInterface
|
||||||
|
{
|
||||||
|
public class OsuMenuItem : MenuItem
|
||||||
|
{
|
||||||
|
public readonly MenuItemType Type;
|
||||||
|
|
||||||
|
public OsuMenuItem(string text, MenuItemType type = MenuItemType.Standard)
|
||||||
|
: base(text)
|
||||||
|
{
|
||||||
|
Type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OsuMenuItem(string text, MenuItemType type, Action action)
|
||||||
|
: base(text, action)
|
||||||
|
{
|
||||||
|
Type = type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,11 +1,16 @@
|
|||||||
// 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 osu.Framework.Graphics;
|
|
||||||
using osu.Framework.Graphics.Containers;
|
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
|
using OpenTK.Input;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Cursor;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Framework.Input;
|
||||||
|
using osu.Framework.Platform;
|
||||||
|
|
||||||
namespace osu.Game.Graphics.UserInterface
|
namespace osu.Game.Graphics.UserInterface
|
||||||
{
|
{
|
||||||
@ -15,6 +20,49 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
|
|
||||||
public override bool AllowClipboardExport => false;
|
public override bool AllowClipboardExport => false;
|
||||||
|
|
||||||
|
private readonly CapsWarning warning;
|
||||||
|
|
||||||
|
private GameHost host;
|
||||||
|
|
||||||
|
public OsuPasswordTextBox()
|
||||||
|
{
|
||||||
|
Add(warning = new CapsWarning
|
||||||
|
{
|
||||||
|
Size = new Vector2(20),
|
||||||
|
Origin = Anchor.CentreRight,
|
||||||
|
Anchor = Anchor.CentreRight,
|
||||||
|
Margin = new MarginPadding { Right = 10 },
|
||||||
|
Alpha = 0,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(GameHost host)
|
||||||
|
{
|
||||||
|
this.host = host;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
|
||||||
|
{
|
||||||
|
if (args.Key == Key.CapsLock)
|
||||||
|
updateCapsWarning(host.CapsLockEnabled);
|
||||||
|
return base.OnKeyDown(state, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnFocus(InputState state)
|
||||||
|
{
|
||||||
|
updateCapsWarning(host.CapsLockEnabled);
|
||||||
|
base.OnFocus(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnFocusLost(InputState state)
|
||||||
|
{
|
||||||
|
updateCapsWarning(false);
|
||||||
|
base.OnFocusLost(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateCapsWarning(bool visible) => warning.FadeTo(visible ? 1 : 0, 250, Easing.OutQuint);
|
||||||
|
|
||||||
public class PasswordMaskChar : Container
|
public class PasswordMaskChar : Container
|
||||||
{
|
{
|
||||||
private readonly CircularContainer circle;
|
private readonly CircularContainer circle;
|
||||||
@ -51,5 +99,21 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
circle.ResizeTo(new Vector2(0.8f), 500, Easing.OutQuint);
|
circle.ResizeTo(new Vector2(0.8f), 500, Easing.OutQuint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class CapsWarning : SpriteIcon, IHasTooltip
|
||||||
|
{
|
||||||
|
public string TooltipText => @"Caps lock is active";
|
||||||
|
|
||||||
|
public CapsWarning()
|
||||||
|
{
|
||||||
|
Icon = FontAwesome.fa_warning;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuColour colour)
|
||||||
|
{
|
||||||
|
Colour = colour.YellowLight;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,34 +37,34 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuColour colours)
|
private void load(OsuColour colours)
|
||||||
{
|
{
|
||||||
if (accentColour == null)
|
if (accentColour == default(Color4))
|
||||||
AccentColour = colours.Blue;
|
AccentColour = colours.Blue;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Color4? accentColour;
|
private Color4 accentColour;
|
||||||
public Color4 AccentColour
|
public Color4 AccentColour
|
||||||
{
|
{
|
||||||
get { return accentColour.GetValueOrDefault(); }
|
get { return accentColour; }
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
accentColour = value;
|
accentColour = value;
|
||||||
var dropDown = Dropdown as OsuTabDropdown;
|
var dropdown = Dropdown as IHasAccentColour;
|
||||||
if (dropDown != null)
|
if (dropdown != null)
|
||||||
dropDown.AccentColour = value;
|
dropdown.AccentColour = value;
|
||||||
foreach (var item in TabContainer.Children.OfType<OsuTabItem>())
|
foreach (var i in TabContainer.Children.OfType<IHasAccentColour>())
|
||||||
item.AccentColour = value;
|
i.AccentColour = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class OsuTabItem : TabItem<T>
|
public class OsuTabItem : TabItem<T>, IHasAccentColour
|
||||||
{
|
{
|
||||||
protected readonly SpriteText Text;
|
protected readonly SpriteText Text;
|
||||||
private readonly Box box;
|
private readonly Box box;
|
||||||
|
|
||||||
private Color4? accentColour;
|
private Color4 accentColour;
|
||||||
public Color4 AccentColour
|
public Color4 AccentColour
|
||||||
{
|
{
|
||||||
get { return accentColour.GetValueOrDefault(); }
|
get { return accentColour; }
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
accentColour = value;
|
accentColour = value;
|
||||||
@ -103,7 +103,7 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuColour colours)
|
private void load(OsuColour colours)
|
||||||
{
|
{
|
||||||
if (accentColour == null)
|
if (accentColour == default(Color4))
|
||||||
AccentColour = colours.Blue;
|
AccentColour = colours.Blue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,38 +140,55 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
protected override void OnDeactivated() => fadeInactive();
|
protected override void OnDeactivated() => fadeInactive();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// todo: this needs to go
|
||||||
private class OsuTabDropdown : OsuDropdown<T>
|
private class OsuTabDropdown : OsuDropdown<T>
|
||||||
{
|
{
|
||||||
protected override DropdownHeader CreateHeader() => new OsuTabDropdownHeader
|
|
||||||
{
|
|
||||||
AccentColour = AccentColour,
|
|
||||||
Anchor = Anchor.TopRight,
|
|
||||||
Origin = Anchor.TopRight,
|
|
||||||
};
|
|
||||||
|
|
||||||
protected override DropdownMenuItem<T> CreateMenuItem(string text, T value)
|
|
||||||
{
|
|
||||||
var item = base.CreateMenuItem(text, value);
|
|
||||||
item.ForegroundColourHover = Color4.Black;
|
|
||||||
return item;
|
|
||||||
}
|
|
||||||
|
|
||||||
public OsuTabDropdown()
|
public OsuTabDropdown()
|
||||||
{
|
{
|
||||||
DropdownMenu.Anchor = Anchor.TopRight;
|
|
||||||
DropdownMenu.Origin = Anchor.TopRight;
|
|
||||||
|
|
||||||
RelativeSizeAxes = Axes.X;
|
RelativeSizeAxes = Axes.X;
|
||||||
|
|
||||||
DropdownMenu.Background.Colour = Color4.Black.Opacity(0.7f);
|
|
||||||
DropdownMenu.MaxHeight = 400;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override DropdownMenu CreateMenu() => new OsuTabDropdownMenu();
|
||||||
|
|
||||||
|
protected override DropdownHeader CreateHeader() => new OsuTabDropdownHeader
|
||||||
|
{
|
||||||
|
Anchor = Anchor.TopRight,
|
||||||
|
Origin = Anchor.TopRight
|
||||||
|
};
|
||||||
|
|
||||||
|
private class OsuTabDropdownMenu : OsuDropdownMenu
|
||||||
|
{
|
||||||
|
public OsuTabDropdownMenu()
|
||||||
|
{
|
||||||
|
Anchor = Anchor.TopRight;
|
||||||
|
Origin = Anchor.TopRight;
|
||||||
|
|
||||||
|
BackgroundColour = Color4.Black.Opacity(0.7f);
|
||||||
|
MaxHeight = 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override DrawableMenuItem CreateDrawableMenuItem(MenuItem item) => new DrawableOsuTabDropdownMenuItem(item) { AccentColour = AccentColour };
|
||||||
|
|
||||||
|
private class DrawableOsuTabDropdownMenuItem : DrawableOsuDropdownMenuItem
|
||||||
|
{
|
||||||
|
public DrawableOsuTabDropdownMenuItem(MenuItem item)
|
||||||
|
: base(item)
|
||||||
|
{
|
||||||
|
ForegroundColourHover = Color4.Black;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
protected class OsuTabDropdownHeader : OsuDropdownHeader
|
protected class OsuTabDropdownHeader : OsuDropdownHeader
|
||||||
{
|
{
|
||||||
public override Color4 AccentColour
|
public override Color4 AccentColour
|
||||||
{
|
{
|
||||||
get { return base.AccentColour; }
|
get
|
||||||
|
{
|
||||||
|
return base.AccentColour;
|
||||||
|
}
|
||||||
|
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
base.AccentColour = value;
|
base.AccentColour = value;
|
||||||
@ -179,18 +196,6 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnHover(InputState state)
|
|
||||||
{
|
|
||||||
Foreground.Colour = BackgroundColour;
|
|
||||||
return base.OnHover(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnHoverLost(InputState state)
|
|
||||||
{
|
|
||||||
Foreground.Colour = BackgroundColourHover;
|
|
||||||
base.OnHoverLost(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
public OsuTabDropdownHeader()
|
public OsuTabDropdownHeader()
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.None;
|
RelativeSizeAxes = Axes.None;
|
||||||
@ -220,6 +225,18 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
|
|
||||||
Padding = new MarginPadding { Left = 5, Right = 5 };
|
Padding = new MarginPadding { Left = 5, Right = 5 };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override bool OnHover(InputState state)
|
||||||
|
{
|
||||||
|
Foreground.Colour = BackgroundColour;
|
||||||
|
return base.OnHover(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnHoverLost(InputState state)
|
||||||
|
{
|
||||||
|
Foreground.Colour = BackgroundColourHover;
|
||||||
|
base.OnHoverLost(state);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
67
osu.Game/Graphics/UserInterface/ProgressBar.cs
Normal file
67
osu.Game/Graphics/UserInterface/ProgressBar.cs
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
// 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;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Framework.Graphics.UserInterface;
|
||||||
|
using OpenTK.Graphics;
|
||||||
|
|
||||||
|
namespace osu.Game.Graphics.UserInterface
|
||||||
|
{
|
||||||
|
public class ProgressBar : SliderBar<double>
|
||||||
|
{
|
||||||
|
public Action<double> OnSeek;
|
||||||
|
|
||||||
|
private readonly Box fill;
|
||||||
|
private readonly Box background;
|
||||||
|
|
||||||
|
public Color4 FillColour
|
||||||
|
{
|
||||||
|
set { fill.Colour = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public Color4 BackgroundColour
|
||||||
|
{
|
||||||
|
set
|
||||||
|
{
|
||||||
|
background.Alpha = 1;
|
||||||
|
background.Colour = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public double EndTime
|
||||||
|
{
|
||||||
|
set { CurrentNumber.MaxValue = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public double CurrentTime
|
||||||
|
{
|
||||||
|
set { CurrentNumber.Value = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProgressBar()
|
||||||
|
{
|
||||||
|
CurrentNumber.MinValue = 0;
|
||||||
|
CurrentNumber.MaxValue = 1;
|
||||||
|
RelativeSizeAxes = Axes.X;
|
||||||
|
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
background = new Box
|
||||||
|
{
|
||||||
|
Alpha = 0,
|
||||||
|
RelativeSizeAxes = Axes.Both
|
||||||
|
},
|
||||||
|
fill = new Box { RelativeSizeAxes = Axes.Y }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void UpdateValue(float value)
|
||||||
|
{
|
||||||
|
fill.Width = value * UsableWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnUserChange() => OnSeek?.Invoke(Current);
|
||||||
|
}
|
||||||
|
}
|
@ -3,11 +3,11 @@
|
|||||||
|
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Input;
|
|
||||||
using osu.Framework.Threading;
|
using osu.Framework.Threading;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using osu.Framework.Audio;
|
using osu.Framework.Audio;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Game.Input.Bindings;
|
||||||
|
|
||||||
namespace osu.Game.Graphics.UserInterface.Volume
|
namespace osu.Game.Graphics.UserInterface.Volume
|
||||||
{
|
{
|
||||||
@ -64,15 +64,25 @@ namespace osu.Game.Graphics.UserInterface.Volume
|
|||||||
volumeMeterMusic.Bindable.ValueChanged -= volumeChanged;
|
volumeMeterMusic.Bindable.ValueChanged -= volumeChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Adjust(InputState state)
|
public bool Adjust(GlobalAction action)
|
||||||
{
|
{
|
||||||
if (State == Visibility.Hidden)
|
switch (action)
|
||||||
{
|
{
|
||||||
Show();
|
case GlobalAction.DecreaseVolume:
|
||||||
return;
|
if (State == Visibility.Hidden)
|
||||||
|
Show();
|
||||||
|
else
|
||||||
|
volumeMeterMaster.Decrease();
|
||||||
|
return true;
|
||||||
|
case GlobalAction.IncreaseVolume:
|
||||||
|
if (State == Visibility.Hidden)
|
||||||
|
Show();
|
||||||
|
else
|
||||||
|
volumeMeterMaster.Increase();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
volumeMeterMaster.TriggerOnWheel(state);
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
|
@ -3,32 +3,16 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Input;
|
using osu.Framework.Input.Bindings;
|
||||||
using OpenTK.Input;
|
using osu.Game.Input.Bindings;
|
||||||
|
|
||||||
namespace osu.Game.Graphics.UserInterface.Volume
|
namespace osu.Game.Graphics.UserInterface.Volume
|
||||||
{
|
{
|
||||||
internal class VolumeControlReceptor : Container
|
internal class VolumeControlReceptor : Container, IKeyBindingHandler<GlobalAction>
|
||||||
{
|
{
|
||||||
public Action<InputState> ActionRequested;
|
public Func<GlobalAction, bool> ActionRequested;
|
||||||
|
|
||||||
protected override bool OnWheel(InputState state)
|
public bool OnPressed(GlobalAction action) => ActionRequested?.Invoke(action) ?? false;
|
||||||
{
|
public bool OnReleased(GlobalAction action) => false;
|
||||||
ActionRequested?.Invoke(state);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
|
|
||||||
{
|
|
||||||
switch (args.Key)
|
|
||||||
{
|
|
||||||
case Key.Up:
|
|
||||||
case Key.Down:
|
|
||||||
ActionRequested?.Invoke(state);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return base.OnKeyDown(state, args);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,15 +4,16 @@
|
|||||||
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.Input;
|
|
||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Framework.Input.Bindings;
|
||||||
|
using osu.Game.Input.Bindings;
|
||||||
|
|
||||||
namespace osu.Game.Graphics.UserInterface.Volume
|
namespace osu.Game.Graphics.UserInterface.Volume
|
||||||
{
|
{
|
||||||
internal class VolumeMeter : Container
|
internal class VolumeMeter : Container, IKeyBindingHandler<GlobalAction>
|
||||||
{
|
{
|
||||||
private readonly Box meterFill;
|
private readonly Box meterFill;
|
||||||
public BindableDouble Bindable { get; } = new BindableDouble();
|
public BindableDouble Bindable { get; } = new BindableDouble();
|
||||||
@ -76,12 +77,35 @@ namespace osu.Game.Graphics.UserInterface.Volume
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnWheel(InputState state)
|
public void Increase()
|
||||||
{
|
{
|
||||||
Volume += 0.05f * state.Mouse.WheelDelta;
|
Volume += 0.05f;
|
||||||
return true;
|
}
|
||||||
|
|
||||||
|
public void Decrease()
|
||||||
|
{
|
||||||
|
Volume -= 0.05f;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateFill() => meterFill.ScaleTo(new Vector2(1, (float)Volume), 300, Easing.OutQuint);
|
private void updateFill() => meterFill.ScaleTo(new Vector2(1, (float)Volume), 300, Easing.OutQuint);
|
||||||
|
|
||||||
|
public bool OnPressed(GlobalAction action)
|
||||||
|
{
|
||||||
|
if (!IsHovered) return false;
|
||||||
|
|
||||||
|
switch (action)
|
||||||
|
{
|
||||||
|
case GlobalAction.DecreaseVolume:
|
||||||
|
Decrease();
|
||||||
|
return true;
|
||||||
|
case GlobalAction.IncreaseVolume:
|
||||||
|
Increase();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool OnReleased(GlobalAction action) => false;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -26,7 +26,10 @@ namespace osu.Game.Input.Bindings
|
|||||||
new KeyBinding(new[] { InputKey.Control, InputKey.Alt, InputKey.R }, GlobalAction.ResetInputSettings),
|
new KeyBinding(new[] { InputKey.Control, InputKey.Alt, InputKey.R }, GlobalAction.ResetInputSettings),
|
||||||
new KeyBinding(new[] { InputKey.Control, InputKey.T }, GlobalAction.ToggleToolbar),
|
new KeyBinding(new[] { InputKey.Control, InputKey.T }, GlobalAction.ToggleToolbar),
|
||||||
new KeyBinding(new[] { InputKey.Control, InputKey.O }, GlobalAction.ToggleSettings),
|
new KeyBinding(new[] { InputKey.Control, InputKey.O }, GlobalAction.ToggleSettings),
|
||||||
new KeyBinding(new[] { InputKey.Control, InputKey.D }, GlobalAction.ToggleDirect),
|
new KeyBinding(new[] { InputKey.Up }, GlobalAction.IncreaseVolume),
|
||||||
|
new KeyBinding(new[] { InputKey.MouseWheelUp }, GlobalAction.IncreaseVolume),
|
||||||
|
new KeyBinding(new[] { InputKey.Down }, GlobalAction.DecreaseVolume),
|
||||||
|
new KeyBinding(new[] { InputKey.MouseWheelDown }, GlobalAction.DecreaseVolume),
|
||||||
};
|
};
|
||||||
|
|
||||||
protected override IEnumerable<Drawable> KeyBindingInputQueue =>
|
protected override IEnumerable<Drawable> KeyBindingInputQueue =>
|
||||||
@ -47,5 +50,9 @@ namespace osu.Game.Input.Bindings
|
|||||||
ToggleSettings,
|
ToggleSettings,
|
||||||
[Description("Toggle osu!direct")]
|
[Description("Toggle osu!direct")]
|
||||||
ToggleDirect,
|
ToggleDirect,
|
||||||
|
[Description("Increase Volume")]
|
||||||
|
IncreaseVolume,
|
||||||
|
[Description("Decrease Volume")]
|
||||||
|
DecreaseVolume,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +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 System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using osu.Framework.Input;
|
||||||
using osu.Framework.Input.Handlers;
|
using osu.Framework.Input.Handlers;
|
||||||
using osu.Framework.Platform;
|
using osu.Framework.Platform;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
@ -29,5 +31,18 @@ namespace osu.Game.Input.Handlers
|
|||||||
public override bool IsActive => true;
|
public override bool IsActive => true;
|
||||||
|
|
||||||
public override int Priority => 0;
|
public override int Priority => 0;
|
||||||
|
|
||||||
|
public class ReplayState<T> : InputState
|
||||||
|
where T : struct
|
||||||
|
{
|
||||||
|
public List<T> PressedActions;
|
||||||
|
|
||||||
|
public override InputState Clone()
|
||||||
|
{
|
||||||
|
var clone = (ReplayState<T>)base.Clone();
|
||||||
|
clone.PressedActions = new List<T>(PressedActions);
|
||||||
|
return clone;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -18,11 +18,11 @@ 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)
|
||||||
insertDefaults(ruleset.GetDefaultKeyBindings(), info.ID, variant);
|
insertDefaults(ruleset.GetDefaultKeyBindings(variant), info.ID, variant);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,11 +11,11 @@ namespace osu.Game.Online.API
|
|||||||
/// An API request with a well-defined response type.
|
/// An API request with a well-defined response type.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">Type of the response (used for deserialisation).</typeparam>
|
/// <typeparam name="T">Type of the response (used for deserialisation).</typeparam>
|
||||||
public class APIRequest<T> : APIRequest
|
public abstract class APIRequest<T> : APIRequest
|
||||||
{
|
{
|
||||||
protected override WebRequest CreateWebRequest() => new JsonWebRequest<T>(Uri);
|
protected override WebRequest CreateWebRequest() => new JsonWebRequest<T>(Uri);
|
||||||
|
|
||||||
public APIRequest()
|
protected APIRequest()
|
||||||
{
|
{
|
||||||
base.Success += onSuccess;
|
base.Success += onSuccess;
|
||||||
}
|
}
|
||||||
@ -28,10 +28,36 @@ namespace osu.Game.Online.API
|
|||||||
public new event APISuccessHandler<T> Success;
|
public new event APISuccessHandler<T> Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public abstract class APIDownloadRequest : APIRequest
|
||||||
|
{
|
||||||
|
protected override WebRequest CreateWebRequest()
|
||||||
|
{
|
||||||
|
var request = new WebRequest(Uri);
|
||||||
|
request.DownloadProgress += request_Progress;
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void request_Progress(WebRequest request, long current, long total) => API.Scheduler.Add(delegate { Progress?.Invoke(current, total); });
|
||||||
|
|
||||||
|
protected APIDownloadRequest()
|
||||||
|
{
|
||||||
|
base.Success += onSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onSuccess()
|
||||||
|
{
|
||||||
|
Success?.Invoke(WebRequest.ResponseData);
|
||||||
|
}
|
||||||
|
|
||||||
|
public event APIProgressHandler Progress;
|
||||||
|
|
||||||
|
public new event APISuccessHandler<byte[]> Success;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// AN API request with no specified response type.
|
/// AN API request with no specified response type.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class APIRequest
|
public abstract class APIRequest
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The maximum amount of time before this request will fail.
|
/// The maximum amount of time before this request will fail.
|
||||||
@ -42,7 +68,7 @@ namespace osu.Game.Online.API
|
|||||||
|
|
||||||
protected virtual WebRequest CreateWebRequest() => new WebRequest(Uri);
|
protected virtual WebRequest CreateWebRequest() => new WebRequest(Uri);
|
||||||
|
|
||||||
protected virtual string Uri => $@"{api.Endpoint}/api/v2/{Target}";
|
protected virtual string Uri => $@"{API.Endpoint}/api/v2/{Target}";
|
||||||
|
|
||||||
private double remainingTime => Math.Max(0, Timeout - (DateTime.Now.TotalMilliseconds() - (startTime ?? 0)));
|
private double remainingTime => Math.Max(0, Timeout - (DateTime.Now.TotalMilliseconds() - (startTime ?? 0)));
|
||||||
|
|
||||||
@ -52,7 +78,7 @@ namespace osu.Game.Online.API
|
|||||||
|
|
||||||
public double StartTime => startTime ?? -1;
|
public double StartTime => startTime ?? -1;
|
||||||
|
|
||||||
private APIAccess api;
|
protected APIAccess API;
|
||||||
protected WebRequest WebRequest;
|
protected WebRequest WebRequest;
|
||||||
|
|
||||||
public event APISuccessHandler Success;
|
public event APISuccessHandler Success;
|
||||||
@ -64,7 +90,7 @@ namespace osu.Game.Online.API
|
|||||||
|
|
||||||
public void Perform(APIAccess api)
|
public void Perform(APIAccess api)
|
||||||
{
|
{
|
||||||
this.api = api;
|
API = api;
|
||||||
|
|
||||||
if (checkAndProcessFailure())
|
if (checkAndProcessFailure())
|
||||||
return;
|
return;
|
||||||
@ -109,9 +135,9 @@ namespace osu.Game.Online.API
|
|||||||
/// <returns>Whether we are in a failed or cancelled state.</returns>
|
/// <returns>Whether we are in a failed or cancelled state.</returns>
|
||||||
private bool checkAndProcessFailure()
|
private bool checkAndProcessFailure()
|
||||||
{
|
{
|
||||||
if (api == null || pendingFailure == null) return cancelled;
|
if (API == null || pendingFailure == null) return cancelled;
|
||||||
|
|
||||||
api.Scheduler.Add(pendingFailure);
|
API.Scheduler.Add(pendingFailure);
|
||||||
pendingFailure = null;
|
pendingFailure = null;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -119,5 +145,6 @@ namespace osu.Game.Online.API
|
|||||||
|
|
||||||
public delegate void APIFailureHandler(Exception e);
|
public delegate void APIFailureHandler(Exception e);
|
||||||
public delegate void APISuccessHandler();
|
public delegate void APISuccessHandler();
|
||||||
|
public delegate void APIProgressHandler(long current, long total);
|
||||||
public delegate void APISuccessHandler<in T>(T content);
|
public delegate void APISuccessHandler<in T>(T content);
|
||||||
}
|
}
|
||||||
|
@ -46,6 +46,9 @@ namespace osu.Game.Online.API.Requests
|
|||||||
[JsonProperty(@"favourite_count")]
|
[JsonProperty(@"favourite_count")]
|
||||||
private int favouriteCount { get; set; }
|
private int favouriteCount { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty(@"id")]
|
||||||
|
private int onlineId { get; set; }
|
||||||
|
|
||||||
[JsonProperty(@"beatmaps")]
|
[JsonProperty(@"beatmaps")]
|
||||||
private IEnumerable<GetBeatmapSetsBeatmapResponse> beatmaps { get; set; }
|
private IEnumerable<GetBeatmapSetsBeatmapResponse> beatmaps { get; set; }
|
||||||
|
|
||||||
@ -53,6 +56,7 @@ namespace osu.Game.Online.API.Requests
|
|||||||
{
|
{
|
||||||
return new BeatmapSetInfo
|
return new BeatmapSetInfo
|
||||||
{
|
{
|
||||||
|
OnlineBeatmapSetID = onlineId,
|
||||||
Metadata = this,
|
Metadata = this,
|
||||||
OnlineInfo = new BeatmapSetOnlineInfo
|
OnlineInfo = new BeatmapSetOnlineInfo
|
||||||
{
|
{
|
||||||
|
@ -26,9 +26,11 @@ 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 => false;
|
||||||
|
|
||||||
public const int MAX_HISTORY = 300;
|
public const int MAX_HISTORY = 300;
|
||||||
|
|
||||||
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user