mirror of
https://github.com/osukey/osukey.git
synced 2025-05-30 01:47:30 +09:00
Merge branch 'screen-breadcrumbs' of https://github.com/DrabWeb/osu into screen-breadcrumbs
This commit is contained in:
commit
c9cf0e6e8f
@ -1 +1 @@
|
|||||||
Subproject commit 8c4f23269447d9ce21a5dbd3a0fd4f6caae9ab38
|
Subproject commit fac688633b8fcf34ae5d0514c26b03e217161eb4
|
@ -14,7 +14,7 @@ using osu.Game.Tests.Beatmaps;
|
|||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.Tests
|
namespace osu.Game.Rulesets.Catch.Tests
|
||||||
{
|
{
|
||||||
public class CatchBeatmapConversionTest : BeatmapConversionTest<TestCatchRuleset, ConvertValue>
|
internal class CatchBeatmapConversionTest : BeatmapConversionTest<TestCatchRuleset, ConvertValue>
|
||||||
{
|
{
|
||||||
protected override string ResourceAssembly => "osu.Game.Rulesets.Catch";
|
protected override string ResourceAssembly => "osu.Game.Rulesets.Catch";
|
||||||
|
|
||||||
@ -50,7 +50,7 @@ namespace osu.Game.Rulesets.Catch.Tests
|
|||||||
protected override IBeatmapConverter CreateConverter(IBeatmap beatmap) => new CatchBeatmapConverter(beatmap);
|
protected override IBeatmapConverter CreateConverter(IBeatmap beatmap) => new CatchBeatmapConverter(beatmap);
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct ConvertValue : IEquatable<ConvertValue>
|
internal struct ConvertValue : IEquatable<ConvertValue>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A sane value to account for osu!stable using ints everwhere.
|
/// A sane value to account for osu!stable using ints everwhere.
|
||||||
@ -65,7 +65,7 @@ namespace osu.Game.Rulesets.Catch.Tests
|
|||||||
&& Precision.AlmostEquals(Position, other.Position, conversion_lenience);
|
&& Precision.AlmostEquals(Position, other.Position, conversion_lenience);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class TestCatchRuleset : CatchRuleset
|
internal class TestCatchRuleset : CatchRuleset
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,8 @@ using osu.Game.Rulesets.Catch.Replays;
|
|||||||
using osu.Game.Rulesets.Replays.Types;
|
using osu.Game.Rulesets.Replays.Types;
|
||||||
using osu.Game.Beatmaps.Legacy;
|
using osu.Game.Beatmaps.Legacy;
|
||||||
using osu.Game.Rulesets.Catch.Beatmaps;
|
using osu.Game.Rulesets.Catch.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Catch.Difficulty;
|
||||||
|
using osu.Game.Rulesets.Difficulty;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch
|
namespace osu.Game.Rulesets.Catch
|
||||||
{
|
{
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 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.Game.Beatmaps;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Difficulty;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch
|
namespace osu.Game.Rulesets.Catch.Difficulty
|
||||||
{
|
{
|
||||||
public class CatchDifficultyCalculator : DifficultyCalculator
|
public class CatchDifficultyCalculator : DifficultyCalculator
|
||||||
{
|
{
|
@ -47,6 +47,8 @@ namespace osu.Game.Rulesets.Catch.Objects
|
|||||||
|
|
||||||
Scale = 1.0f - 0.7f * (difficulty.CircleSize - 5) / 5;
|
Scale = 1.0f - 0.7f * (difficulty.CircleSize - 5) / 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override HitWindows CreateHitWindows() => null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum FruitVisualRepresentation
|
public enum FruitVisualRepresentation
|
||||||
|
@ -14,7 +14,7 @@ using osu.Game.Tests.Beatmaps;
|
|||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Tests
|
namespace osu.Game.Rulesets.Mania.Tests
|
||||||
{
|
{
|
||||||
public class ManiaBeatmapConversionTest : BeatmapConversionTest<TestManiaRuleset, ConvertValue>
|
internal class ManiaBeatmapConversionTest : BeatmapConversionTest<TestManiaRuleset, ConvertValue>
|
||||||
{
|
{
|
||||||
protected override string ResourceAssembly => "osu.Game.Rulesets.Mania";
|
protected override string ResourceAssembly => "osu.Game.Rulesets.Mania";
|
||||||
|
|
||||||
@ -38,7 +38,7 @@ namespace osu.Game.Rulesets.Mania.Tests
|
|||||||
protected override IBeatmapConverter CreateConverter(IBeatmap beatmap) => new ManiaBeatmapConverter(beatmap);
|
protected override IBeatmapConverter CreateConverter(IBeatmap beatmap) => new ManiaBeatmapConverter(beatmap);
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct ConvertValue : IEquatable<ConvertValue>
|
internal struct ConvertValue : IEquatable<ConvertValue>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A sane value to account for osu!stable using ints everwhere.
|
/// A sane value to account for osu!stable using ints everwhere.
|
||||||
@ -55,7 +55,7 @@ namespace osu.Game.Rulesets.Mania.Tests
|
|||||||
&& Column == other.Column;
|
&& Column == other.Column;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class TestManiaRuleset : ManiaRuleset
|
internal class TestManiaRuleset : ManiaRuleset
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,8 @@
|
|||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
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.Tests.Visual;
|
using osu.Game.Tests.Visual;
|
||||||
@ -17,6 +19,14 @@ namespace osu.Game.Rulesets.Mania.Tests
|
|||||||
{
|
{
|
||||||
public TestCaseManiaHitObjects()
|
public TestCaseManiaHitObjects()
|
||||||
{
|
{
|
||||||
|
Note note1 = new Note();
|
||||||
|
Note note2 = new Note();
|
||||||
|
HoldNote holdNote = new HoldNote { StartTime = 1000 };
|
||||||
|
|
||||||
|
note1.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
|
||||||
|
note2.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
|
||||||
|
holdNote.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
|
||||||
|
|
||||||
Add(new FillFlowContainer
|
Add(new FillFlowContainer
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
@ -43,14 +53,14 @@ namespace osu.Game.Rulesets.Mania.Tests
|
|||||||
RelativeChildSize = new Vector2(1, 10000),
|
RelativeChildSize = new Vector2(1, 10000),
|
||||||
Children = new[]
|
Children = new[]
|
||||||
{
|
{
|
||||||
new DrawableNote(new Note(), ManiaAction.Key1)
|
new DrawableNote(note1, ManiaAction.Key1)
|
||||||
{
|
{
|
||||||
Y = 5000,
|
Y = 5000,
|
||||||
LifetimeStart = double.MinValue,
|
LifetimeStart = double.MinValue,
|
||||||
LifetimeEnd = double.MaxValue,
|
LifetimeEnd = double.MaxValue,
|
||||||
AccentColour = Color4.Red
|
AccentColour = Color4.Red
|
||||||
},
|
},
|
||||||
new DrawableNote(new Note(), ManiaAction.Key1)
|
new DrawableNote(note2, ManiaAction.Key1)
|
||||||
{
|
{
|
||||||
Y = 6000,
|
Y = 6000,
|
||||||
LifetimeStart = double.MinValue,
|
LifetimeStart = double.MinValue,
|
||||||
@ -77,13 +87,13 @@ namespace osu.Game.Rulesets.Mania.Tests
|
|||||||
RelativeChildSize = new Vector2(1, 10000),
|
RelativeChildSize = new Vector2(1, 10000),
|
||||||
Children = new[]
|
Children = new[]
|
||||||
{
|
{
|
||||||
new DrawableHoldNote(new HoldNote { Duration = 1000 } , ManiaAction.Key1)
|
new DrawableHoldNote(holdNote, ManiaAction.Key1)
|
||||||
{
|
{
|
||||||
Y = 5000,
|
Y = 5000,
|
||||||
Height = 1000,
|
Height = 1000,
|
||||||
LifetimeStart = double.MinValue,
|
LifetimeStart = double.MinValue,
|
||||||
LifetimeEnd = double.MaxValue,
|
LifetimeEnd = double.MaxValue,
|
||||||
AccentColour = Color4.Red
|
AccentColour = Color4.Red,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,8 @@ using NUnit.Framework;
|
|||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Timing;
|
using osu.Framework.Timing;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
using osu.Game.Rulesets.Mania.Beatmaps;
|
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||||
using osu.Game.Rulesets.Mania.Configuration;
|
using osu.Game.Rulesets.Mania.Configuration;
|
||||||
@ -83,13 +85,16 @@ namespace osu.Game.Rulesets.Mania.Tests
|
|||||||
|
|
||||||
int col = rng.Next(0, 4);
|
int col = rng.Next(0, 4);
|
||||||
|
|
||||||
var note = new DrawableNote(new Note { Column = col }, ManiaAction.Key1)
|
var note = new Note { Column = col };
|
||||||
|
note.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
|
||||||
|
|
||||||
|
var drawableNote = new DrawableNote(note, ManiaAction.Key1)
|
||||||
{
|
{
|
||||||
AccentColour = playfield.Columns.ElementAt(col).AccentColour
|
AccentColour = playfield.Columns.ElementAt(col).AccentColour
|
||||||
};
|
};
|
||||||
|
|
||||||
playfield.OnJudgement(note, new ManiaJudgement { Result = HitResult.Perfect });
|
playfield.OnJudgement(drawableNote, new ManiaJudgement { Result = HitResult.Perfect });
|
||||||
playfield.Columns[col].OnJudgement(note, new ManiaJudgement { Result = HitResult.Perfect });
|
playfield.Columns[col].OnJudgement(drawableNote, new ManiaJudgement { Result = HitResult.Perfect });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -162,32 +167,24 @@ namespace osu.Game.Rulesets.Mania.Tests
|
|||||||
|
|
||||||
for (double t = start_time; t <= start_time + duration; t += 100)
|
for (double t = start_time; t <= start_time + duration; t += 100)
|
||||||
{
|
{
|
||||||
playfield.Add(new DrawableNote(new Note
|
var note1 = new Note { StartTime = t, Column = 0 };
|
||||||
{
|
var note2 = new Note { StartTime = t, Column = 3 };
|
||||||
StartTime = t,
|
|
||||||
Column = 0
|
|
||||||
}, ManiaAction.Key1));
|
|
||||||
|
|
||||||
playfield.Add(new DrawableNote(new Note
|
note1.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
|
||||||
{
|
note2.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
|
||||||
StartTime = t,
|
|
||||||
Column = 3
|
playfield.Add(new DrawableNote(note1, ManiaAction.Key1));
|
||||||
}, ManiaAction.Key4));
|
playfield.Add(new DrawableNote(note2, ManiaAction.Key4));
|
||||||
}
|
}
|
||||||
|
|
||||||
playfield.Add(new DrawableHoldNote(new HoldNote
|
var holdNote1 = new HoldNote { StartTime = start_time, Duration = duration, Column = 1 };
|
||||||
{
|
var holdNote2 = new HoldNote { StartTime = start_time, Duration = duration, Column = 2 };
|
||||||
StartTime = start_time,
|
|
||||||
Duration = duration,
|
|
||||||
Column = 1
|
|
||||||
}, ManiaAction.Key2));
|
|
||||||
|
|
||||||
playfield.Add(new DrawableHoldNote(new HoldNote
|
holdNote1.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
|
||||||
{
|
holdNote2.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
|
||||||
StartTime = start_time,
|
|
||||||
Duration = duration,
|
playfield.Add(new DrawableHoldNote(holdNote1, ManiaAction.Key2));
|
||||||
Column = 2
|
playfield.Add(new DrawableHoldNote(holdNote2, ManiaAction.Key3));
|
||||||
}, ManiaAction.Key3));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -59,7 +59,6 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
|
|||||||
|
|
||||||
protected override Beatmap<ManiaHitObject> ConvertBeatmap(IBeatmap original)
|
protected override Beatmap<ManiaHitObject> ConvertBeatmap(IBeatmap original)
|
||||||
{
|
{
|
||||||
|
|
||||||
BeatmapDifficulty difficulty = original.BeatmapInfo.BaseDifficulty;
|
BeatmapDifficulty difficulty = original.BeatmapInfo.BaseDifficulty;
|
||||||
|
|
||||||
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);
|
||||||
@ -85,7 +84,10 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
|
|||||||
yield break;
|
yield break;
|
||||||
|
|
||||||
foreach (ManiaHitObject obj in objects)
|
foreach (ManiaHitObject obj in objects)
|
||||||
|
{
|
||||||
|
obj.HitWindows = original.HitWindows;
|
||||||
yield return obj;
|
yield return obj;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly List<double> prevNoteTimes = new List<double>(max_notes_for_density);
|
private readonly List<double> prevNoteTimes = new List<double>(max_notes_for_density);
|
||||||
|
@ -1,14 +1,15 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 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 osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Difficulty;
|
||||||
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 osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania
|
namespace osu.Game.Rulesets.Mania.Difficulty
|
||||||
{
|
{
|
||||||
internal class ManiaDifficultyCalculator : DifficultyCalculator
|
internal class ManiaDifficultyCalculator : DifficultyCalculator
|
||||||
{
|
{
|
@ -15,7 +15,9 @@ using osu.Game.Graphics;
|
|||||||
using osu.Game.Rulesets.Mania.Replays;
|
using osu.Game.Rulesets.Mania.Replays;
|
||||||
using osu.Game.Rulesets.Replays.Types;
|
using osu.Game.Rulesets.Replays.Types;
|
||||||
using osu.Game.Beatmaps.Legacy;
|
using osu.Game.Beatmaps.Legacy;
|
||||||
|
using osu.Game.Rulesets.Difficulty;
|
||||||
using osu.Game.Rulesets.Mania.Beatmaps;
|
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Mania.Difficulty;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania
|
namespace osu.Game.Rulesets.Mania
|
||||||
{
|
{
|
||||||
|
@ -103,6 +103,7 @@ namespace osu.Game.Rulesets.Mania.Objects
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Lenience of release hit windows. This is to make cases where the hold note release
|
/// Lenience of release hit windows. This is to make cases where the hold note release
|
||||||
/// is timed alongside presses of other hit objects less awkward.
|
/// is timed alongside presses of other hit objects less awkward.
|
||||||
|
/// Todo: This shouldn't exist for non-LegacyBeatmapDecoder beatmaps
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private const double release_window_lenience = 1.5;
|
private const double release_window_lenience = 1.5;
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ using OpenTK;
|
|||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Tests
|
namespace osu.Game.Rulesets.Osu.Tests
|
||||||
{
|
{
|
||||||
public class OsuBeatmapConversionTest : BeatmapConversionTest<TestOsuRuleset, ConvertValue>
|
internal class OsuBeatmapConversionTest : BeatmapConversionTest<TestOsuRuleset, ConvertValue>
|
||||||
{
|
{
|
||||||
protected override string ResourceAssembly => "osu.Game.Rulesets.Osu";
|
protected override string ResourceAssembly => "osu.Game.Rulesets.Osu";
|
||||||
|
|
||||||
@ -45,7 +45,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
protected override IBeatmapConverter CreateConverter(IBeatmap beatmap) => new OsuBeatmapConverter(beatmap);
|
protected override IBeatmapConverter CreateConverter(IBeatmap beatmap) => new OsuBeatmapConverter(beatmap);
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct ConvertValue : IEquatable<ConvertValue>
|
internal struct ConvertValue : IEquatable<ConvertValue>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A sane value to account for osu!stable using ints everwhere.
|
/// A sane value to account for osu!stable using ints everwhere.
|
||||||
@ -68,7 +68,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
&& Precision.AlmostEquals(EndY, other.EndY, conversion_lenience);
|
&& Precision.AlmostEquals(EndY, other.EndY, conversion_lenience);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class TestOsuRuleset : OsuRuleset
|
internal class TestOsuRuleset : OsuRuleset
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -93,12 +93,36 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
|
|
||||||
AddStep("Big Single, Large StackOffset", () => testSimpleBigLargeStackOffset());
|
AddStep("Big Single, Large StackOffset", () => testSimpleBigLargeStackOffset());
|
||||||
AddStep("Big 1 Repeat, Large StackOffset", () => testSimpleBigLargeStackOffset(1));
|
AddStep("Big 1 Repeat, Large StackOffset", () => testSimpleBigLargeStackOffset(1));
|
||||||
|
|
||||||
|
AddStep("Distance Overflow", () => testDistanceOverflow());
|
||||||
|
AddStep("Distance Overflow 1 Repeat", () => testDistanceOverflow(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void testSimpleBig(int repeats = 0) => createSlider(2, repeats: repeats);
|
private void testSimpleBig(int repeats = 0) => createSlider(2, repeats: repeats);
|
||||||
|
|
||||||
private void testSimpleBigLargeStackOffset(int repeats = 0) => createSlider(2, repeats: repeats, stackHeight: 10);
|
private void testSimpleBigLargeStackOffset(int repeats = 0) => createSlider(2, repeats: repeats, stackHeight: 10);
|
||||||
|
|
||||||
|
private void testDistanceOverflow(int repeats = 0)
|
||||||
|
{
|
||||||
|
var slider = new Slider
|
||||||
|
{
|
||||||
|
StartTime = Time.Current + 1000,
|
||||||
|
Position = new Vector2(239, 176),
|
||||||
|
ControlPoints = new List<Vector2>
|
||||||
|
{
|
||||||
|
Vector2.Zero,
|
||||||
|
new Vector2(154, 28),
|
||||||
|
new Vector2(52, -34)
|
||||||
|
},
|
||||||
|
Distance = 700,
|
||||||
|
RepeatCount = repeats,
|
||||||
|
RepeatSamples = createEmptySamples(repeats),
|
||||||
|
StackHeight = 10
|
||||||
|
};
|
||||||
|
|
||||||
|
addSlider(slider, 2, 2);
|
||||||
|
}
|
||||||
|
|
||||||
private void testSimpleMedium(int repeats = 0) => createSlider(5, repeats: repeats);
|
private void testSimpleMedium(int repeats = 0) => createSlider(5, repeats: repeats);
|
||||||
|
|
||||||
private void testSimpleSmall(int repeats = 0) => createSlider(7, repeats: repeats);
|
private void testSimpleSmall(int repeats = 0) => createSlider(7, repeats: repeats);
|
||||||
|
@ -40,7 +40,8 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
|
|||||||
RepeatSamples = curveData.RepeatSamples,
|
RepeatSamples = curveData.RepeatSamples,
|
||||||
RepeatCount = curveData.RepeatCount,
|
RepeatCount = curveData.RepeatCount,
|
||||||
Position = positionData?.Position ?? Vector2.Zero,
|
Position = positionData?.Position ?? Vector2.Zero,
|
||||||
NewCombo = comboData?.NewCombo ?? false
|
NewCombo = comboData?.NewCombo ?? false,
|
||||||
|
HitWindows = original.HitWindows
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
else if (endTimeData != null)
|
else if (endTimeData != null)
|
||||||
@ -50,8 +51,8 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
|
|||||||
StartTime = original.StartTime,
|
StartTime = original.StartTime,
|
||||||
Samples = original.Samples,
|
Samples = original.Samples,
|
||||||
EndTime = endTimeData.EndTime,
|
EndTime = endTimeData.EndTime,
|
||||||
|
|
||||||
Position = positionData?.Position ?? OsuPlayfield.BASE_SIZE / 2,
|
Position = positionData?.Position ?? OsuPlayfield.BASE_SIZE / 2,
|
||||||
|
HitWindows = original.HitWindows
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -61,7 +62,8 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
|
|||||||
StartTime = original.StartTime,
|
StartTime = original.StartTime,
|
||||||
Samples = original.Samples,
|
Samples = original.Samples,
|
||||||
Position = positionData?.Position ?? Vector2.Zero,
|
Position = positionData?.Position ?? Vector2.Zero,
|
||||||
NewCombo = comboData?.NewCombo ?? false
|
NewCombo = comboData?.NewCombo ?? false,
|
||||||
|
HitWindows = original.HitWindows
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,12 +4,13 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Difficulty;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
|
using osu.Game.Rulesets.Osu.Difficulty.Preprocessing;
|
||||||
|
using osu.Game.Rulesets.Osu.Difficulty.Skills;
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
using osu.Game.Rulesets.Osu.OsuDifficulty.Preprocessing;
|
|
||||||
using osu.Game.Rulesets.Osu.OsuDifficulty.Skills;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.OsuDifficulty
|
namespace osu.Game.Rulesets.Osu.Difficulty
|
||||||
{
|
{
|
||||||
public class OsuDifficultyCalculator : DifficultyCalculator
|
public class OsuDifficultyCalculator : DifficultyCalculator
|
||||||
{
|
{
|
@ -5,7 +5,7 @@ using System.Collections;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.OsuDifficulty.Preprocessing
|
namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// An enumerable container wrapping <see cref="OsuHitObject"/> input as <see cref="OsuDifficultyHitObject"/>
|
/// An enumerable container wrapping <see cref="OsuHitObject"/> input as <see cref="OsuDifficultyHitObject"/>
|
@ -3,10 +3,10 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using OpenTK;
|
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
|
using OpenTK;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.OsuDifficulty.Preprocessing
|
namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A wrapper around <see cref="OsuHitObject"/> extending it with additional data required for difficulty calculation.
|
/// A wrapper around <see cref="OsuHitObject"/> extending it with additional data required for difficulty calculation.
|
@ -2,9 +2,9 @@
|
|||||||
// 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 osu.Game.Rulesets.Osu.OsuDifficulty.Preprocessing;
|
using osu.Game.Rulesets.Osu.Difficulty.Preprocessing;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.OsuDifficulty.Skills
|
namespace osu.Game.Rulesets.Osu.Difficulty.Skills
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents the skill required to correctly aim at every object in the map with a uniform CircleSize and normalized distances.
|
/// Represents the skill required to correctly aim at every object in the map with a uniform CircleSize and normalized distances.
|
@ -3,11 +3,11 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using osu.Game.Rulesets.Osu.Difficulty.Preprocessing;
|
||||||
|
using osu.Game.Rulesets.Osu.Difficulty.Utils;
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
using osu.Game.Rulesets.Osu.OsuDifficulty.Preprocessing;
|
|
||||||
using osu.Game.Rulesets.Osu.OsuDifficulty.Utils;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.OsuDifficulty.Skills
|
namespace osu.Game.Rulesets.Osu.Difficulty.Skills
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Used to processes strain values of <see cref="OsuDifficultyHitObject"/>s, keep track of strain levels caused by the processed objects
|
/// Used to processes strain values of <see cref="OsuDifficultyHitObject"/>s, keep track of strain levels caused by the processed objects
|
@ -1,9 +1,9 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 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.Game.Rulesets.Osu.OsuDifficulty.Preprocessing;
|
using osu.Game.Rulesets.Osu.Difficulty.Preprocessing;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.OsuDifficulty.Skills
|
namespace osu.Game.Rulesets.Osu.Difficulty.Skills
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents the skill required to press keys with regards to keeping up with the speed at which objects need to be hit.
|
/// Represents the skill required to press keys with regards to keeping up with the speed at which objects need to be hit.
|
@ -5,7 +5,7 @@ using System;
|
|||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.OsuDifficulty.Utils
|
namespace osu.Game.Rulesets.Osu.Difficulty.Utils
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// An indexed stack with Push() only, which disposes items at the bottom after the capacity is full.
|
/// An indexed stack with Push() only, which disposes items at the bottom after the capacity is full.
|
@ -5,7 +5,6 @@ using osu.Game.Beatmaps;
|
|||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.Osu.Mods;
|
using osu.Game.Rulesets.Osu.Mods;
|
||||||
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 System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@ -19,7 +18,9 @@ using osu.Game.Rulesets.Edit;
|
|||||||
using osu.Game.Rulesets.Osu.Replays;
|
using osu.Game.Rulesets.Osu.Replays;
|
||||||
using osu.Game.Rulesets.Replays.Types;
|
using osu.Game.Rulesets.Replays.Types;
|
||||||
using osu.Game.Beatmaps.Legacy;
|
using osu.Game.Beatmaps.Legacy;
|
||||||
|
using osu.Game.Rulesets.Difficulty;
|
||||||
using osu.Game.Rulesets.Osu.Beatmaps;
|
using osu.Game.Rulesets.Osu.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Osu.Difficulty;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu
|
namespace osu.Game.Rulesets.Osu
|
||||||
{
|
{
|
||||||
|
@ -5,6 +5,7 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Difficulty;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.Osu.Mods;
|
using osu.Game.Rulesets.Osu.Mods;
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
@ -18,7 +19,17 @@ namespace osu.Game.Rulesets.Osu.Scoring
|
|||||||
private readonly int beatmapMaxCombo;
|
private readonly int beatmapMaxCombo;
|
||||||
|
|
||||||
private Mod[] mods;
|
private Mod[] mods;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Approach rate adjusted by mods.
|
||||||
|
/// </summary>
|
||||||
private double realApproachRate;
|
private double realApproachRate;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Overall difficulty adjusted by mods.
|
||||||
|
/// </summary>
|
||||||
|
private double realOverallDifficulty;
|
||||||
|
|
||||||
private double accuracy;
|
private double accuracy;
|
||||||
private int scoreMaxCombo;
|
private int scoreMaxCombo;
|
||||||
private int count300;
|
private int count300;
|
||||||
@ -32,7 +43,8 @@ namespace osu.Game.Rulesets.Osu.Scoring
|
|||||||
countHitCircles = Beatmap.HitObjects.Count(h => h is HitCircle);
|
countHitCircles = Beatmap.HitObjects.Count(h => h is HitCircle);
|
||||||
|
|
||||||
beatmapMaxCombo = Beatmap.HitObjects.Count();
|
beatmapMaxCombo = Beatmap.HitObjects.Count();
|
||||||
beatmapMaxCombo += Beatmap.HitObjects.OfType<Slider>().Sum(s => s.NestedHitObjects.Count) + 1;
|
// Add the ticks + tail of the slider. 1 is subtracted because the "headcircle" would be counted twice (once for the slider itself in the line above)
|
||||||
|
beatmapMaxCombo += Beatmap.HitObjects.OfType<Slider>().Sum(s => s.NestedHitObjects.Count - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override double Calculate(Dictionary<string, double> categoryRatings = null)
|
public override double Calculate(Dictionary<string, double> categoryRatings = null)
|
||||||
@ -57,8 +69,12 @@ namespace osu.Game.Rulesets.Osu.Scoring
|
|||||||
ar = Math.Min(10, ar * 1.4);
|
ar = Math.Min(10, ar * 1.4);
|
||||||
if (mods.Any(m => m is OsuModEasy))
|
if (mods.Any(m => m is OsuModEasy))
|
||||||
ar = Math.Max(0, ar / 2);
|
ar = Math.Max(0, ar / 2);
|
||||||
double preEmpt = BeatmapDifficulty.DifficultyRange(ar, 1800, 1200, 450);
|
|
||||||
|
double preEmpt = BeatmapDifficulty.DifficultyRange(ar, 1800, 1200, 450) / TimeRate;
|
||||||
|
double hitWindow300 = (Beatmap.HitObjects.First().HitWindows.Great / 2 - 0.5) / TimeRate;
|
||||||
|
|
||||||
realApproachRate = preEmpt > 1200 ? (1800 - preEmpt) / 120 : (1200 - preEmpt) / 150 + 5;
|
realApproachRate = preEmpt > 1200 ? (1800 - preEmpt) / 120 : (1200 - preEmpt) / 150 + 5;
|
||||||
|
realOverallDifficulty = (80 - 0.5 - hitWindow300) / 6;
|
||||||
|
|
||||||
// Custom multipliers for NoFail and SpunOut.
|
// Custom multipliers for NoFail and SpunOut.
|
||||||
double multiplier = 1.12f; // This is being adjusted to keep the final pp value scaled around what it used to be when changing things
|
double multiplier = 1.12f; // This is being adjusted to keep the final pp value scaled around what it used to be when changing things
|
||||||
@ -84,6 +100,9 @@ namespace osu.Game.Rulesets.Osu.Scoring
|
|||||||
categoryRatings.Add("Aim", aimValue);
|
categoryRatings.Add("Aim", aimValue);
|
||||||
categoryRatings.Add("Speed", speedValue);
|
categoryRatings.Add("Speed", speedValue);
|
||||||
categoryRatings.Add("Accuracy", accuracyValue);
|
categoryRatings.Add("Accuracy", accuracyValue);
|
||||||
|
categoryRatings.Add("OD", realOverallDifficulty);
|
||||||
|
categoryRatings.Add("AR", realApproachRate);
|
||||||
|
categoryRatings.Add("Max Combo", beatmapMaxCombo);
|
||||||
}
|
}
|
||||||
|
|
||||||
return totalValue;
|
return totalValue;
|
||||||
@ -120,8 +139,9 @@ namespace osu.Game.Rulesets.Osu.Scoring
|
|||||||
|
|
||||||
aimValue *= approachRateFactor;
|
aimValue *= approachRateFactor;
|
||||||
|
|
||||||
|
// We want to give more reward for lower AR when it comes to aim and HD. This nerfs high AR and buffs lower AR.
|
||||||
if (mods.Any(h => h is OsuModHidden))
|
if (mods.Any(h => h is OsuModHidden))
|
||||||
aimValue *= 1.18f;
|
aimValue *= 1.02 + (11.0f - realApproachRate) / 50.0; // Gives a 1.04 bonus for AR10, a 1.06 bonus for AR9, a 1.02 bonus for AR11.
|
||||||
|
|
||||||
if (mods.Any(h => h is OsuModFlashlight))
|
if (mods.Any(h => h is OsuModFlashlight))
|
||||||
{
|
{
|
||||||
@ -132,7 +152,7 @@ namespace osu.Game.Rulesets.Osu.Scoring
|
|||||||
// Scale the aim value with accuracy _slightly_
|
// Scale the aim value with accuracy _slightly_
|
||||||
aimValue *= 0.5f + accuracy / 2.0f;
|
aimValue *= 0.5f + accuracy / 2.0f;
|
||||||
// It is important to also consider accuracy difficulty when doing that
|
// It is important to also consider accuracy difficulty when doing that
|
||||||
aimValue *= 0.98f + Math.Pow(Beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty, 2) / 2500;
|
aimValue *= 0.98f + Math.Pow(realOverallDifficulty, 2) / 2500;
|
||||||
|
|
||||||
return aimValue;
|
return aimValue;
|
||||||
}
|
}
|
||||||
@ -152,10 +172,13 @@ namespace osu.Game.Rulesets.Osu.Scoring
|
|||||||
if (beatmapMaxCombo > 0)
|
if (beatmapMaxCombo > 0)
|
||||||
speedValue *= Math.Min(Math.Pow(scoreMaxCombo, 0.8f) / Math.Pow(beatmapMaxCombo, 0.8f), 1.0f);
|
speedValue *= Math.Min(Math.Pow(scoreMaxCombo, 0.8f) / Math.Pow(beatmapMaxCombo, 0.8f), 1.0f);
|
||||||
|
|
||||||
|
if (mods.Any(m => m is OsuModHidden))
|
||||||
|
speedValue *= 1.18f;
|
||||||
|
|
||||||
// Scale the speed value with accuracy _slightly_
|
// Scale the speed value with accuracy _slightly_
|
||||||
speedValue *= 0.5f + accuracy / 2.0f;
|
speedValue *= 0.5f + accuracy / 2.0f;
|
||||||
// It is important to also consider accuracy difficulty when doing that
|
// It is important to also consider accuracy difficulty when doing that
|
||||||
speedValue *= 0.98f + Math.Pow(Beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty, 2) / 2500;
|
speedValue *= 0.98f + Math.Pow(realOverallDifficulty, 2) / 2500;
|
||||||
|
|
||||||
return speedValue;
|
return speedValue;
|
||||||
}
|
}
|
||||||
@ -177,7 +200,7 @@ namespace osu.Game.Rulesets.Osu.Scoring
|
|||||||
|
|
||||||
// Lots of arbitrary values from testing.
|
// Lots of arbitrary values from testing.
|
||||||
// Considering to use derivation from perfect accuracy in a probabilistic manner - assume normal distribution
|
// Considering to use derivation from perfect accuracy in a probabilistic manner - assume normal distribution
|
||||||
double accuracyValue = Math.Pow(1.52163f, Beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty) * Math.Pow(betterAccuracyPercentage, 24) * 2.83f;
|
double accuracyValue = Math.Pow(1.52163f, realOverallDifficulty) * Math.Pow(betterAccuracyPercentage, 24) * 2.83f;
|
||||||
|
|
||||||
// Bonus for many hitcircles - it's harder to keep good accuracy up for longer
|
// Bonus for many hitcircles - it's harder to keep good accuracy up for longer
|
||||||
accuracyValue *= Math.Min(1.15f, Math.Pow(amountHitObjectsWithAccuracy / 1000.0f, 0.3f));
|
accuracyValue *= Math.Min(1.15f, Math.Pow(amountHitObjectsWithAccuracy / 1000.0f, 0.3f));
|
||||||
|
@ -14,7 +14,7 @@ using osu.Game.Tests.Beatmaps;
|
|||||||
|
|
||||||
namespace osu.Game.Rulesets.Taiko.Tests
|
namespace osu.Game.Rulesets.Taiko.Tests
|
||||||
{
|
{
|
||||||
public class TaikoBeatmapConversionTest : BeatmapConversionTest<TestTaikoRuleset, ConvertValue>
|
internal class TaikoBeatmapConversionTest : BeatmapConversionTest<TestTaikoRuleset, ConvertValue>
|
||||||
{
|
{
|
||||||
protected override string ResourceAssembly => "osu.Game.Rulesets.Taiko";
|
protected override string ResourceAssembly => "osu.Game.Rulesets.Taiko";
|
||||||
|
|
||||||
@ -43,7 +43,7 @@ namespace osu.Game.Rulesets.Taiko.Tests
|
|||||||
protected override IBeatmapConverter CreateConverter(IBeatmap beatmap) => new TaikoBeatmapConverter(beatmap);
|
protected override IBeatmapConverter CreateConverter(IBeatmap beatmap) => new TaikoBeatmapConverter(beatmap);
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct ConvertValue : IEquatable<ConvertValue>
|
internal struct ConvertValue : IEquatable<ConvertValue>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A sane value to account for osu!stable using ints everwhere.
|
/// A sane value to account for osu!stable using ints everwhere.
|
||||||
@ -68,7 +68,7 @@ namespace osu.Game.Rulesets.Taiko.Tests
|
|||||||
&& IsStrong == other.IsStrong;
|
&& IsStrong == other.IsStrong;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class TestTaikoRuleset : TaikoRuleset
|
internal class TestTaikoRuleset : TaikoRuleset
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -132,7 +132,8 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
|
|||||||
{
|
{
|
||||||
StartTime = j,
|
StartTime = j,
|
||||||
Samples = currentSamples,
|
Samples = currentSamples,
|
||||||
IsStrong = strong
|
IsStrong = strong,
|
||||||
|
HitWindows = obj.HitWindows
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -142,6 +143,7 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
|
|||||||
StartTime = j,
|
StartTime = j,
|
||||||
Samples = currentSamples,
|
Samples = currentSamples,
|
||||||
IsStrong = strong,
|
IsStrong = strong,
|
||||||
|
HitWindows = obj.HitWindows
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,6 +159,7 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
|
|||||||
IsStrong = strong,
|
IsStrong = strong,
|
||||||
Duration = taikoDuration,
|
Duration = taikoDuration,
|
||||||
TickRate = beatmap.BeatmapInfo.BaseDifficulty.SliderTickRate == 3 ? 3 : 4,
|
TickRate = beatmap.BeatmapInfo.BaseDifficulty.SliderTickRate == 3 ? 3 : 4,
|
||||||
|
HitWindows = obj.HitWindows
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -171,6 +174,7 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
|
|||||||
IsStrong = strong,
|
IsStrong = strong,
|
||||||
Duration = endTimeData.Duration,
|
Duration = endTimeData.Duration,
|
||||||
RequiredHits = (int)Math.Max(1, endTimeData.Duration / 1000 * hitMultiplier),
|
RequiredHits = (int)Math.Max(1, endTimeData.Duration / 1000 * hitMultiplier),
|
||||||
|
HitWindows = obj.HitWindows
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -184,6 +188,7 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
|
|||||||
StartTime = obj.StartTime,
|
StartTime = obj.StartTime,
|
||||||
Samples = obj.Samples,
|
Samples = obj.Samples,
|
||||||
IsStrong = strong,
|
IsStrong = strong,
|
||||||
|
HitWindows = obj.HitWindows
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -193,6 +198,7 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
|
|||||||
StartTime = obj.StartTime,
|
StartTime = obj.StartTime,
|
||||||
Samples = obj.Samples,
|
Samples = obj.Samples,
|
||||||
IsStrong = strong,
|
IsStrong = strong,
|
||||||
|
HitWindows = obj.HitWindows
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 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.Game.Beatmaps;
|
|
||||||
using osu.Game.Rulesets.Taiko.Objects;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Difficulty;
|
||||||
|
using osu.Game.Rulesets.Taiko.Objects;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Taiko
|
namespace osu.Game.Rulesets.Taiko.Difficulty
|
||||||
{
|
{
|
||||||
internal class TaikoDifficultyCalculator : DifficultyCalculator
|
internal class TaikoDifficultyCalculator : DifficultyCalculator
|
||||||
{
|
{
|
@ -40,6 +40,8 @@ namespace osu.Game.Rulesets.Taiko.Objects
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private double tickSpacing = 100;
|
private double tickSpacing = 100;
|
||||||
|
|
||||||
|
private float overallDifficulty = BeatmapDifficulty.DEFAULT_DIFFICULTY;
|
||||||
|
|
||||||
protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
|
protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
|
||||||
{
|
{
|
||||||
base.ApplyDefaultsToSelf(controlPointInfo, difficulty);
|
base.ApplyDefaultsToSelf(controlPointInfo, difficulty);
|
||||||
@ -47,9 +49,7 @@ namespace osu.Game.Rulesets.Taiko.Objects
|
|||||||
TimingControlPoint timingPoint = controlPointInfo.TimingPointAt(StartTime);
|
TimingControlPoint timingPoint = controlPointInfo.TimingPointAt(StartTime);
|
||||||
|
|
||||||
tickSpacing = timingPoint.BeatLength / TickRate;
|
tickSpacing = timingPoint.BeatLength / TickRate;
|
||||||
|
overallDifficulty = difficulty.OverallDifficulty;
|
||||||
RequiredGoodHits = NestedHitObjects.Count * Math.Min(0.15, 0.05 + 0.10 / 6 * difficulty.OverallDifficulty);
|
|
||||||
RequiredGreatHits = NestedHitObjects.Count * Math.Min(0.30, 0.10 + 0.20 / 6 * difficulty.OverallDifficulty);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void CreateNestedHitObjects()
|
protected override void CreateNestedHitObjects()
|
||||||
@ -57,6 +57,9 @@ namespace osu.Game.Rulesets.Taiko.Objects
|
|||||||
base.CreateNestedHitObjects();
|
base.CreateNestedHitObjects();
|
||||||
|
|
||||||
createTicks();
|
createTicks();
|
||||||
|
|
||||||
|
RequiredGoodHits = NestedHitObjects.Count * Math.Min(0.15, 0.05 + 0.10 / 6 * overallDifficulty);
|
||||||
|
RequiredGreatHits = NestedHitObjects.Count * Math.Min(0.30, 0.10 + 0.20 / 6 * overallDifficulty);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createTicks()
|
private void createTicks()
|
||||||
|
@ -13,7 +13,9 @@ using osu.Framework.Input.Bindings;
|
|||||||
using osu.Game.Rulesets.Replays.Types;
|
using osu.Game.Rulesets.Replays.Types;
|
||||||
using osu.Game.Rulesets.Taiko.Replays;
|
using osu.Game.Rulesets.Taiko.Replays;
|
||||||
using osu.Game.Beatmaps.Legacy;
|
using osu.Game.Beatmaps.Legacy;
|
||||||
|
using osu.Game.Rulesets.Difficulty;
|
||||||
using osu.Game.Rulesets.Taiko.Beatmaps;
|
using osu.Game.Rulesets.Taiko.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Taiko.Difficulty;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Taiko
|
namespace osu.Game.Rulesets.Taiko
|
||||||
{
|
{
|
||||||
|
@ -9,6 +9,7 @@ using osu.Game.Audio;
|
|||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Beatmaps.Formats;
|
using osu.Game.Beatmaps.Formats;
|
||||||
using osu.Game.IO.Serialization;
|
using osu.Game.IO.Serialization;
|
||||||
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Objects.Types;
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
using osu.Game.Tests.Resources;
|
using osu.Game.Tests.Resources;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
@ -117,7 +118,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
|||||||
public void TestParity(string beatmap)
|
public void TestParity(string beatmap)
|
||||||
{
|
{
|
||||||
var legacy = decode(beatmap, out Beatmap json);
|
var legacy = decode(beatmap, out Beatmap json);
|
||||||
json.ShouldDeepEqual(legacy);
|
json.WithDeepEqual(legacy).IgnoreProperty(r => r.DeclaringType == typeof(HitWindows)).Assert();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
62
osu.Game.Tests/Visual/TestCaseHoldToConfirmOverlay.cs
Normal file
62
osu.Game.Tests/Visual/TestCaseHoldToConfirmOverlay.cs
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Game.Graphics.Sprites;
|
||||||
|
using osu.Game.Screens.Menu;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.Visual
|
||||||
|
{
|
||||||
|
public class TestCaseHoldToConfirmOverlay : OsuTestCase
|
||||||
|
{
|
||||||
|
public override IReadOnlyList<Type> RequiredTypes => new[] { typeof(ExitConfirmOverlay) };
|
||||||
|
|
||||||
|
public TestCaseHoldToConfirmOverlay()
|
||||||
|
{
|
||||||
|
bool fired = false;
|
||||||
|
|
||||||
|
var firedText = new OsuSpriteText
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
Text = "Fired!",
|
||||||
|
TextSize = 50,
|
||||||
|
Alpha = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
var overlay = new TestHoldToConfirmOverlay
|
||||||
|
{
|
||||||
|
Action = () =>
|
||||||
|
{
|
||||||
|
fired = true;
|
||||||
|
firedText.FadeTo(1).Then().FadeOut(1000);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
overlay,
|
||||||
|
firedText
|
||||||
|
};
|
||||||
|
|
||||||
|
AddStep("start confirming", () => overlay.Begin());
|
||||||
|
AddStep("abort confirming", () => overlay.Abort());
|
||||||
|
|
||||||
|
AddAssert("ensure aborted", () => !fired);
|
||||||
|
|
||||||
|
AddStep("start confirming", () => overlay.Begin());
|
||||||
|
|
||||||
|
AddUntilStep(() => fired, "wait until confirmed");
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TestHoldToConfirmOverlay : ExitConfirmOverlay
|
||||||
|
{
|
||||||
|
protected override bool AllowMultipleFires => true;
|
||||||
|
|
||||||
|
public void Begin() => BeginConfirm();
|
||||||
|
public void Abort() => AbortConfirm();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -4,6 +4,8 @@
|
|||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Configuration;
|
using osu.Framework.Configuration;
|
||||||
|
using osu.Framework.Configuration.Tracking;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual
|
namespace osu.Game.Tests.Visual
|
||||||
@ -11,36 +13,82 @@ namespace osu.Game.Tests.Visual
|
|||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class TestCaseOnScreenDisplay : OsuTestCase
|
public class TestCaseOnScreenDisplay : OsuTestCase
|
||||||
{
|
{
|
||||||
private FrameworkConfigManager config;
|
|
||||||
private Bindable<FrameSync> frameSyncMode;
|
|
||||||
|
|
||||||
protected override void LoadComplete()
|
|
||||||
{
|
|
||||||
base.LoadComplete();
|
|
||||||
|
|
||||||
Add(new OnScreenDisplay());
|
|
||||||
|
|
||||||
frameSyncMode = config.GetBindable<FrameSync>(FrameworkSetting.FrameSync);
|
|
||||||
|
|
||||||
FrameSync initial = frameSyncMode.Value;
|
|
||||||
|
|
||||||
AddRepeatStep(@"Change frame limiter", setNextMode, 3);
|
|
||||||
|
|
||||||
AddStep(@"Restore frame limiter", () => frameSyncMode.Value = initial);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setNextMode()
|
|
||||||
{
|
|
||||||
var nextMode = frameSyncMode.Value + 1;
|
|
||||||
if (nextMode > FrameSync.Unlimited)
|
|
||||||
nextMode = FrameSync.VSync;
|
|
||||||
frameSyncMode.Value = nextMode;
|
|
||||||
}
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(FrameworkConfigManager config)
|
private void load()
|
||||||
{
|
{
|
||||||
this.config = config;
|
var config = new TestConfigManager();
|
||||||
|
|
||||||
|
var osd = new TestOnScreenDisplay();
|
||||||
|
osd.BeginTracking(this, config);
|
||||||
|
Add(osd);
|
||||||
|
|
||||||
|
AddRepeatStep("Change toggle (no bind)", () => config.ToggleSetting(TestConfigSetting.ToggleSettingNoKeybind), 2);
|
||||||
|
AddRepeatStep("Change toggle (with bind)", () => config.ToggleSetting(TestConfigSetting.ToggleSettingWithKeybind), 2);
|
||||||
|
AddRepeatStep("Change enum (no bind)", () => config.IncrementEnumSetting(TestConfigSetting.EnumSettingNoKeybind), 3);
|
||||||
|
AddRepeatStep("Change enum (with bind)", () => config.IncrementEnumSetting(TestConfigSetting.EnumSettingWithKeybind), 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TestConfigManager : ConfigManager<TestConfigSetting>
|
||||||
|
{
|
||||||
|
public TestConfigManager()
|
||||||
|
{
|
||||||
|
InitialiseDefaults();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void InitialiseDefaults()
|
||||||
|
{
|
||||||
|
Set(TestConfigSetting.ToggleSettingNoKeybind, false);
|
||||||
|
Set(TestConfigSetting.EnumSettingNoKeybind, EnumSetting.Setting1);
|
||||||
|
Set(TestConfigSetting.ToggleSettingWithKeybind, false);
|
||||||
|
Set(TestConfigSetting.EnumSettingWithKeybind, EnumSetting.Setting1);
|
||||||
|
|
||||||
|
base.InitialiseDefaults();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ToggleSetting(TestConfigSetting setting) => Set(setting, !Get<bool>(setting));
|
||||||
|
|
||||||
|
public void IncrementEnumSetting(TestConfigSetting setting)
|
||||||
|
{
|
||||||
|
var nextValue = Get<EnumSetting>(setting) + 1;
|
||||||
|
if (nextValue > EnumSetting.Setting4)
|
||||||
|
nextValue = EnumSetting.Setting1;
|
||||||
|
Set(setting, nextValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override TrackedSettings CreateTrackedSettings() => new TrackedSettings
|
||||||
|
{
|
||||||
|
new TrackedSetting<bool>(TestConfigSetting.ToggleSettingNoKeybind, b => new SettingDescription(b, "toggle setting with no keybind", b ? "enabled" : "disabled")),
|
||||||
|
new TrackedSetting<EnumSetting>(TestConfigSetting.EnumSettingNoKeybind, v => new SettingDescription(v, "enum setting with no keybind", v.ToString())),
|
||||||
|
new TrackedSetting<bool>(TestConfigSetting.ToggleSettingWithKeybind, b => new SettingDescription(b, "toggle setting with keybind", b ? "enabled" : "disabled", "fake keybind")),
|
||||||
|
new TrackedSetting<EnumSetting>(TestConfigSetting.EnumSettingWithKeybind, v => new SettingDescription(v, "enum setting with keybind", v.ToString(), "fake keybind")),
|
||||||
|
};
|
||||||
|
|
||||||
|
protected override void PerformLoad()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool PerformSave() => false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum TestConfigSetting
|
||||||
|
{
|
||||||
|
ToggleSettingNoKeybind,
|
||||||
|
EnumSettingNoKeybind,
|
||||||
|
ToggleSettingWithKeybind,
|
||||||
|
EnumSettingWithKeybind
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum EnumSetting
|
||||||
|
{
|
||||||
|
Setting1,
|
||||||
|
Setting2,
|
||||||
|
Setting3,
|
||||||
|
Setting4
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TestOnScreenDisplay : OnScreenDisplay
|
||||||
|
{
|
||||||
|
protected override void Display(Drawable toDisplay) => toDisplay.FadeIn().ResizeHeightTo(110);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ using NUnit.Framework;
|
|||||||
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.Screens;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
@ -15,18 +16,19 @@ using OpenTK;
|
|||||||
namespace osu.Game.Tests.Visual
|
namespace osu.Game.Tests.Visual
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class TestCaseScreenBreadcrumbs : OsuTestCase
|
public class TestCaseScreenBreadcrumbControl : OsuTestCase
|
||||||
{
|
{
|
||||||
private readonly ScreenBreadcrumbControl<TestScreen> breadcrumbs;
|
private readonly ScreenBreadcrumbControl breadcrumbs;
|
||||||
private TestScreen currentScreen, changedScreen;
|
private Screen currentScreen, changedScreen;
|
||||||
|
|
||||||
public TestCaseScreenBreadcrumbs()
|
public TestCaseScreenBreadcrumbControl()
|
||||||
{
|
{
|
||||||
TestScreen startScreen;
|
TestScreen startScreen;
|
||||||
OsuSpriteText titleText;
|
OsuSpriteText titleText;
|
||||||
|
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
|
changedScreen = currentScreen = startScreen = new TestScreenOne(),
|
||||||
new FillFlowContainer
|
new FillFlowContainer
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
@ -35,23 +37,21 @@ namespace osu.Game.Tests.Visual
|
|||||||
Spacing = new Vector2(10),
|
Spacing = new Vector2(10),
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
breadcrumbs = new ScreenBreadcrumbControl<TestScreen>
|
breadcrumbs = new ScreenBreadcrumbControl(startScreen)
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
},
|
},
|
||||||
titleText = new OsuSpriteText(),
|
titleText = new OsuSpriteText(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
currentScreen = startScreen = new TestScreenOne(),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
breadcrumbs.OnScreenChanged += s =>
|
breadcrumbs.Current.ValueChanged += s =>
|
||||||
{
|
{
|
||||||
titleText.Text = $"Changed to {s.ToString()}";
|
titleText.Text = $"Changed to {s.ToString()}";
|
||||||
changedScreen = s;
|
changedScreen = s;
|
||||||
};
|
};
|
||||||
|
|
||||||
AddStep(@"make start current", () => breadcrumbs.CurrentScreen = startScreen);
|
|
||||||
assertCurrent();
|
assertCurrent();
|
||||||
pushNext();
|
pushNext();
|
||||||
assertCurrent();
|
assertCurrent();
|
||||||
@ -75,7 +75,7 @@ namespace osu.Game.Tests.Visual
|
|||||||
breadcrumbs.StripColour = colours.Blue;
|
breadcrumbs.StripColour = colours.Blue;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void pushNext() => AddStep(@"push next screen", () => currentScreen = currentScreen.PushNext());
|
private void pushNext() => AddStep(@"push next screen", () => currentScreen = ((TestScreen)currentScreen).PushNext());
|
||||||
private void assertCurrent() => AddAssert(@"assert the current screen is correct", () => currentScreen == changedScreen);
|
private void assertCurrent() => AddAssert(@"assert the current screen is correct", () => currentScreen == changedScreen);
|
||||||
|
|
||||||
private abstract class TestScreen : OsuScreen
|
private abstract class TestScreen : OsuScreen
|
@ -6,6 +6,7 @@ using System.Collections.Generic;
|
|||||||
using osu.Framework.Audio.Track;
|
using osu.Framework.Audio.Track;
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
|
using osu.Game.Rulesets.Difficulty;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.UI;
|
using osu.Game.Rulesets.UI;
|
||||||
|
@ -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 osu.Framework.Configuration;
|
using osu.Framework.Configuration;
|
||||||
|
using osu.Framework.Configuration.Tracking;
|
||||||
using osu.Framework.Platform;
|
using osu.Framework.Platform;
|
||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
using osu.Game.Screens.Select;
|
using osu.Game.Screens.Select;
|
||||||
@ -95,6 +96,11 @@ namespace osu.Game.Configuration
|
|||||||
public OsuConfigManager(Storage storage) : base(storage)
|
public OsuConfigManager(Storage storage) : base(storage)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override TrackedSettings CreateTrackedSettings() => new TrackedSettings
|
||||||
|
{
|
||||||
|
new TrackedSetting<bool>(OsuSetting.MouseDisableButtons, v => new SettingDescription(!v, "gameplay mouse buttons", v ? "disabled" : "enabled"))
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum OsuSetting
|
public enum OsuSetting
|
||||||
|
@ -44,19 +44,6 @@ namespace osu.Game.Graphics.Containers
|
|||||||
return base.OnClick(state);
|
return base.OnClick(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnDragStart(InputState state)
|
|
||||||
{
|
|
||||||
if (!base.ReceiveMouseInputAt(state.Mouse.NativeState.Position))
|
|
||||||
{
|
|
||||||
State = Visibility.Hidden;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return base.OnDragStart(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override bool OnDrag(InputState state) => State == Visibility.Hidden;
|
|
||||||
|
|
||||||
private void onStateChanged(Visibility visibility)
|
private void onStateChanged(Visibility visibility)
|
||||||
{
|
{
|
||||||
switch (visibility)
|
switch (visibility)
|
||||||
|
@ -1,78 +1,52 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 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.Extensions.IEnumerableExtensions;
|
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||||
using osu.Framework.Screens;
|
using osu.Framework.Screens;
|
||||||
|
|
||||||
namespace osu.Game.Graphics.UserInterface
|
namespace osu.Game.Graphics.UserInterface
|
||||||
{
|
{
|
||||||
public class ScreenBreadcrumbControl : ScreenBreadcrumbControl<Screen>
|
/// <summary>
|
||||||
|
/// A <see cref="BreadcrumbControl"/> which follows the active screen (and allows navigation) in a <see cref="Screen"/> stack.
|
||||||
|
/// </summary>
|
||||||
|
public class ScreenBreadcrumbControl : BreadcrumbControl<Screen>
|
||||||
{
|
{
|
||||||
}
|
private Screen last;
|
||||||
|
|
||||||
public class ScreenBreadcrumbControl<T> : BreadcrumbControl<T> where T : Screen
|
public ScreenBreadcrumbControl(Screen initialScreen)
|
||||||
{
|
|
||||||
private T currentScreen;
|
|
||||||
public T CurrentScreen
|
|
||||||
{
|
{
|
||||||
get { return currentScreen; }
|
Current.ValueChanged += newScreen =>
|
||||||
set
|
|
||||||
{
|
{
|
||||||
if (value == currentScreen) return;
|
if (last != newScreen && !newScreen.IsCurrentScreen)
|
||||||
|
newScreen.MakeCurrent();
|
||||||
if (CurrentScreen != null)
|
|
||||||
{
|
|
||||||
CurrentScreen.Exited -= onExited;
|
|
||||||
CurrentScreen.ModePushed -= onPushed;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// this is the first screen in the stack, so call the initial onPushed
|
|
||||||
currentScreen = value;
|
|
||||||
onPushed(CurrentScreen);
|
|
||||||
}
|
|
||||||
|
|
||||||
currentScreen = value;
|
|
||||||
|
|
||||||
if (CurrentScreen != null)
|
|
||||||
{
|
|
||||||
CurrentScreen.Exited += onExited;
|
|
||||||
CurrentScreen.ModePushed += onPushed;
|
|
||||||
Current.Value = CurrentScreen;
|
|
||||||
OnScreenChanged?.Invoke(CurrentScreen);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public event Action<T> OnScreenChanged;
|
|
||||||
|
|
||||||
public ScreenBreadcrumbControl()
|
|
||||||
{
|
|
||||||
Current.ValueChanged += s =>
|
|
||||||
{
|
|
||||||
if (s != CurrentScreen)
|
|
||||||
{
|
|
||||||
CurrentScreen = s;
|
|
||||||
s.MakeCurrent();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
onPushed(initialScreen);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onExited(Screen screen)
|
private void screenChanged(Screen newScreen)
|
||||||
{
|
{
|
||||||
CurrentScreen = screen as T;
|
if (last != null)
|
||||||
|
{
|
||||||
|
last.Exited -= screenChanged;
|
||||||
|
last.ModePushed -= onPushed;
|
||||||
|
}
|
||||||
|
|
||||||
|
last = newScreen;
|
||||||
|
|
||||||
|
newScreen.Exited += screenChanged;
|
||||||
|
newScreen.ModePushed += onPushed;
|
||||||
|
|
||||||
|
Current.Value = newScreen;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onPushed(Screen screen)
|
private void onPushed(Screen screen)
|
||||||
{
|
{
|
||||||
var newScreen = screen as T;
|
|
||||||
|
|
||||||
Items.ToList().SkipWhile(i => i != Current.Value).Skip(1).ForEach(RemoveItem);
|
Items.ToList().SkipWhile(i => i != Current.Value).Skip(1).ForEach(RemoveItem);
|
||||||
AddItem(newScreen);
|
AddItem(screen);
|
||||||
|
|
||||||
CurrentScreen = newScreen;
|
screenChanged(screen);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,8 @@ namespace osu.Game.Input.Bindings
|
|||||||
{
|
{
|
||||||
new KeyBinding(InputKey.F8, GlobalAction.ToggleChat),
|
new KeyBinding(InputKey.F8, GlobalAction.ToggleChat),
|
||||||
new KeyBinding(InputKey.F9, GlobalAction.ToggleSocial),
|
new KeyBinding(InputKey.F9, GlobalAction.ToggleSocial),
|
||||||
new KeyBinding(InputKey.F12,GlobalAction.TakeScreenshot),
|
new KeyBinding(InputKey.F10, GlobalAction.ToggleGameplayMouseButtons),
|
||||||
|
new KeyBinding(InputKey.F12, GlobalAction.TakeScreenshot),
|
||||||
|
|
||||||
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),
|
||||||
@ -76,6 +77,8 @@ namespace osu.Game.Input.Bindings
|
|||||||
QuickRetry,
|
QuickRetry,
|
||||||
|
|
||||||
[Description("Take screenshot")]
|
[Description("Take screenshot")]
|
||||||
TakeScreenshot
|
TakeScreenshot,
|
||||||
|
[Description("Toggle gameplay mouse buttons")]
|
||||||
|
ToggleGameplayMouseButtons,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -466,6 +466,9 @@ namespace osu.Game
|
|||||||
case GlobalAction.ToggleDirect:
|
case GlobalAction.ToggleDirect:
|
||||||
direct.ToggleVisibility();
|
direct.ToggleVisibility();
|
||||||
return true;
|
return true;
|
||||||
|
case GlobalAction.ToggleGameplayMouseButtons:
|
||||||
|
LocalConfig.Set(OsuSetting.MouseDisableButtons, !LocalConfig.Get<bool>(OsuSetting.MouseDisableButtons));
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
66
osu.Game/Overlays/HoldToConfirmOverlay.cs
Normal file
66
osu.Game/Overlays/HoldToConfirmOverlay.cs
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using OpenTK.Graphics;
|
||||||
|
|
||||||
|
namespace osu.Game.Overlays
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// An overlay which will display a black screen that dims over a period before confirming an exit action.
|
||||||
|
/// Action is BYO (derived class will need to call <see cref="BeginConfirm"/> and <see cref="AbortConfirm"/> from a user event).
|
||||||
|
/// </summary>
|
||||||
|
public abstract class HoldToConfirmOverlay : Container
|
||||||
|
{
|
||||||
|
public Action Action;
|
||||||
|
|
||||||
|
private Box overlay;
|
||||||
|
|
||||||
|
private const int activate_delay = 400;
|
||||||
|
private const int fadeout_delay = 200;
|
||||||
|
|
||||||
|
private bool fired;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether the overlay should be allowed to return from a fired state.
|
||||||
|
/// </summary>
|
||||||
|
protected virtual bool AllowMultipleFires => false;
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both;
|
||||||
|
AlwaysPresent = true;
|
||||||
|
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
overlay = new Box
|
||||||
|
{
|
||||||
|
Alpha = 0,
|
||||||
|
Colour = Color4.Black,
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void BeginConfirm()
|
||||||
|
{
|
||||||
|
if (!AllowMultipleFires && fired) return;
|
||||||
|
overlay.FadeIn(activate_delay * (1 - overlay.Alpha), Easing.Out).OnComplete(_ =>
|
||||||
|
{
|
||||||
|
Action?.Invoke();
|
||||||
|
fired = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void AbortConfirm()
|
||||||
|
{
|
||||||
|
if (!AllowMultipleFires && fired) return;
|
||||||
|
overlay.FadeOut(fadeout_delay, Easing.Out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -12,6 +12,7 @@ using osu.Framework.Graphics.Shapes;
|
|||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
using osu.Framework.Input.Bindings;
|
using osu.Framework.Input.Bindings;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
|
using osu.Game.Graphics.Containers;
|
||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
using osu.Game.Input;
|
using osu.Game.Input;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
@ -43,7 +44,7 @@ namespace osu.Game.Overlays.KeyBinding
|
|||||||
}
|
}
|
||||||
|
|
||||||
private OsuSpriteText text;
|
private OsuSpriteText text;
|
||||||
private OsuSpriteText pressAKey;
|
private OsuTextFlowContainer pressAKey;
|
||||||
|
|
||||||
private FillFlowContainer<KeyButton> buttons;
|
private FillFlowContainer<KeyButton> buttons;
|
||||||
|
|
||||||
@ -95,10 +96,11 @@ namespace osu.Game.Overlays.KeyBinding
|
|||||||
Anchor = Anchor.TopRight,
|
Anchor = Anchor.TopRight,
|
||||||
Origin = Anchor.TopRight
|
Origin = Anchor.TopRight
|
||||||
},
|
},
|
||||||
pressAKey = new OsuSpriteText
|
pressAKey = new OsuTextFlowContainer
|
||||||
{
|
{
|
||||||
Text = "Press a key to change binding, DEL to delete, ESC to cancel.",
|
Text = "Press a key to change binding, Shift+Delete to delete, Escape to cancel.",
|
||||||
Y = height,
|
RelativeSizeAxes = Axes.X,
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
Margin = new MarginPadding(padding),
|
Margin = new MarginPadding(padding),
|
||||||
Alpha = 0,
|
Alpha = 0,
|
||||||
Colour = colours.YellowDark
|
Colour = colours.YellowDark
|
||||||
@ -204,9 +206,16 @@ namespace osu.Game.Overlays.KeyBinding
|
|||||||
finalise();
|
finalise();
|
||||||
return true;
|
return true;
|
||||||
case Key.Delete:
|
case Key.Delete:
|
||||||
bindTarget.UpdateKeyCombination(InputKey.None);
|
{
|
||||||
finalise();
|
if (state.Keyboard.ShiftPressed)
|
||||||
return true;
|
{
|
||||||
|
bindTarget.UpdateKeyCombination(InputKey.None);
|
||||||
|
finalise();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(state));
|
bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(state));
|
||||||
@ -223,6 +232,26 @@ namespace osu.Game.Overlays.KeyBinding
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override bool OnJoystickPress(InputState state, Framework.Input.JoystickEventArgs args)
|
||||||
|
{
|
||||||
|
if (!HasFocus)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(state));
|
||||||
|
finalise();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool OnJoystickRelease(InputState state, Framework.Input.JoystickEventArgs args)
|
||||||
|
{
|
||||||
|
if (!HasFocus)
|
||||||
|
return base.OnJoystickRelease(state, args);
|
||||||
|
|
||||||
|
finalise();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
private void finalise()
|
private void finalise()
|
||||||
{
|
{
|
||||||
if (bindTarget != null)
|
if (bindTarget != null)
|
||||||
@ -241,7 +270,7 @@ namespace osu.Game.Overlays.KeyBinding
|
|||||||
GetContainingInputManager().ChangeFocus(null);
|
GetContainingInputManager().ChangeFocus(null);
|
||||||
|
|
||||||
pressAKey.FadeOut(300, Easing.OutQuint);
|
pressAKey.FadeOut(300, Easing.OutQuint);
|
||||||
pressAKey.Padding = new MarginPadding { Bottom = -pressAKey.DrawHeight };
|
pressAKey.Padding = new MarginPadding { Top = height, Bottom = -pressAKey.DrawHeight };
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnFocus(InputState state)
|
protected override void OnFocus(InputState state)
|
||||||
@ -250,7 +279,7 @@ namespace osu.Game.Overlays.KeyBinding
|
|||||||
AutoSizeEasing = Easing.OutQuint;
|
AutoSizeEasing = Easing.OutQuint;
|
||||||
|
|
||||||
pressAKey.FadeIn(300, Easing.OutQuint);
|
pressAKey.FadeIn(300, Easing.OutQuint);
|
||||||
pressAKey.Padding = new MarginPadding();
|
pressAKey.Padding = new MarginPadding { Top = height };
|
||||||
|
|
||||||
updateBindTarget();
|
updateBindTarget();
|
||||||
base.OnFocus(state);
|
base.OnFocus(state);
|
||||||
|
@ -4,7 +4,8 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
using osu.Framework.Allocation;
|
||||||
|
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.Framework.Input;
|
||||||
@ -16,7 +17,8 @@ namespace osu.Game.Overlays.Music
|
|||||||
{
|
{
|
||||||
public class PlaylistList : CompositeDrawable
|
public class PlaylistList : CompositeDrawable
|
||||||
{
|
{
|
||||||
public Action<BeatmapSetInfo> OnSelect;
|
public Action<BeatmapSetInfo> Selected;
|
||||||
|
public Action<BeatmapSetInfo, int> OrderChanged;
|
||||||
|
|
||||||
private readonly ItemsScrollContainer items;
|
private readonly ItemsScrollContainer items;
|
||||||
|
|
||||||
@ -25,7 +27,8 @@ namespace osu.Game.Overlays.Music
|
|||||||
InternalChild = items = new ItemsScrollContainer
|
InternalChild = items = new ItemsScrollContainer
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
OnSelect = set => OnSelect?.Invoke(set)
|
Selected = set => Selected?.Invoke(set),
|
||||||
|
OrderChanged = (s, i) => OrderChanged?.Invoke(s, i)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,34 +38,20 @@ namespace osu.Game.Overlays.Music
|
|||||||
set { base.Padding = value; }
|
set { base.Padding = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<BeatmapSetInfo> BeatmapSets
|
|
||||||
{
|
|
||||||
get { return items.Sets; }
|
|
||||||
set { items.Sets = value; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public BeatmapSetInfo FirstVisibleSet => items.FirstVisibleSet;
|
public BeatmapSetInfo FirstVisibleSet => items.FirstVisibleSet;
|
||||||
public BeatmapSetInfo NextSet => items.NextSet;
|
|
||||||
public BeatmapSetInfo PreviousSet => items.PreviousSet;
|
|
||||||
|
|
||||||
public BeatmapSetInfo SelectedSet
|
|
||||||
{
|
|
||||||
get { return items.SelectedSet; }
|
|
||||||
set { items.SelectedSet = value; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddBeatmapSet(BeatmapSetInfo beatmapSet) => items.AddBeatmapSet(beatmapSet);
|
|
||||||
public void RemoveBeatmapSet(BeatmapSetInfo beatmapSet) => items.RemoveBeatmapSet(beatmapSet);
|
|
||||||
|
|
||||||
public void Filter(string searchTerm) => items.SearchTerm = searchTerm;
|
public void Filter(string searchTerm) => items.SearchTerm = searchTerm;
|
||||||
|
|
||||||
private class ItemsScrollContainer : OsuScrollContainer
|
private class ItemsScrollContainer : OsuScrollContainer
|
||||||
{
|
{
|
||||||
public Action<BeatmapSetInfo> OnSelect;
|
public Action<BeatmapSetInfo> Selected;
|
||||||
|
public Action<BeatmapSetInfo, int> OrderChanged;
|
||||||
|
|
||||||
private readonly SearchContainer search;
|
private readonly SearchContainer search;
|
||||||
private readonly FillFlowContainer<PlaylistItem> items;
|
private readonly FillFlowContainer<PlaylistItem> items;
|
||||||
|
|
||||||
|
private readonly IBindable<WorkingBeatmap> beatmapBacking = new Bindable<WorkingBeatmap>();
|
||||||
|
|
||||||
public ItemsScrollContainer()
|
public ItemsScrollContainer()
|
||||||
{
|
{
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
@ -83,14 +72,36 @@ namespace osu.Game.Overlays.Music
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<BeatmapSetInfo> Sets
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(BeatmapManager beatmaps, OsuGameBase osuGame)
|
||||||
{
|
{
|
||||||
get { return items.Select(x => x.BeatmapSetInfo).ToList(); }
|
beatmaps.GetAllUsableBeatmapSets().ForEach(addBeatmapSet);
|
||||||
set
|
beatmaps.ItemAdded += addBeatmapSet;
|
||||||
{
|
beatmaps.ItemRemoved += removeBeatmapSet;
|
||||||
items.Clear();
|
|
||||||
value.ForEach(AddBeatmapSet);
|
beatmapBacking.BindTo(osuGame.Beatmap);
|
||||||
}
|
beatmapBacking.ValueChanged += _ => updateSelectedSet();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addBeatmapSet(BeatmapSetInfo obj)
|
||||||
|
{
|
||||||
|
var newItem = new PlaylistItem(obj) { OnSelect = set => Selected?.Invoke(set) };
|
||||||
|
|
||||||
|
items.Add(newItem);
|
||||||
|
items.SetLayoutPosition(newItem, items.Count - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeBeatmapSet(BeatmapSetInfo obj)
|
||||||
|
{
|
||||||
|
var itemToRemove = items.FirstOrDefault(i => i.BeatmapSetInfo.ID == obj.ID);
|
||||||
|
if (itemToRemove != null)
|
||||||
|
items.Remove(itemToRemove);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateSelectedSet()
|
||||||
|
{
|
||||||
|
foreach (PlaylistItem s in items.Children)
|
||||||
|
s.Selected = s.BeatmapSetInfo.ID == beatmapBacking.Value.BeatmapSetInfo.ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string SearchTerm
|
public string SearchTerm
|
||||||
@ -99,34 +110,7 @@ namespace osu.Game.Overlays.Music
|
|||||||
set { search.SearchTerm = value; }
|
set { search.SearchTerm = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddBeatmapSet(BeatmapSetInfo beatmapSet)
|
|
||||||
{
|
|
||||||
var newItem = new PlaylistItem(beatmapSet) { OnSelect = set => OnSelect?.Invoke(set) };
|
|
||||||
|
|
||||||
items.Add(newItem);
|
|
||||||
items.SetLayoutPosition(newItem, items.Count);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RemoveBeatmapSet(BeatmapSetInfo beatmapSet)
|
|
||||||
{
|
|
||||||
var itemToRemove = items.FirstOrDefault(i => i.BeatmapSetInfo.ID == beatmapSet.ID);
|
|
||||||
if (itemToRemove != null)
|
|
||||||
items.Remove(itemToRemove);
|
|
||||||
}
|
|
||||||
|
|
||||||
public BeatmapSetInfo SelectedSet
|
|
||||||
{
|
|
||||||
get { return items.FirstOrDefault(i => i.Selected)?.BeatmapSetInfo; }
|
|
||||||
set
|
|
||||||
{
|
|
||||||
foreach (PlaylistItem s in items.Children)
|
|
||||||
s.Selected = s.BeatmapSetInfo.ID == value?.ID;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public BeatmapSetInfo FirstVisibleSet => items.FirstOrDefault(i => i.MatchingFilter)?.BeatmapSetInfo;
|
public BeatmapSetInfo FirstVisibleSet => items.FirstOrDefault(i => i.MatchingFilter)?.BeatmapSetInfo;
|
||||||
public BeatmapSetInfo NextSet => (items.SkipWhile(i => !i.Selected).Skip(1).FirstOrDefault() ?? items.FirstOrDefault())?.BeatmapSetInfo;
|
|
||||||
public BeatmapSetInfo PreviousSet => (items.TakeWhile(i => !i.Selected).LastOrDefault() ?? items.LastOrDefault())?.BeatmapSetInfo;
|
|
||||||
|
|
||||||
private Vector2 nativeDragPosition;
|
private Vector2 nativeDragPosition;
|
||||||
private PlaylistItem draggedItem;
|
private PlaylistItem draggedItem;
|
||||||
@ -227,6 +211,7 @@ namespace osu.Game.Overlays.Music
|
|||||||
}
|
}
|
||||||
|
|
||||||
items.SetLayoutPosition(draggedItem, dstIndex);
|
items.SetLayoutPosition(draggedItem, dstIndex);
|
||||||
|
OrderChanged?.Invoke(draggedItem.BeatmapSetInfo, dstIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ItemSearchContainer : FillFlowContainer<PlaylistItem>, IHasFilterableChildren
|
private class ItemSearchContainer : FillFlowContainer<PlaylistItem>, IHasFilterableChildren
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Configuration;
|
using osu.Framework.Configuration;
|
||||||
@ -19,18 +19,16 @@ namespace osu.Game.Overlays.Music
|
|||||||
public class PlaylistOverlay : OverlayContainer
|
public class PlaylistOverlay : OverlayContainer
|
||||||
{
|
{
|
||||||
private const float transition_duration = 600;
|
private const float transition_duration = 600;
|
||||||
|
|
||||||
private const float playlist_height = 510;
|
private const float playlist_height = 510;
|
||||||
|
|
||||||
|
public Action<BeatmapSetInfo, int> OrderChanged;
|
||||||
|
|
||||||
|
private BeatmapManager beatmaps;
|
||||||
private FilterControl filter;
|
private FilterControl filter;
|
||||||
private PlaylistList list;
|
private PlaylistList list;
|
||||||
|
|
||||||
private BeatmapManager beatmaps;
|
|
||||||
|
|
||||||
private readonly Bindable<WorkingBeatmap> beatmapBacking = new Bindable<WorkingBeatmap>();
|
private readonly Bindable<WorkingBeatmap> beatmapBacking = new Bindable<WorkingBeatmap>();
|
||||||
|
|
||||||
public IEnumerable<BeatmapSetInfo> BeatmapSets => list.BeatmapSets;
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuGameBase game, BeatmapManager beatmaps, OsuColour colours)
|
private void load(OsuGameBase game, BeatmapManager beatmaps, OsuColour colours)
|
||||||
{
|
{
|
||||||
@ -60,7 +58,8 @@ namespace osu.Game.Overlays.Music
|
|||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Padding = new MarginPadding { Top = 95, Bottom = 10, Right = 10 },
|
Padding = new MarginPadding { Top = 95, Bottom = 10, Right = 10 },
|
||||||
OnSelect = itemSelected,
|
Selected = itemSelected,
|
||||||
|
OrderChanged = (s, i) => OrderChanged?.Invoke(s, i)
|
||||||
},
|
},
|
||||||
filter = new FilterControl
|
filter = new FilterControl
|
||||||
{
|
{
|
||||||
@ -74,30 +73,16 @@ namespace osu.Game.Overlays.Music
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
beatmaps.ItemAdded += handleBeatmapAdded;
|
|
||||||
beatmaps.ItemRemoved += handleBeatmapRemoved;
|
|
||||||
|
|
||||||
list.BeatmapSets = beatmaps.GetAllUsableBeatmapSets();
|
|
||||||
|
|
||||||
beatmapBacking.BindTo(game.Beatmap);
|
beatmapBacking.BindTo(game.Beatmap);
|
||||||
|
|
||||||
filter.Search.OnCommit = (sender, newText) =>
|
filter.Search.OnCommit = (sender, newText) =>
|
||||||
{
|
{
|
||||||
var beatmap = list.FirstVisibleSet?.Beatmaps?.FirstOrDefault();
|
BeatmapInfo beatmap = list.FirstVisibleSet?.Beatmaps?.FirstOrDefault();
|
||||||
if (beatmap != null) playSpecified(beatmap);
|
if (beatmap != null)
|
||||||
|
beatmapBacking.Value = beatmaps.GetWorkingBeatmap(beatmap);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void LoadComplete()
|
|
||||||
{
|
|
||||||
base.LoadComplete();
|
|
||||||
beatmapBacking.ValueChanged += b => list.SelectedSet = b?.BeatmapSetInfo;
|
|
||||||
beatmapBacking.TriggerChange();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void handleBeatmapAdded(BeatmapSetInfo setInfo) => Schedule(() => list.AddBeatmapSet(setInfo));
|
|
||||||
private void handleBeatmapRemoved(BeatmapSetInfo setInfo) => Schedule(() => list.RemoveBeatmapSet(setInfo));
|
|
||||||
|
|
||||||
protected override void PopIn()
|
protected override void PopIn()
|
||||||
{
|
{
|
||||||
filter.Search.HoldFocus = true;
|
filter.Search.HoldFocus = true;
|
||||||
@ -123,49 +108,7 @@ namespace osu.Game.Overlays.Music
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
playSpecified(set.Beatmaps.First());
|
beatmapBacking.Value = beatmaps.GetWorkingBeatmap(set.Beatmaps.First());
|
||||||
}
|
|
||||||
|
|
||||||
public void PlayPrevious()
|
|
||||||
{
|
|
||||||
var playable = list.PreviousSet;
|
|
||||||
|
|
||||||
if (playable != null)
|
|
||||||
{
|
|
||||||
playSpecified(playable.Beatmaps.First());
|
|
||||||
list.SelectedSet = playable;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void PlayNext()
|
|
||||||
{
|
|
||||||
var playable = list.NextSet;
|
|
||||||
|
|
||||||
if (playable != null)
|
|
||||||
{
|
|
||||||
playSpecified(playable.Beatmaps.First());
|
|
||||||
list.SelectedSet = playable;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void playSpecified(BeatmapInfo info)
|
|
||||||
{
|
|
||||||
beatmapBacking.Value = beatmaps.GetWorkingBeatmap(info, beatmapBacking);
|
|
||||||
|
|
||||||
var track = beatmapBacking.Value.Track;
|
|
||||||
|
|
||||||
track.Restart();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Dispose(bool isDisposing)
|
|
||||||
{
|
|
||||||
base.Dispose(isDisposing);
|
|
||||||
|
|
||||||
if (beatmaps != null)
|
|
||||||
{
|
|
||||||
beatmaps.ItemAdded -= handleBeatmapAdded;
|
|
||||||
beatmaps.ItemRemoved -= handleBeatmapRemoved;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
@ -50,7 +51,10 @@ namespace osu.Game.Overlays
|
|||||||
|
|
||||||
private LocalisationEngine localisation;
|
private LocalisationEngine localisation;
|
||||||
|
|
||||||
|
private BeatmapManager beatmaps;
|
||||||
private readonly Bindable<WorkingBeatmap> beatmapBacking = new Bindable<WorkingBeatmap>();
|
private readonly Bindable<WorkingBeatmap> beatmapBacking = new Bindable<WorkingBeatmap>();
|
||||||
|
private List<BeatmapSetInfo> beatmapSets;
|
||||||
|
private BeatmapSetInfo currentSet;
|
||||||
|
|
||||||
private Container dragContainer;
|
private Container dragContainer;
|
||||||
private Container playerContainer;
|
private Container playerContainer;
|
||||||
@ -93,8 +97,9 @@ namespace osu.Game.Overlays
|
|||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuGameBase game, OsuColour colours, LocalisationEngine localisation)
|
private void load(OsuGameBase game, BeatmapManager beatmaps, OsuColour colours, LocalisationEngine localisation)
|
||||||
{
|
{
|
||||||
|
this.beatmaps = beatmaps;
|
||||||
this.localisation = localisation;
|
this.localisation = localisation;
|
||||||
|
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
@ -111,6 +116,7 @@ namespace osu.Game.Overlays
|
|||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
Y = player_height + 10,
|
Y = player_height + 10,
|
||||||
|
OrderChanged = playlistOrderChanged
|
||||||
},
|
},
|
||||||
playerContainer = new Container
|
playerContainer = new Container
|
||||||
{
|
{
|
||||||
@ -185,7 +191,7 @@ namespace osu.Game.Overlays
|
|||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Action = next,
|
Action = () => next(),
|
||||||
Icon = FontAwesome.fa_step_forward,
|
Icon = FontAwesome.fa_step_forward,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -214,11 +220,24 @@ namespace osu.Game.Overlays
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
beatmapSets = beatmaps.GetAllUsableBeatmapSets();
|
||||||
|
beatmaps.ItemAdded += handleBeatmapAdded;
|
||||||
|
beatmaps.ItemRemoved += handleBeatmapRemoved;
|
||||||
|
|
||||||
beatmapBacking.BindTo(game.Beatmap);
|
beatmapBacking.BindTo(game.Beatmap);
|
||||||
|
|
||||||
playlist.StateChanged += s => playlistButton.FadeColour(s == Visibility.Visible ? colours.Yellow : Color4.White, 200, Easing.OutQuint);
|
playlist.StateChanged += s => playlistButton.FadeColour(s == Visibility.Visible ? colours.Yellow : Color4.White, 200, Easing.OutQuint);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void playlistOrderChanged(BeatmapSetInfo beatmapSetInfo, int index)
|
||||||
|
{
|
||||||
|
beatmapSets.Remove(beatmapSetInfo);
|
||||||
|
beatmapSets.Insert(index, beatmapSetInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleBeatmapAdded(BeatmapSetInfo obj) => beatmapSets.Add(obj);
|
||||||
|
private void handleBeatmapRemoved(BeatmapSetInfo obj) => beatmapSets.RemoveAll(s => s.ID == obj.ID);
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
beatmapBacking.ValueChanged += beatmapChanged;
|
beatmapBacking.ValueChanged += beatmapChanged;
|
||||||
@ -257,7 +276,7 @@ namespace osu.Game.Overlays
|
|||||||
|
|
||||||
playButton.Icon = track.IsRunning ? FontAwesome.fa_pause_circle_o : FontAwesome.fa_play_circle_o;
|
playButton.Icon = track.IsRunning ? FontAwesome.fa_pause_circle_o : FontAwesome.fa_play_circle_o;
|
||||||
|
|
||||||
if (track.HasCompleted && !track.Looping && !beatmapBacking.Disabled && playlist.BeatmapSets.Any())
|
if (track.HasCompleted && !track.Looping && !beatmapBacking.Disabled && beatmapSets.Any())
|
||||||
next();
|
next();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -271,7 +290,7 @@ namespace osu.Game.Overlays
|
|||||||
if (track == null)
|
if (track == null)
|
||||||
{
|
{
|
||||||
if (!beatmapBacking.Disabled)
|
if (!beatmapBacking.Disabled)
|
||||||
playlist.PlayNext();
|
next(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -284,13 +303,26 @@ namespace osu.Game.Overlays
|
|||||||
private void prev()
|
private void prev()
|
||||||
{
|
{
|
||||||
queuedDirection = TransformDirection.Prev;
|
queuedDirection = TransformDirection.Prev;
|
||||||
playlist.PlayPrevious();
|
|
||||||
|
var playable = beatmapSets.TakeWhile(i => i.ID != current.BeatmapSetInfo.ID).LastOrDefault() ?? beatmapSets.LastOrDefault();
|
||||||
|
if (playable != null)
|
||||||
|
{
|
||||||
|
beatmapBacking.Value = beatmaps.GetWorkingBeatmap(playable.Beatmaps.First(), beatmapBacking);
|
||||||
|
beatmapBacking.Value.Track.Restart();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void next()
|
private void next(bool instant = false)
|
||||||
{
|
{
|
||||||
queuedDirection = TransformDirection.Next;
|
if (!instant)
|
||||||
playlist.PlayNext();
|
queuedDirection = TransformDirection.Next;
|
||||||
|
|
||||||
|
var playable = beatmapSets.SkipWhile(i => i.ID != current.BeatmapSetInfo.ID).Skip(1).FirstOrDefault() ?? beatmapSets.FirstOrDefault();
|
||||||
|
if (playable != null)
|
||||||
|
{
|
||||||
|
beatmapBacking.Value = beatmaps.GetWorkingBeatmap(playable.Beatmaps.First(), beatmapBacking);
|
||||||
|
beatmapBacking.Value.Track.Restart();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private WorkingBeatmap current;
|
private WorkingBeatmap current;
|
||||||
@ -314,8 +346,8 @@ namespace osu.Game.Overlays
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
//figure out the best direction based on order in playlist.
|
//figure out the best direction based on order in playlist.
|
||||||
var last = playlist.BeatmapSets.TakeWhile(b => b.ID != current.BeatmapSetInfo?.ID).Count();
|
var last = beatmapSets.TakeWhile(b => b.ID != current.BeatmapSetInfo?.ID).Count();
|
||||||
var next = beatmap == null ? -1 : playlist.BeatmapSets.TakeWhile(b => b.ID != beatmap.BeatmapSetInfo?.ID).Count();
|
var next = beatmap == null ? -1 : beatmapSets.TakeWhile(b => b.ID != beatmap.BeatmapSetInfo?.ID).Count();
|
||||||
|
|
||||||
direction = last > next ? TransformDirection.Prev : TransformDirection.Next;
|
direction = last > next ? TransformDirection.Prev : TransformDirection.Next;
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@ using osu.Game.Graphics;
|
|||||||
using OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
|
using osu.Game.Configuration;
|
||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
|
|
||||||
namespace osu.Game.Overlays
|
namespace osu.Game.Overlays
|
||||||
@ -30,6 +31,7 @@ namespace osu.Game.Overlays
|
|||||||
private readonly SpriteText textLine3;
|
private readonly SpriteText textLine3;
|
||||||
|
|
||||||
private const float height = 110;
|
private const float height = 110;
|
||||||
|
private const float height_notext = 98;
|
||||||
private const float height_contracted = height * 0.9f;
|
private const float height_contracted = height * 0.9f;
|
||||||
|
|
||||||
private readonly FillFlowContainer<OptionLight> optionLights;
|
private readonly FillFlowContainer<OptionLight> optionLights;
|
||||||
@ -101,12 +103,12 @@ namespace osu.Game.Overlays
|
|||||||
},
|
},
|
||||||
textLine3 = new OsuSpriteText
|
textLine3 = new OsuSpriteText
|
||||||
{
|
{
|
||||||
Padding = new MarginPadding { Bottom = 15 },
|
Anchor = Anchor.TopCentre,
|
||||||
|
Origin = Anchor.TopCentre,
|
||||||
|
Margin = new MarginPadding { Bottom = 15 },
|
||||||
Font = @"Exo2.0-Bold",
|
Font = @"Exo2.0-Bold",
|
||||||
TextSize = 12,
|
TextSize = 12,
|
||||||
Alpha = 0.3f,
|
Alpha = 0.3f,
|
||||||
Anchor = Anchor.TopCentre,
|
|
||||||
Origin = Anchor.TopCentre,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -116,9 +118,10 @@ namespace osu.Game.Overlays
|
|||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(FrameworkConfigManager frameworkConfig)
|
private void load(FrameworkConfigManager frameworkConfig, OsuConfigManager osuConfig)
|
||||||
{
|
{
|
||||||
BeginTracking(this, frameworkConfig);
|
BeginTracking(this, frameworkConfig);
|
||||||
|
BeginTracking(this, osuConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly Dictionary<(object, IConfigManager), TrackedSettings> trackedConfigManagers = new Dictionary<(object, IConfigManager), TrackedSettings>();
|
private readonly Dictionary<(object, IConfigManager), TrackedSettings> trackedConfigManagers = new Dictionary<(object, IConfigManager), TrackedSettings>();
|
||||||
@ -175,13 +178,10 @@ namespace osu.Game.Overlays
|
|||||||
textLine2.Text = description.Value;
|
textLine2.Text = description.Value;
|
||||||
textLine3.Text = description.Shortcut.ToUpper();
|
textLine3.Text = description.Shortcut.ToUpper();
|
||||||
|
|
||||||
box.Animate(
|
if (string.IsNullOrEmpty(textLine3.Text))
|
||||||
b => b.FadeIn(500, Easing.OutQuint),
|
textLine3.Text = "NO KEY BOUND";
|
||||||
b => b.ResizeHeightTo(height, 500, Easing.OutQuint)
|
|
||||||
).Then(
|
Display(box);
|
||||||
b => b.FadeOutFromOne(1500, Easing.InQuint),
|
|
||||||
b => b.ResizeHeightTo(height_contracted, 1500, Easing.InQuint)
|
|
||||||
);
|
|
||||||
|
|
||||||
int optionCount = 0;
|
int optionCount = 0;
|
||||||
int selectedOption = -1;
|
int selectedOption = -1;
|
||||||
@ -213,6 +213,17 @@ namespace osu.Game.Overlays
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected virtual void Display(Drawable toDisplay)
|
||||||
|
{
|
||||||
|
toDisplay.Animate(
|
||||||
|
b => b.FadeIn(500, Easing.OutQuint),
|
||||||
|
b => b.ResizeHeightTo(height, 500, Easing.OutQuint)
|
||||||
|
).Then(
|
||||||
|
b => b.FadeOutFromOne(1500, Easing.InQuint),
|
||||||
|
b => b.ResizeHeightTo(height_contracted, 1500, Easing.InQuint)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
private class OptionLight : Container
|
private class OptionLight : Container
|
||||||
{
|
{
|
||||||
private Color4 glowingColour, idleColour;
|
private Color4 glowingColour, idleColour;
|
||||||
|
@ -100,6 +100,8 @@ namespace osu.Game.Overlays
|
|||||||
|
|
||||||
public bool Adjust(GlobalAction action)
|
public bool Adjust(GlobalAction action)
|
||||||
{
|
{
|
||||||
|
if (!IsLoaded) return false;
|
||||||
|
|
||||||
switch (action)
|
switch (action)
|
||||||
{
|
{
|
||||||
case GlobalAction.DecreaseVolume:
|
case GlobalAction.DecreaseVolume:
|
||||||
|
@ -2,19 +2,20 @@
|
|||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using osu.Game.Rulesets.Mods;
|
|
||||||
using osu.Framework.Timing;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||||
|
using osu.Framework.Timing;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Mods;
|
||||||
|
|
||||||
namespace osu.Game.Beatmaps
|
namespace osu.Game.Rulesets.Difficulty
|
||||||
{
|
{
|
||||||
public abstract class DifficultyCalculator
|
public abstract class DifficultyCalculator
|
||||||
{
|
{
|
||||||
protected readonly IBeatmap Beatmap;
|
protected readonly IBeatmap Beatmap;
|
||||||
protected readonly Mod[] Mods;
|
protected readonly Mod[] Mods;
|
||||||
|
|
||||||
protected double TimeRate = 1;
|
protected double TimeRate { get; private set; } = 1;
|
||||||
|
|
||||||
protected DifficultyCalculator(IBeatmap beatmap, Mod[] mods = null)
|
protected DifficultyCalculator(IBeatmap beatmap, Mod[] mods = null)
|
||||||
{
|
{
|
@ -2,9 +2,14 @@
|
|||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||||
|
using osu.Framework.Timing;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Mods;
|
||||||
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Scoring
|
namespace osu.Game.Rulesets.Difficulty
|
||||||
{
|
{
|
||||||
public abstract class PerformanceCalculator
|
public abstract class PerformanceCalculator
|
||||||
{
|
{
|
||||||
@ -14,6 +19,8 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
protected readonly IBeatmap Beatmap;
|
protected readonly IBeatmap Beatmap;
|
||||||
protected readonly Score Score;
|
protected readonly Score Score;
|
||||||
|
|
||||||
|
protected double TimeRate { get; private set; } = 1;
|
||||||
|
|
||||||
protected PerformanceCalculator(Ruleset ruleset, IBeatmap beatmap, Score score)
|
protected PerformanceCalculator(Ruleset ruleset, IBeatmap beatmap, Score score)
|
||||||
{
|
{
|
||||||
Score = score;
|
Score = score;
|
||||||
@ -22,6 +29,15 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
|
|
||||||
var diffCalc = ruleset.CreateDifficultyCalculator(beatmap, score.Mods);
|
var diffCalc = ruleset.CreateDifficultyCalculator(beatmap, score.Mods);
|
||||||
diffCalc.Calculate(attributes);
|
diffCalc.Calculate(attributes);
|
||||||
|
|
||||||
|
ApplyMods(score.Mods);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void ApplyMods(Mod[] mods)
|
||||||
|
{
|
||||||
|
var clock = new StopwatchClock();
|
||||||
|
mods.OfType<IApplicableToClock>().ForEach(m => m.ApplyToClock(clock));
|
||||||
|
TimeRate = clock.Rate;
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract double Calculate(Dictionary<string, double> categoryDifficulty = null);
|
public abstract double Calculate(Dictionary<string, double> categoryDifficulty = null);
|
@ -51,16 +51,10 @@ namespace osu.Game.Rulesets.Objects
|
|||||||
|
|
||||||
private float overallDifficulty = BeatmapDifficulty.DEFAULT_DIFFICULTY;
|
private float overallDifficulty = BeatmapDifficulty.DEFAULT_DIFFICULTY;
|
||||||
|
|
||||||
private HitWindows hitWindows;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The hit windows for this <see cref="HitObject"/>.
|
/// The hit windows for this <see cref="HitObject"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public HitWindows HitWindows
|
public HitWindows HitWindows { get; set; }
|
||||||
{
|
|
||||||
get => hitWindows ?? (hitWindows = new HitWindows(overallDifficulty));
|
|
||||||
protected set => hitWindows = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly SortedList<HitObject> nestedHitObjects = new SortedList<HitObject>((h1, h2) => h1.StartTime.CompareTo(h2.StartTime));
|
private readonly SortedList<HitObject> nestedHitObjects = new SortedList<HitObject>((h1, h2) => h1.StartTime.CompareTo(h2.StartTime));
|
||||||
|
|
||||||
@ -78,7 +72,11 @@ namespace osu.Game.Rulesets.Objects
|
|||||||
|
|
||||||
nestedHitObjects.Clear();
|
nestedHitObjects.Clear();
|
||||||
CreateNestedHitObjects();
|
CreateNestedHitObjects();
|
||||||
nestedHitObjects.ForEach(h => h.ApplyDefaults(controlPointInfo, difficulty));
|
nestedHitObjects.ForEach(h =>
|
||||||
|
{
|
||||||
|
h.HitWindows = HitWindows;
|
||||||
|
h.ApplyDefaults(controlPointInfo, difficulty);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
|
protected virtual void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
|
||||||
@ -89,8 +87,9 @@ namespace osu.Game.Rulesets.Objects
|
|||||||
Kiai = effectPoint.KiaiMode;
|
Kiai = effectPoint.KiaiMode;
|
||||||
SampleControlPoint = samplePoint;
|
SampleControlPoint = samplePoint;
|
||||||
|
|
||||||
overallDifficulty = difficulty.OverallDifficulty;
|
if (HitWindows == null)
|
||||||
hitWindows = null;
|
HitWindows = CreateHitWindows();
|
||||||
|
HitWindows?.SetDifficulty(difficulty.OverallDifficulty);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void CreateNestedHitObjects()
|
protected virtual void CreateNestedHitObjects()
|
||||||
@ -98,5 +97,14 @@ namespace osu.Game.Rulesets.Objects
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void AddNested(HitObject hitObject) => nestedHitObjects.Add(hitObject);
|
protected void AddNested(HitObject hitObject) => nestedHitObjects.Add(hitObject);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates the <see cref="HitWindows"/> for this <see cref="HitObject"/>.
|
||||||
|
/// This can be null to indicate that the <see cref="HitObject"/> has no <see cref="HitWindows"/>.
|
||||||
|
/// <para>
|
||||||
|
/// This will only be invoked if <see cref="HitWindows"/> hasn't been set externally (e.g. from a <see cref="BeatmapConverter"/>.
|
||||||
|
/// </para>
|
||||||
|
/// </summary>
|
||||||
|
protected virtual HitWindows CreateHitWindows() => new HitWindows();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -63,10 +63,10 @@ namespace osu.Game.Rulesets.Objects
|
|||||||
public bool AllowsOk;
|
public bool AllowsOk;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Constructs hit windows by fitting a parameter to a 2-part piecewise linear function for each hit window.
|
/// Sets hit windows with values that correspond to a difficulty parameter.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="difficulty">The parameter.</param>
|
/// <param name="difficulty">The parameter.</param>
|
||||||
public HitWindows(double difficulty)
|
public virtual void SetDifficulty(double difficulty)
|
||||||
{
|
{
|
||||||
Perfect = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Perfect]);
|
Perfect = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Perfect]);
|
||||||
Great = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Great]);
|
Great = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Great]);
|
||||||
|
@ -13,5 +13,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Mania
|
|||||||
public float X { get; set; }
|
public float X { get; set; }
|
||||||
|
|
||||||
public bool NewCombo { get; set; }
|
public bool NewCombo { get; set; }
|
||||||
|
|
||||||
|
protected override HitWindows CreateHitWindows() => new ConvertHitWindows();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
32
osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHitWindows.cs
Normal file
32
osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHitWindows.cs
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
// Copyright (c) 2007-2018 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.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Objects.Legacy.Mania
|
||||||
|
{
|
||||||
|
public class ConvertHitWindows : HitWindows
|
||||||
|
{
|
||||||
|
private static readonly IReadOnlyDictionary<HitResult, (double od0, double od5, double od10)> base_ranges = new Dictionary<HitResult, (double, double, double)>
|
||||||
|
{
|
||||||
|
{ HitResult.Perfect, (44.8, 38.8, 27.8) },
|
||||||
|
{ HitResult.Great, (128, 98, 68 ) },
|
||||||
|
{ HitResult.Good, (194, 164, 134) },
|
||||||
|
{ HitResult.Ok, (254, 224, 194) },
|
||||||
|
{ HitResult.Meh, (302, 272, 242) },
|
||||||
|
{ HitResult.Miss, (376, 346, 316) },
|
||||||
|
};
|
||||||
|
|
||||||
|
public override void SetDifficulty(double difficulty)
|
||||||
|
{
|
||||||
|
Perfect = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Perfect]);
|
||||||
|
Great = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Great]);
|
||||||
|
Good = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Good]);
|
||||||
|
Ok = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Ok]);
|
||||||
|
Meh = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Meh]);
|
||||||
|
Miss = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Miss]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -12,5 +12,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Mania
|
|||||||
public double EndTime { get; set; }
|
public double EndTime { get; set; }
|
||||||
|
|
||||||
public double Duration => EndTime - StartTime;
|
public double Duration => EndTime - StartTime;
|
||||||
|
|
||||||
|
protected override HitWindows CreateHitWindows() => new ConvertHitWindows();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,5 +13,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Mania
|
|||||||
public float X { get; set; }
|
public float X { get; set; }
|
||||||
|
|
||||||
public bool NewCombo { get; set; }
|
public bool NewCombo { get; set; }
|
||||||
|
|
||||||
|
protected override HitWindows CreateHitWindows() => new ConvertHitWindows();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,5 +15,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Mania
|
|||||||
public double Duration => EndTime - StartTime;
|
public double Duration => EndTime - StartTime;
|
||||||
|
|
||||||
public float X { get; set; }
|
public float X { get; set; }
|
||||||
|
|
||||||
|
protected override HitWindows CreateHitWindows() => new ConvertHitWindows();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,5 +18,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu
|
|||||||
public float Y => Position.Y;
|
public float Y => Position.Y;
|
||||||
|
|
||||||
public bool NewCombo { get; set; }
|
public bool NewCombo { get; set; }
|
||||||
|
|
||||||
|
protected override HitWindows CreateHitWindows() => new ConvertHitWindows();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
28
osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHitWindows.cs
Normal file
28
osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHitWindows.cs
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
// Copyright (c) 2007-2018 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.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Objects.Legacy.Osu
|
||||||
|
{
|
||||||
|
public class ConvertHitWindows : HitWindows
|
||||||
|
{
|
||||||
|
private static readonly IReadOnlyDictionary<HitResult, (double od0, double od5, double od10)> base_ranges = new Dictionary<HitResult, (double, double, double)>
|
||||||
|
{
|
||||||
|
{ HitResult.Great, (160, 100, 40) },
|
||||||
|
{ HitResult.Good, (280, 200, 120) },
|
||||||
|
{ HitResult.Meh, (400, 300, 200) },
|
||||||
|
{ HitResult.Miss, (400, 400, 400) },
|
||||||
|
};
|
||||||
|
|
||||||
|
public override void SetDifficulty(double difficulty)
|
||||||
|
{
|
||||||
|
Great = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Great]);
|
||||||
|
Good = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Good]);
|
||||||
|
Meh = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Meh]);
|
||||||
|
Miss = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Miss]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -18,5 +18,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu
|
|||||||
public float Y => Position.Y;
|
public float Y => Position.Y;
|
||||||
|
|
||||||
public bool NewCombo { get; set; }
|
public bool NewCombo { get; set; }
|
||||||
|
|
||||||
|
protected override HitWindows CreateHitWindows() => new ConvertHitWindows();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,5 +20,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu
|
|||||||
public float X => Position.X;
|
public float X => Position.X;
|
||||||
|
|
||||||
public float Y => Position.Y;
|
public float Y => Position.Y;
|
||||||
|
|
||||||
|
protected override HitWindows CreateHitWindows() => new ConvertHitWindows();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,5 +11,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Taiko
|
|||||||
internal sealed class ConvertHit : HitObject, IHasCombo
|
internal sealed class ConvertHit : HitObject, IHasCombo
|
||||||
{
|
{
|
||||||
public bool NewCombo { get; set; }
|
public bool NewCombo { get; set; }
|
||||||
|
|
||||||
|
protected override HitWindows CreateHitWindows() => new ConvertHitWindows();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
28
osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHitWindows.cs
Normal file
28
osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHitWindows.cs
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
// Copyright (c) 2007-2018 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.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Objects.Legacy.Taiko
|
||||||
|
{
|
||||||
|
public class ConvertHitWindows : HitWindows
|
||||||
|
{
|
||||||
|
private static readonly IReadOnlyDictionary<HitResult, (double od0, double od5, double od10)> base_ranges = new Dictionary<HitResult, (double, double, double)>
|
||||||
|
{
|
||||||
|
{ HitResult.Great, (100, 70, 40) },
|
||||||
|
{ HitResult.Good, (240, 160, 100) },
|
||||||
|
{ HitResult.Meh, (270, 190, 140) },
|
||||||
|
{ HitResult.Miss, (400, 400, 400) },
|
||||||
|
};
|
||||||
|
|
||||||
|
public override void SetDifficulty(double difficulty)
|
||||||
|
{
|
||||||
|
Great = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Great]);
|
||||||
|
Good = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Good]);
|
||||||
|
Meh = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Meh]);
|
||||||
|
Miss = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Miss]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -11,5 +11,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Taiko
|
|||||||
internal sealed class ConvertSlider : Legacy.ConvertSlider, IHasCombo
|
internal sealed class ConvertSlider : Legacy.ConvertSlider, IHasCombo
|
||||||
{
|
{
|
||||||
public bool NewCombo { get; set; }
|
public bool NewCombo { get; set; }
|
||||||
|
|
||||||
|
protected override HitWindows CreateHitWindows() => new ConvertHitWindows();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,5 +13,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Taiko
|
|||||||
public double EndTime { get; set; }
|
public double EndTime { get; set; }
|
||||||
|
|
||||||
public double Duration => EndTime - StartTime;
|
public double Duration => EndTime - StartTime;
|
||||||
|
|
||||||
|
protected override HitWindows CreateHitWindows() => new ConvertHitWindows();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -99,11 +99,9 @@ namespace osu.Game.Rulesets.Objects
|
|||||||
cumulativeLength.Add(l);
|
cumulativeLength.Add(l);
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: Figure out if the following code is needed in some cases. Judging by the map
|
|
||||||
// "Transform" http://osu.ppy.sh/s/484689 it seems like we should _not_ be doing this.
|
|
||||||
// Lengthen slider curves that are too short compared to what's
|
// Lengthen slider curves that are too short compared to what's
|
||||||
// in the .osu file.
|
// in the .osu file.
|
||||||
/*if (l < Length && calculatedPath.Count > 1)
|
if (l < Distance && calculatedPath.Count > 1)
|
||||||
{
|
{
|
||||||
Vector2 diff = calculatedPath[calculatedPath.Count - 1] - calculatedPath[calculatedPath.Count - 2];
|
Vector2 diff = calculatedPath[calculatedPath.Count - 1] - calculatedPath[calculatedPath.Count - 2];
|
||||||
double d = diff.Length;
|
double d = diff.Length;
|
||||||
@ -111,9 +109,9 @@ namespace osu.Game.Rulesets.Objects
|
|||||||
if (d <= 0)
|
if (d <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
calculatedPath[calculatedPath.Count - 1] += diff * (float)((Length - l) / d);
|
calculatedPath[calculatedPath.Count - 1] += diff * (float)((Distance - l) / d);
|
||||||
cumulativeLength[calculatedPath.Count - 1] = Length;
|
cumulativeLength[calculatedPath.Count - 1] = Distance;
|
||||||
}*/
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Calculate()
|
public void Calculate()
|
||||||
|
@ -15,6 +15,7 @@ using osu.Game.Rulesets.Replays.Types;
|
|||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Rulesets.UI;
|
using osu.Game.Rulesets.UI;
|
||||||
using osu.Game.Beatmaps.Legacy;
|
using osu.Game.Beatmaps.Legacy;
|
||||||
|
using osu.Game.Rulesets.Difficulty;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets
|
namespace osu.Game.Rulesets
|
||||||
{
|
{
|
||||||
|
@ -112,7 +112,7 @@ namespace osu.Game.Rulesets
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var assembly = Assembly.LoadFrom(file);
|
var assembly = Assembly.LoadFrom(file);
|
||||||
loaded_assemblies[assembly] = assembly.GetTypes().First(t => t.IsSubclassOf(typeof(Ruleset)));
|
loaded_assemblies[assembly] = assembly.GetTypes().First(t => t.IsPublic && t.IsSubclassOf(typeof(Ruleset)));
|
||||||
}
|
}
|
||||||
catch (Exception)
|
catch (Exception)
|
||||||
{
|
{
|
||||||
|
@ -0,0 +1,26 @@
|
|||||||
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Scoring.Legacy
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A <see cref="LegacyScoreParser"/> which retrieves the applicable <see cref="Beatmap"/> and <see cref="Ruleset"/>
|
||||||
|
/// for the score from the database.
|
||||||
|
/// </summary>
|
||||||
|
public class DatabasedLegacyScoreParser : LegacyScoreParser
|
||||||
|
{
|
||||||
|
private readonly RulesetStore rulesets;
|
||||||
|
private readonly BeatmapManager beatmaps;
|
||||||
|
|
||||||
|
public DatabasedLegacyScoreParser(RulesetStore rulesets, BeatmapManager beatmaps)
|
||||||
|
{
|
||||||
|
this.rulesets = rulesets;
|
||||||
|
this.beatmaps = beatmaps;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Ruleset GetRuleset(int rulesetId) => rulesets.GetRuleset(rulesetId).CreateInstance();
|
||||||
|
protected override WorkingBeatmap GetBeatmap(string md5Hash) => beatmaps.GetWorkingBeatmap(beatmaps.QueryBeatmap(b => b.MD5Hash == md5Hash));
|
||||||
|
}
|
||||||
|
}
|
@ -14,17 +14,8 @@ using System.Linq;
|
|||||||
|
|
||||||
namespace osu.Game.Rulesets.Scoring.Legacy
|
namespace osu.Game.Rulesets.Scoring.Legacy
|
||||||
{
|
{
|
||||||
public class LegacyScoreParser
|
public abstract class LegacyScoreParser
|
||||||
{
|
{
|
||||||
private readonly RulesetStore rulesets;
|
|
||||||
private readonly BeatmapManager beatmaps;
|
|
||||||
|
|
||||||
public LegacyScoreParser(RulesetStore rulesets, BeatmapManager beatmaps)
|
|
||||||
{
|
|
||||||
this.rulesets = rulesets;
|
|
||||||
this.beatmaps = beatmaps;
|
|
||||||
}
|
|
||||||
|
|
||||||
private IBeatmap currentBeatmap;
|
private IBeatmap currentBeatmap;
|
||||||
private Ruleset currentRuleset;
|
private Ruleset currentRuleset;
|
||||||
|
|
||||||
@ -34,33 +25,35 @@ namespace osu.Game.Rulesets.Scoring.Legacy
|
|||||||
|
|
||||||
using (SerializationReader sr = new SerializationReader(stream))
|
using (SerializationReader sr = new SerializationReader(stream))
|
||||||
{
|
{
|
||||||
score = new Score { Ruleset = rulesets.GetRuleset(sr.ReadByte()) };
|
currentRuleset = GetRuleset(sr.ReadByte());
|
||||||
currentRuleset = score.Ruleset.CreateInstance();
|
score = new Score { Ruleset = currentRuleset.RulesetInfo };
|
||||||
|
|
||||||
/* score.Pass = true;*/
|
/* score.Pass = true;*/
|
||||||
var version = sr.ReadInt32();
|
var version = sr.ReadInt32();
|
||||||
|
|
||||||
/* score.FileChecksum = */
|
/* score.FileChecksum = */
|
||||||
var beatmapHash = sr.ReadString();
|
currentBeatmap = GetBeatmap(sr.ReadString()).Beatmap;
|
||||||
score.Beatmap = beatmaps.QueryBeatmap(b => b.MD5Hash == beatmapHash);
|
score.Beatmap = currentBeatmap.BeatmapInfo;
|
||||||
currentBeatmap = beatmaps.GetWorkingBeatmap(score.Beatmap).Beatmap;
|
|
||||||
|
|
||||||
/* score.PlayerName = */
|
/* score.PlayerName = */
|
||||||
score.User = new User { Username = sr.ReadString() };
|
score.User = new User { Username = sr.ReadString() };
|
||||||
/* var localScoreChecksum = */
|
/* var localScoreChecksum = */
|
||||||
sr.ReadString();
|
sr.ReadString();
|
||||||
/* score.Count300 = */
|
|
||||||
sr.ReadUInt16();
|
var count300 = sr.ReadUInt16();
|
||||||
/* score.Count100 = */
|
var count100 = sr.ReadUInt16();
|
||||||
sr.ReadUInt16();
|
var count50 = sr.ReadUInt16();
|
||||||
/* score.Count50 = */
|
var countGeki = sr.ReadUInt16();
|
||||||
sr.ReadUInt16();
|
var countKatu = sr.ReadUInt16();
|
||||||
/* score.CountGeki = */
|
var countMiss = sr.ReadUInt16();
|
||||||
sr.ReadUInt16();
|
|
||||||
/* score.CountKatu = */
|
score.Statistics[HitResult.Great] = count300;
|
||||||
sr.ReadUInt16();
|
score.Statistics[HitResult.Good] = count100;
|
||||||
/* score.CountMiss = */
|
score.Statistics[HitResult.Meh] = count50;
|
||||||
sr.ReadUInt16();
|
score.Statistics[HitResult.Perfect] = countGeki;
|
||||||
|
score.Statistics[HitResult.Ok] = countKatu;
|
||||||
|
score.Statistics[HitResult.Miss] = countMiss;
|
||||||
|
|
||||||
score.TotalScore = sr.ReadInt32();
|
score.TotalScore = sr.ReadInt32();
|
||||||
score.MaxCombo = sr.ReadUInt16();
|
score.MaxCombo = sr.ReadUInt16();
|
||||||
/* score.Perfect = */
|
/* score.Perfect = */
|
||||||
@ -81,6 +74,34 @@ namespace osu.Game.Rulesets.Scoring.Legacy
|
|||||||
/*OnlineId =*/
|
/*OnlineId =*/
|
||||||
sr.ReadInt32();
|
sr.ReadInt32();
|
||||||
|
|
||||||
|
switch (score.Ruleset.ID)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
int totalHits = count50 + count100 + count300 + countMiss;
|
||||||
|
score.Accuracy = totalHits > 0 ? (double)(count50 * 50 + count100 * 100 + count300 * 300) / (totalHits * 300) : 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
int totalHits = count50 + count100 + count300 + countMiss;
|
||||||
|
score.Accuracy = totalHits > 0 ? (double)(count100 * 150 + count300 * 300) / (totalHits * 300) : 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 2:
|
||||||
|
{
|
||||||
|
int totalHits = count50 + count100 + count300 + countMiss + countKatu;
|
||||||
|
score.Accuracy = totalHits > 0 ? (double)(count50 + count100 + count300 ) / totalHits : 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 3:
|
||||||
|
{
|
||||||
|
int totalHits = count50 + count100 + count300 + countMiss + countGeki + countKatu;
|
||||||
|
score.Accuracy = totalHits > 0 ? (double)(count50 * 50 + count100 * 100 + countKatu * 200 + (count300 + countGeki) * 300) / (totalHits * 300) : 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
using (var replayInStream = new MemoryStream(compressedReplay))
|
using (var replayInStream = new MemoryStream(compressedReplay))
|
||||||
{
|
{
|
||||||
byte[] properties = new byte[5];
|
byte[] properties = new byte[5];
|
||||||
@ -150,5 +171,19 @@ namespace osu.Game.Rulesets.Scoring.Legacy
|
|||||||
|
|
||||||
return frame;
|
return frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves the <see cref="Ruleset"/> for a specific id.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="rulesetId">The id.</param>
|
||||||
|
/// <returns>The <see cref="Ruleset"/>.</returns>
|
||||||
|
protected abstract Ruleset GetRuleset(int rulesetId);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves the <see cref="WorkingBeatmap"/> corresponding to an MD5 hash.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="md5Hash">The MD5 hash.</param>
|
||||||
|
/// <returns>The <see cref="WorkingBeatmap"/>.</returns>
|
||||||
|
protected abstract WorkingBeatmap GetBeatmap(string md5Hash);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,7 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
public Score ReadReplayFile(string replayFilename)
|
public Score ReadReplayFile(string replayFilename)
|
||||||
{
|
{
|
||||||
using (Stream s = storage.GetStream(Path.Combine(replay_folder, replayFilename)))
|
using (Stream s = storage.GetStream(Path.Combine(replay_folder, replayFilename)))
|
||||||
return new LegacyScoreParser(rulesets, beatmaps).Parse(s);
|
return new DatabasedLegacyScoreParser(rulesets, beatmaps).Parse(s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
34
osu.Game/Screens/Menu/ExitConfirmOverlay.cs
Normal file
34
osu.Game/Screens/Menu/ExitConfirmOverlay.cs
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using osu.Framework.Input;
|
||||||
|
using osu.Game.Overlays;
|
||||||
|
using OpenTK.Input;
|
||||||
|
|
||||||
|
namespace osu.Game.Screens.Menu
|
||||||
|
{
|
||||||
|
public class ExitConfirmOverlay : HoldToConfirmOverlay
|
||||||
|
{
|
||||||
|
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
|
||||||
|
{
|
||||||
|
if (args.Key == Key.Escape && !args.Repeat)
|
||||||
|
{
|
||||||
|
BeginConfirm();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return base.OnKeyDown(state, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool OnKeyUp(InputState state, KeyUpEventArgs args)
|
||||||
|
{
|
||||||
|
if (args.Key == Key.Escape)
|
||||||
|
{
|
||||||
|
AbortConfirm();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return base.OnKeyUp(state, args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -39,6 +39,10 @@ namespace osu.Game.Screens.Menu
|
|||||||
|
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
|
new ExitConfirmOverlay
|
||||||
|
{
|
||||||
|
Action = Exit,
|
||||||
|
},
|
||||||
new ParallaxContainer
|
new ParallaxContainer
|
||||||
{
|
{
|
||||||
ParallaxAmount = 0.01f,
|
ParallaxAmount = 0.01f,
|
||||||
|
@ -1,50 +1,19 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 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.Allocation;
|
|
||||||
using System;
|
|
||||||
using osu.Framework.Graphics.Containers;
|
|
||||||
using osu.Framework.Graphics;
|
|
||||||
using osu.Framework.Graphics.Shapes;
|
|
||||||
using osu.Framework.Input.Bindings;
|
using osu.Framework.Input.Bindings;
|
||||||
using osu.Game.Input.Bindings;
|
using osu.Game.Input.Bindings;
|
||||||
using OpenTK.Graphics;
|
using osu.Game.Overlays;
|
||||||
|
|
||||||
namespace osu.Game.Screens.Play
|
namespace osu.Game.Screens.Play
|
||||||
{
|
{
|
||||||
public class HotkeyRetryOverlay : Container, IKeyBindingHandler<GlobalAction>
|
public class HotkeyRetryOverlay : HoldToConfirmOverlay, IKeyBindingHandler<GlobalAction>
|
||||||
{
|
{
|
||||||
public Action Action;
|
|
||||||
|
|
||||||
private Box overlay;
|
|
||||||
|
|
||||||
private const int activate_delay = 400;
|
|
||||||
private const int fadeout_delay = 200;
|
|
||||||
|
|
||||||
private bool fired;
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
|
||||||
private void load()
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both;
|
|
||||||
AlwaysPresent = true;
|
|
||||||
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
overlay = new Box
|
|
||||||
{
|
|
||||||
Alpha = 0,
|
|
||||||
Colour = Color4.Black,
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool OnPressed(GlobalAction action)
|
public bool OnPressed(GlobalAction action)
|
||||||
{
|
{
|
||||||
if (action != GlobalAction.QuickRetry) return false;
|
if (action != GlobalAction.QuickRetry) return false;
|
||||||
|
|
||||||
overlay.FadeIn(activate_delay, Easing.Out);
|
BeginConfirm();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,18 +21,8 @@ namespace osu.Game.Screens.Play
|
|||||||
{
|
{
|
||||||
if (action != GlobalAction.QuickRetry) return false;
|
if (action != GlobalAction.QuickRetry) return false;
|
||||||
|
|
||||||
overlay.FadeOut(fadeout_delay, Easing.Out);
|
AbortConfirm();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Update()
|
|
||||||
{
|
|
||||||
base.Update();
|
|
||||||
if (!fired && overlay.Alpha == 1)
|
|
||||||
{
|
|
||||||
fired = true;
|
|
||||||
Action?.Invoke();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -162,7 +162,7 @@ namespace osu.Game.Screens.Play
|
|||||||
hudOverlay.KeyCounter.IsCounting = pauseContainer.IsPaused;
|
hudOverlay.KeyCounter.IsCounting = pauseContainer.IsPaused;
|
||||||
},
|
},
|
||||||
OnResume = () => hudOverlay.KeyCounter.IsCounting = true,
|
OnResume = () => hudOverlay.KeyCounter.IsCounting = true,
|
||||||
Children = new Drawable[]
|
Children = new[]
|
||||||
{
|
{
|
||||||
storyboardContainer = new Container
|
storyboardContainer = new Container
|
||||||
{
|
{
|
||||||
@ -174,12 +174,12 @@ namespace osu.Game.Screens.Play
|
|||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Child = RulesetContainer
|
Child = RulesetContainer
|
||||||
},
|
},
|
||||||
new SkipOverlay(firstObjectTime)
|
new BreakOverlay(beatmap.BeatmapInfo.LetterboxInBreaks, scoreProcessor)
|
||||||
{
|
{
|
||||||
Clock = Clock, // skip button doesn't want to use the audio clock directly
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
ProcessCustomClock = false,
|
ProcessCustomClock = false,
|
||||||
AdjustableClock = adjustableClock,
|
Breaks = beatmap.Breaks
|
||||||
FramedClock = offsetClock,
|
|
||||||
},
|
},
|
||||||
hudOverlay = new HUDOverlay(scoreProcessor, RulesetContainer, working, offsetClock, adjustableClock)
|
hudOverlay = new HUDOverlay(scoreProcessor, RulesetContainer, working, offsetClock, adjustableClock)
|
||||||
{
|
{
|
||||||
@ -188,13 +188,14 @@ namespace osu.Game.Screens.Play
|
|||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre
|
Origin = Anchor.Centre
|
||||||
},
|
},
|
||||||
new BreakOverlay(beatmap.BeatmapInfo.LetterboxInBreaks, scoreProcessor)
|
RulesetContainer.Cursor?.CreateProxy() ?? new Container(),
|
||||||
|
new SkipOverlay(firstObjectTime)
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Clock = Clock, // skip button doesn't want to use the audio clock directly
|
||||||
Origin = Anchor.Centre,
|
|
||||||
ProcessCustomClock = false,
|
ProcessCustomClock = false,
|
||||||
Breaks = beatmap.Breaks
|
AdjustableClock = adjustableClock,
|
||||||
}
|
FramedClock = offsetClock,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
failOverlay = new FailOverlay
|
failOverlay = new FailOverlay
|
||||||
|
@ -85,11 +85,13 @@ namespace osu.Game.Screens.Play
|
|||||||
|
|
||||||
if (currentSecond != previousSecond && songCurrentTime < songLength)
|
if (currentSecond != previousSecond && songCurrentTime < songLength)
|
||||||
{
|
{
|
||||||
timeCurrent.Text = TimeSpan.FromSeconds(currentSecond).ToString(songCurrentTime < 0 ? @"\-m\:ss" : @"m\:ss");
|
timeCurrent.Text = formatTime(TimeSpan.FromSeconds(currentSecond));
|
||||||
timeLeft.Text = TimeSpan.FromMilliseconds(endTime - AudioClock.CurrentTime).ToString(@"\-m\:ss");
|
timeLeft.Text = formatTime(TimeSpan.FromMilliseconds(endTime - AudioClock.CurrentTime));
|
||||||
|
|
||||||
previousSecond = currentSecond;
|
previousSecond = currentSecond;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string formatTime(TimeSpan timeSpan) => $"{(timeSpan < TimeSpan.Zero ? "-" : "")}{timeSpan.Duration().TotalMinutes:N0}:{timeSpan.Duration().Seconds:D2}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -88,17 +88,27 @@ namespace osu.Game.Screens.Select
|
|||||||
|
|
||||||
private void loadBeatmap()
|
private void loadBeatmap()
|
||||||
{
|
{
|
||||||
|
void updateState()
|
||||||
|
{
|
||||||
|
State = beatmap == null ? Visibility.Hidden : Visibility.Visible;
|
||||||
|
|
||||||
|
Info?.FadeOut(250);
|
||||||
|
Info?.Expire();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (beatmap == null)
|
||||||
|
{
|
||||||
|
updateState();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
LoadComponentAsync(new BufferedWedgeInfo(beatmap, ruleset.Value)
|
LoadComponentAsync(new BufferedWedgeInfo(beatmap, ruleset.Value)
|
||||||
{
|
{
|
||||||
Shear = -Shear,
|
Shear = -Shear,
|
||||||
Depth = Info?.Depth + 1 ?? 0,
|
Depth = Info?.Depth + 1 ?? 0,
|
||||||
}, newInfo =>
|
}, newInfo =>
|
||||||
{
|
{
|
||||||
State = beatmap == null ? Visibility.Hidden : Visibility.Visible;
|
updateState();
|
||||||
|
|
||||||
Info?.FadeOut(250);
|
|
||||||
Info?.Expire();
|
|
||||||
|
|
||||||
Add(Info = newInfo);
|
Add(Info = newInfo);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user