1
0
mirror of https://github.com/ppy/osu.git synced 2026-05-14 00:03:18 +08:00

Compare commits

...

68 Commits

43 changed files with 1074 additions and 397 deletions
@@ -13,11 +13,12 @@ using osu.Game.Tests.Beatmaps;
namespace osu.Game.Rulesets.Catch.Tests
{
internal class CatchBeatmapConversionTest : BeatmapConversionTest<ConvertValue>
[TestFixture]
public class CatchBeatmapConversionTest : BeatmapConversionTest<ConvertValue>
{
protected override string ResourceAssembly => "osu.Game.Rulesets.Catch";
[TestCase("basic"), Ignore("See: https://github.com/ppy/osu/issues/2232")]
[TestCase("basic")]
[TestCase("spinner")]
[TestCase("spinner-and-circles")]
public new void Test(string name)
@@ -44,7 +45,7 @@ namespace osu.Game.Rulesets.Catch.Tests
protected override Ruleset CreateRuleset() => new CatchRuleset();
}
internal struct ConvertValue : IEquatable<ConvertValue>
public struct ConvertValue : IEquatable<ConvertValue>
{
/// <summary>
/// A sane value to account for osu!stable using ints everwhere.
@@ -26,6 +26,7 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
var positionData = obj as IHasXPosition;
var comboData = obj as IHasCombo;
var endTime = obj as IHasEndTime;
var legacyOffset = obj as IHasLegacyLastTickOffset;
if (curveData != null)
{
@@ -39,7 +40,8 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
RepeatSamples = curveData.RepeatSamples,
RepeatCount = curveData.RepeatCount,
X = (positionData?.X ?? 0) / CatchPlayfield.BASE_WIDTH,
NewCombo = comboData?.NewCombo ?? false
NewCombo = comboData?.NewCombo ?? false,
LegacyLastTickOffset = legacyOffset?.LegacyLastTickOffset ?? 0
};
}
else if (endTime != null)
@@ -77,6 +77,13 @@ namespace osu.Game.Rulesets.Catch.Objects
double time = spanStartTime + timeProgress * spanDuration;
if (LegacyLastTickOffset != null)
{
// If we're the last tick, apply the legacy offset
if (span == this.SpanCount() - 1 && d + tickDistance > length)
time = Math.Max(StartTime + Duration / 2, time - LegacyLastTickOffset.Value);
}
double tinyTickInterval = time - lastDropletTime;
while (tinyTickInterval > 100)
tinyTickInterval /= 2;
@@ -152,5 +159,7 @@ namespace osu.Game.Rulesets.Catch.Objects
get { return Curve.CurveType; }
set { Curve.CurveType = value; }
}
public double? LegacyLastTickOffset { get; set; }
}
}
@@ -12,7 +12,8 @@ using osu.Game.Tests.Beatmaps;
namespace osu.Game.Rulesets.Mania.Tests
{
internal class ManiaBeatmapConversionTest : BeatmapConversionTest<ConvertValue>
[TestFixture]
public class ManiaBeatmapConversionTest : BeatmapConversionTest<ConvertValue>
{
protected override string ResourceAssembly => "osu.Game.Rulesets.Mania";
@@ -36,7 +37,7 @@ namespace osu.Game.Rulesets.Mania.Tests
protected override Ruleset CreateRuleset() => new ManiaRuleset();
}
internal struct ConvertValue : IEquatable<ConvertValue>
public struct ConvertValue : IEquatable<ConvertValue>
{
/// <summary>
/// A sane value to account for osu!stable using ints everwhere.
@@ -8,17 +8,19 @@ using osu.Framework.MathUtils;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.UI;
using osu.Game.Tests.Beatmaps;
using OpenTK;
namespace osu.Game.Rulesets.Osu.Tests
{
internal class OsuBeatmapConversionTest : BeatmapConversionTest<ConvertValue>
[TestFixture]
public class OsuBeatmapConversionTest : BeatmapConversionTest<ConvertValue>
{
protected override string ResourceAssembly => "osu.Game.Rulesets.Osu";
[TestCase("basic")]
[TestCase("colinear-perfect-curve")]
[TestCase("slider-ticks")]
public new void Test(string name)
{
base.Test(name);
@@ -26,24 +28,30 @@ namespace osu.Game.Rulesets.Osu.Tests
protected override IEnumerable<ConvertValue> CreateConvertValue(HitObject hitObject)
{
var startPosition = (hitObject as IHasPosition)?.Position ?? new Vector2(256, 192);
var endPosition = (hitObject as Slider)?.EndPosition ?? startPosition;
yield return new ConvertValue
switch (hitObject)
{
StartTime = hitObject.StartTime,
EndTime = (hitObject as IHasEndTime)?.EndTime ?? hitObject.StartTime,
StartX = startPosition.X,
StartY = startPosition.Y,
EndX = endPosition.X,
EndY = endPosition.Y
case Slider slider:
foreach (var nested in slider.NestedHitObjects)
yield return createConvertValue(nested);
break;
default:
yield return createConvertValue(hitObject);
break;
}
ConvertValue createConvertValue(HitObject obj) => new ConvertValue
{
StartTime = obj.StartTime,
EndTime = (obj as IHasEndTime)?.EndTime ?? obj.StartTime,
X = (obj as IHasPosition)?.X ?? OsuPlayfield.BASE_SIZE.X / 2,
Y = (obj as IHasPosition)?.Y ?? OsuPlayfield.BASE_SIZE.Y / 2,
};
}
protected override Ruleset CreateRuleset() => new OsuRuleset();
}
internal struct ConvertValue : IEquatable<ConvertValue>
public struct ConvertValue : IEquatable<ConvertValue>
{
/// <summary>
/// A sane value to account for osu!stable using ints everwhere.
@@ -52,17 +60,13 @@ namespace osu.Game.Rulesets.Osu.Tests
public double StartTime;
public double EndTime;
public float StartX;
public float StartY;
public float EndX;
public float EndY;
public float X;
public float Y;
public bool Equals(ConvertValue other)
=> Precision.AlmostEquals(StartTime, other.StartTime)
=> Precision.AlmostEquals(StartTime, other.StartTime, conversion_lenience)
&& Precision.AlmostEquals(EndTime, other.EndTime, conversion_lenience)
&& Precision.AlmostEquals(StartX, other.StartX)
&& Precision.AlmostEquals(StartY, other.StartY, conversion_lenience)
&& Precision.AlmostEquals(EndX, other.EndX, conversion_lenience)
&& Precision.AlmostEquals(EndY, other.EndY, conversion_lenience);
&& Precision.AlmostEquals(X, other.X, conversion_lenience)
&& Precision.AlmostEquals(Y, other.Y, conversion_lenience);
}
}
@@ -27,6 +27,7 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
var endTimeData = original as IHasEndTime;
var positionData = original as IHasPosition;
var comboData = original as IHasCombo;
var legacyOffset = original as IHasLegacyLastTickOffset;
if (curveData != null)
{
@@ -40,7 +41,8 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
RepeatSamples = curveData.RepeatSamples,
RepeatCount = curveData.RepeatCount,
Position = positionData?.Position ?? Vector2.Zero,
NewCombo = comboData?.NewCombo ?? false
NewCombo = comboData?.NewCombo ?? false,
LegacyLastTickOffset = legacyOffset?.LegacyLastTickOffset
};
}
else if (endTimeData != null)
@@ -93,6 +93,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
base.AccentColour = value;
Body.AccentColour = AccentColour;
Ball.AccentColour = AccentColour;
if (HasNestedHitObjects)
foreach (var drawableHitObject in NestedHitObjects)
drawableHitObject.AccentColour = AccentColour;
}
}
+6
View File
@@ -1,6 +1,7 @@
// 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 OpenTK;
using osu.Game.Rulesets.Objects.Types;
using System.Collections.Generic;
@@ -45,6 +46,8 @@ namespace osu.Game.Rulesets.Osu.Objects
set { Curve.Distance = value; }
}
public double? LegacyLastTickOffset { get; set; }
/// <summary>
/// The position of the cursor at the point of completion of this <see cref="Slider"/> if it was hit
/// with as few movements as possible. This is set and used by difficulty calculation.
@@ -91,6 +94,9 @@ namespace osu.Game.Rulesets.Osu.Objects
createSliderEnds();
createTicks();
createRepeatPoints();
if (LegacyLastTickOffset != null)
TailCircle.StartTime = Math.Max(StartTime + Duration / 2, TailCircle.StartTime - LegacyLastTickOffset.Value);
}
private void createSliderEnds()
@@ -6,6 +6,7 @@ using osu.Game.Beatmaps;
using osu.Game.Rulesets.Osu.Objects;
using System;
using System.Collections.Generic;
using osu.Game.Rulesets.Osu.UI;
using osu.Game.Rulesets.Replays;
using osu.Game.Users;
@@ -18,7 +19,7 @@ namespace osu.Game.Rulesets.Osu.Replays
/// <summary>
/// Constants (for spinners).
/// </summary>
protected static readonly Vector2 SPINNER_CENTRE = new Vector2(256, 192);
protected static readonly Vector2 SPINNER_CENTRE = OsuPlayfield.BASE_SIZE / 2;
protected const float SPIN_RADIUS = 50;
/// <summary>
@@ -1,124 +1,256 @@
{
"Mappings": [{
"StartTime": 500,
"Objects": [{
"StartTime": 500,
"EndTime": 2500,
"StartX": 96,
"StartY": 192,
"EndX": 96,
"EndY": 192
}]
},
{
"StartTime": 3000,
"Objects": [{
"StartTime": 3000,
"EndTime": 4000,
"StartX": 256,
"StartY": 192,
"EndX": 256,
"EndY": 192
}]
},
{
"StartTime": 4500,
"Objects": [{
"StartTime": 4500,
"EndTime": 5500,
"StartX": 256,
"StartY": 192,
"EndX": 256,
"EndY": 192
}]
},
{
"StartTime": 6000,
"Objects": [{
"StartTime": 6000,
"EndTime": 6500,
"StartX": 256,
"StartY": 192,
"EndX": 256,
"EndY": 192
}]
},
{
"StartTime": 7000,
"Objects": [{
"StartTime": 7000,
"EndTime": 8000,
"StartX": 256,
"StartY": 128,
"EndX": 256,
"EndY": 128
}]
},
{
"StartTime": 8500,
"Objects": [{
"StartTime": 8500,
"EndTime": 10999,
"StartX": 32,
"StartY": 192,
"EndX": 508.166229,
"EndY": 153.299271
}]
},
{
"StartTime": 11500,
"Objects": [{
"StartTime": 11500,
"EndTime": 12000,
"StartX": 256,
"StartY": 192,
"EndX": 256,
"EndY": 192
}]
},
{
"StartTime": 12500,
"Objects": [{
"StartTime": 12500,
"EndTime": 16500,
"StartX": 512,
"StartY": 320,
"EndX": 291.1977,
"EndY": 40.799427
}]
},
{
"StartTime": 17000,
"Objects": [{
"StartTime": 17000,
"EndTime": 18000,
"StartX": 256,
"StartY": 256,
"EndX": 256,
"EndY": 256
}]
},
{
"StartTime": 18500,
"Objects": [{
"StartTime": 18500,
"EndTime": 19450,
"StartX": 256,
"StartY": 192,
"EndX": 256,
"EndY": 192
}]
},
{
"StartTime": 19875,
"Objects": [{
"StartTime": 19875,
"EndTime": 23874,
"StartX": 216,
"StartY": 231,
"EndX": 408.720825,
"EndY": 339.810455
}]
}
]
"StartTime": 500.0,
"Objects": [{
"StartTime": 500.0,
"EndTime": 500.0,
"X": 96.0,
"Y": 192.0
}, {
"StartTime": 1000.0,
"EndTime": 1000.0,
"X": 256.0,
"Y": 192.0
}, {
"StartTime": 1500.0,
"EndTime": 1500.0,
"X": 416.0,
"Y": 192.0
}, {
"StartTime": 2000.0,
"EndTime": 2000.0,
"X": 256.0,
"Y": 192.0
}, {
"StartTime": 2464.0,
"EndTime": 2464.0,
"X": 96.0,
"Y": 192.0
}]
}, {
"StartTime": 3000.0,
"Objects": [{
"StartTime": 3000.0,
"EndTime": 4000.0,
"X": 256.0,
"Y": 192.0
}]
}, {
"StartTime": 4500.0,
"Objects": [{
"StartTime": 4500.0,
"EndTime": 5500.0,
"X": 256.0,
"Y": 192.0
}]
}, {
"StartTime": 6000.0,
"Objects": [{
"StartTime": 6000.0,
"EndTime": 6500.0,
"X": 256.0,
"Y": 192.0
}]
}, {
"StartTime": 7000.0,
"Objects": [{
"StartTime": 7000.0,
"EndTime": 7000.0,
"X": 256.0,
"Y": 128.0
}, {
"StartTime": 7250.0,
"EndTime": 7250.0,
"X": 336.0,
"Y": 128.0
}, {
"StartTime": 7500.0,
"EndTime": 7500.0,
"X": 256.0,
"Y": 128.0
}, {
"StartTime": 7750.0,
"EndTime": 7750.0,
"X": 336.0,
"Y": 128.0
}, {
"StartTime": 7964.0,
"EndTime": 7964.0,
"X": 256.0,
"Y": 128.0
}]
}, {
"StartTime": 8500.0,
"Objects": [{
"StartTime": 8500.0,
"EndTime": 8500.0,
"X": 32.0,
"Y": 192.0
}, {
"StartTime": 9000.0,
"EndTime": 9000.0,
"X": 101.81015,
"Y": 326.4915
}, {
"StartTime": 9500.0,
"EndTime": 9500.0,
"X": 237.2304,
"Y": 276.282928
}, {
"StartTime": 10000.0,
"EndTime": 10000.0,
"X": 270.339874,
"Y": 121.1423
}, {
"StartTime": 10500.0,
"EndTime": 10500.0,
"X": 401.0588,
"Y": 49.1515045
}, {
"StartTime": 10964.0,
"EndTime": 10964.0,
"X": 508.166229,
"Y": 153.299271
}]
}, {
"StartTime": 11500.0,
"Objects": [{
"StartTime": 11500.0,
"EndTime": 12000.0,
"X": 256.0,
"Y": 192.0
}]
}, {
"StartTime": 12500.0,
"Objects": [{
"StartTime": 12500.0,
"EndTime": 12500.0,
"X": 512.0,
"Y": 320.0
}, {
"StartTime": 13000.0,
"EndTime": 13000.0,
"X": 353.235535,
"Y": 300.154449
}, {
"StartTime": 13500.0,
"EndTime": 13500.0,
"X": 194.471069,
"Y": 280.3089
}, {
"StartTime": 14000.0,
"EndTime": 14000.0,
"X": 35.7066345,
"Y": 260.463318
}, {
"StartTime": 14500.0,
"EndTime": 14500.0,
"X": 118.370323,
"Y": 219.009277
}, {
"StartTime": 15000.0,
"EndTime": 15000.0,
"X": 271.087128,
"Y": 171.285278
}, {
"StartTime": 15500.0,
"EndTime": 15500.0,
"X": 423.803925,
"Y": 123.561279
}, {
"StartTime": 16000.0,
"EndTime": 16000.0,
"X": 446.420532,
"Y": 79.60513
}, {
"StartTime": 16464.0,
"EndTime": 16464.0,
"X": 291.1977,
"Y": 40.799427
}]
}, {
"StartTime": 17000.0,
"Objects": [{
"StartTime": 17000.0,
"EndTime": 17000.0,
"X": 256.0,
"Y": 256.0
}, {
"StartTime": 17250.0,
"EndTime": 17250.0,
"X": 176.0,
"Y": 256.0
}, {
"StartTime": 17500.0,
"EndTime": 17500.0,
"X": 256.0,
"Y": 256.0
}, {
"StartTime": 17750.0,
"EndTime": 17750.0,
"X": 176.0,
"Y": 256.0
}, {
"StartTime": 17964.0,
"EndTime": 17964.0,
"X": 256.0,
"Y": 256.0
}]
}, {
"StartTime": 18500.0,
"Objects": [{
"StartTime": 18500.0,
"EndTime": 19450.0,
"X": 256.0,
"Y": 192.0
}]
}, {
"StartTime": 19875.0,
"Objects": [{
"StartTime": 19875.0,
"EndTime": 19875.0,
"X": 216.0,
"Y": 231.0
}, {
"StartTime": 20375.0,
"EndTime": 20375.0,
"X": 317.446747,
"Y": 171.345245
}, {
"StartTime": 20875.0,
"EndTime": 20875.0,
"X": 270.3294,
"Y": 310.4395
}, {
"StartTime": 21375.0,
"EndTime": 21375.0,
"X": 119.121056,
"Y": 322.8657
}, {
"StartTime": 21875.0,
"EndTime": 21875.0,
"X": 124.28746,
"Y": 165.224731
}, {
"StartTime": 22375.0,
"EndTime": 22375.0,
"X": 240.4715,
"Y": 62.65587
}, {
"StartTime": 22875.0,
"EndTime": 22875.0,
"X": 398.054047,
"Y": 39.064167
}, {
"StartTime": 23375.0,
"EndTime": 23375.0,
"X": 439.749878,
"Y": 183.668091
}, {
"StartTime": 23839.0,
"EndTime": 23839.0,
"X": 408.720825,
"Y": 339.810455
}]
}]
}
@@ -1,13 +1,16 @@
{
"Mappings": [{
"StartTime": 118858,
"Objects": [{
"StartTime": 118858,
"EndTime": 119088,
"StartX": 219,
"StartY": 215,
"EndX": 239.6507,
"EndY": 29.1437378
"Mappings": [{
"StartTime": 118858.0,
"Objects": [{
"StartTime": 118858.0,
"EndTime": 118858.0,
"X": 219.0,
"Y": 215.0
}, {
"StartTime": 119052.0,
"EndTime": 119052.0,
"X": 239.6507,
"Y": 29.1437378
}]
}]
}]
}
@@ -0,0 +1,331 @@
{
"Mappings": [{
"StartTime": 500.0,
"Objects": [{
"StartTime": 500.0,
"EndTime": 500.0,
"X": 96.0,
"Y": 192.0
}, {
"StartTime": 624.0,
"EndTime": 624.0,
"X": 105.921242,
"Y": 192.0
}, {
"StartTime": 749.0,
"EndTime": 749.0,
"X": 115.922493,
"Y": 192.0
}, {
"StartTime": 874.0,
"EndTime": 874.0,
"X": 125.923737,
"Y": 192.0
}, {
"StartTime": 999.0,
"EndTime": 999.0,
"X": 135.924988,
"Y": 192.0
}, {
"StartTime": 1124.0,
"EndTime": 1124.0,
"X": 145.926239,
"Y": 192.0
}, {
"StartTime": 1249.0,
"EndTime": 1249.0,
"X": 155.92749,
"Y": 192.0
}, {
"StartTime": 1374.0,
"EndTime": 1374.0,
"X": 165.928741,
"Y": 192.0
}, {
"StartTime": 1499.0,
"EndTime": 1499.0,
"X": 175.93,
"Y": 192.0
}, {
"StartTime": 1624.0,
"EndTime": 1624.0,
"X": 185.931244,
"Y": 192.0
}, {
"StartTime": 1749.0,
"EndTime": 1749.0,
"X": 195.9325,
"Y": 192.0
}, {
"StartTime": 1874.0,
"EndTime": 1874.0,
"X": 205.933746,
"Y": 192.0
}, {
"StartTime": 1999.0,
"EndTime": 1999.0,
"X": 215.935,
"Y": 192.0
}, {
"StartTime": 2124.0,
"EndTime": 2124.0,
"X": 225.936234,
"Y": 192.0
}, {
"StartTime": 2249.0,
"EndTime": 2249.0,
"X": 235.9375,
"Y": 192.0
}, {
"StartTime": 2374.0,
"EndTime": 2374.0,
"X": 245.938751,
"Y": 192.0
}, {
"StartTime": 2499.0,
"EndTime": 2499.0,
"X": 255.94,
"Y": 192.0
}, {
"StartTime": 2624.0,
"EndTime": 2624.0,
"X": 265.941223,
"Y": 192.0
}, {
"StartTime": 2749.0,
"EndTime": 2749.0,
"X": 275.9425,
"Y": 192.0
}, {
"StartTime": 2874.0,
"EndTime": 2874.0,
"X": 285.943756,
"Y": 192.0
}, {
"StartTime": 2999.0,
"EndTime": 2999.0,
"X": 295.945,
"Y": 192.0
}, {
"StartTime": 3124.0,
"EndTime": 3124.0,
"X": 305.946259,
"Y": 192.0
}, {
"StartTime": 3249.0,
"EndTime": 3249.0,
"X": 315.9475,
"Y": 192.0
}, {
"StartTime": 3374.0,
"EndTime": 3374.0,
"X": 325.94873,
"Y": 192.0
}, {
"StartTime": 3499.0,
"EndTime": 3499.0,
"X": 335.949982,
"Y": 192.0
}, {
"StartTime": 3624.0,
"EndTime": 3624.0,
"X": 345.951233,
"Y": 192.0
}, {
"StartTime": 3749.0,
"EndTime": 3749.0,
"X": 355.952484,
"Y": 192.0
}, {
"StartTime": 3874.0,
"EndTime": 3874.0,
"X": 365.953766,
"Y": 192.0
}, {
"StartTime": 3999.0,
"EndTime": 3999.0,
"X": 375.955,
"Y": 192.0
}, {
"StartTime": 4124.0,
"EndTime": 4124.0,
"X": 385.956238,
"Y": 192.0
}, {
"StartTime": 4249.0,
"EndTime": 4249.0,
"X": 395.9575,
"Y": 192.0
}, {
"StartTime": 4374.0,
"EndTime": 4374.0,
"X": 405.95874,
"Y": 192.0
}, {
"StartTime": 4499.0,
"EndTime": 4499.0,
"X": 415.960022,
"Y": 192.0
}, {
"StartTime": 4624.0,
"EndTime": 4624.0,
"X": 406.038757,
"Y": 192.0
}, {
"StartTime": 4749.0,
"EndTime": 4749.0,
"X": 396.0375,
"Y": 192.0
}, {
"StartTime": 4874.0,
"EndTime": 4874.0,
"X": 386.036255,
"Y": 192.0
}, {
"StartTime": 4999.0,
"EndTime": 4999.0,
"X": 376.035034,
"Y": 192.0
}, {
"StartTime": 5124.0,
"EndTime": 5124.0,
"X": 366.033752,
"Y": 192.0
}, {
"StartTime": 5249.0,
"EndTime": 5249.0,
"X": 356.0325,
"Y": 192.0
}, {
"StartTime": 5374.0,
"EndTime": 5374.0,
"X": 346.03125,
"Y": 192.0
}, {
"StartTime": 5499.0,
"EndTime": 5499.0,
"X": 336.030029,
"Y": 192.0
}, {
"StartTime": 5624.0,
"EndTime": 5624.0,
"X": 326.028748,
"Y": 192.0
}, {
"StartTime": 5749.0,
"EndTime": 5749.0,
"X": 316.0275,
"Y": 192.0
}, {
"StartTime": 5874.0,
"EndTime": 5874.0,
"X": 306.026245,
"Y": 192.0
}, {
"StartTime": 5999.0,
"EndTime": 5999.0,
"X": 296.025,
"Y": 192.0
}, {
"StartTime": 6124.0,
"EndTime": 6124.0,
"X": 286.023773,
"Y": 192.0
}, {
"StartTime": 6249.0,
"EndTime": 6249.0,
"X": 276.022522,
"Y": 192.0
}, {
"StartTime": 6374.0,
"EndTime": 6374.0,
"X": 266.02124,
"Y": 192.0
}, {
"StartTime": 6499.0,
"EndTime": 6499.0,
"X": 256.02,
"Y": 192.0
}, {
"StartTime": 6624.0,
"EndTime": 6624.0,
"X": 246.018768,
"Y": 192.0
}, {
"StartTime": 6749.0,
"EndTime": 6749.0,
"X": 236.017517,
"Y": 192.0
}, {
"StartTime": 6874.0,
"EndTime": 6874.0,
"X": 226.016251,
"Y": 192.0
}, {
"StartTime": 6999.0,
"EndTime": 6999.0,
"X": 216.014984,
"Y": 192.0
}, {
"StartTime": 7124.0,
"EndTime": 7124.0,
"X": 206.013733,
"Y": 192.0
}, {
"StartTime": 7249.0,
"EndTime": 7249.0,
"X": 196.012512,
"Y": 192.0
}, {
"StartTime": 7374.0,
"EndTime": 7374.0,
"X": 186.011261,
"Y": 192.0
}, {
"StartTime": 7499.0,
"EndTime": 7499.0,
"X": 176.01,
"Y": 192.0
}, {
"StartTime": 7624.0,
"EndTime": 7624.0,
"X": 166.008728,
"Y": 192.0
}, {
"StartTime": 7749.0,
"EndTime": 7749.0,
"X": 156.0075,
"Y": 192.0
}, {
"StartTime": 7874.0,
"EndTime": 7874.0,
"X": 146.006256,
"Y": 192.0
}, {
"StartTime": 7999.0,
"EndTime": 7999.0,
"X": 136.005,
"Y": 192.0
}, {
"StartTime": 8124.0,
"EndTime": 8124.0,
"X": 126.003738,
"Y": 192.0
}, {
"StartTime": 8249.0,
"EndTime": 8249.0,
"X": 116.002518,
"Y": 192.0
}, {
"StartTime": 8374.0,
"EndTime": 8374.0,
"X": 106.001259,
"Y": 192.0
}, {
"StartTime": 8463.0,
"EndTime": 8463.0,
"X": 96.0,
"Y": 192.0
}]
}]
}
@@ -0,0 +1,20 @@
osu file format v14
[General]
StackLeniency: 0.7
[Difficulty]
HPDrainRate:6
CircleSize:4
OverallDifficulty:7
ApproachRate:8.3
SliderMultiplier:0.400000005960464
SliderTickRate:4
[TimingPoints]
500,500,4,2,1,50,1,0
13426,-100,4,3,1,45,0,0
14884,-100,4,2,1,50,0,0
[HitObjects]
96,192,500,6,0,L|416:192,2,320.000004768372
@@ -12,7 +12,8 @@ using osu.Game.Tests.Beatmaps;
namespace osu.Game.Rulesets.Taiko.Tests
{
internal class TaikoBeatmapConversionTest : BeatmapConversionTest<ConvertValue>
[TestFixture]
public class TaikoBeatmapConversionTest : BeatmapConversionTest<ConvertValue>
{
protected override string ResourceAssembly => "osu.Game.Rulesets.Taiko";
@@ -41,7 +42,7 @@ namespace osu.Game.Rulesets.Taiko.Tests
protected override Ruleset CreateRuleset() => new TaikoRuleset();
}
internal struct ConvertValue : IEquatable<ConvertValue>
public struct ConvertValue : IEquatable<ConvertValue>
{
/// <summary>
/// A sane value to account for osu!stable using ints everwhere.
@@ -1,8 +1,7 @@
// 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 NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
@@ -10,9 +9,6 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Edit.Tools;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Tests.Beatmaps;
using OpenTK;
@@ -20,10 +16,9 @@ using OpenTK.Graphics;
namespace osu.Game.Tests.Visual
{
[TestFixture]
public class TestCaseEditorSeekSnapping : EditorClockTestCase
{
public override IReadOnlyList<Type> RequiredTypes => new[] { typeof(HitObjectComposer) };
public TestCaseEditorSeekSnapping()
{
BeatDivisor.Value = 4;
@@ -56,22 +51,13 @@ namespace osu.Game.Tests.Visual
Beatmap.Value = new TestWorkingBeatmap(testBeatmap);
Child = new TimingPointVisualiser(testBeatmap, 5000) { Clock = Clock };
testSeekNoSnapping();
testSeekSnappingOnBeat();
testSeekSnappingInBetweenBeat();
testSeekForwardNoSnapping();
testSeekForwardSnappingOnBeat();
testSeekForwardSnappingFromInBetweenBeat();
testSeekBackwardSnappingOnBeat();
testSeekBackwardSnappingFromInBetweenBeat();
testSeekingWithFloatingPointBeatLength();
}
/// <summary>
/// Tests whether time is correctly seeked without snapping.
/// </summary>
private void testSeekNoSnapping()
[Test]
public void TestSeekNoSnapping()
{
reset();
@@ -94,7 +80,8 @@ namespace osu.Game.Tests.Visual
/// Tests whether seeking to exact beat times puts us on the beat time.
/// These are the white/yellow ticks on the graph.
/// </summary>
private void testSeekSnappingOnBeat()
[Test]
public void TestSeekSnappingOnBeat()
{
reset();
@@ -117,9 +104,9 @@ namespace osu.Game.Tests.Visual
/// <summary>
/// Tests whether seeking to somewhere in the middle between beats puts us on the expected beats.
/// For example, snapping between a white/yellow beat should put us on either the yellow or white, depending on which one we're closer too.
/// If
/// </summary>
private void testSeekSnappingInBetweenBeat()
[Test]
public void TestSeekSnappingInBetweenBeat()
{
reset();
@@ -140,7 +127,8 @@ namespace osu.Game.Tests.Visual
/// <summary>
/// Tests that when seeking forward with no beat snapping, beats are never explicitly snapped to, nor the next timing point (if we've skipped it).
/// </summary>
private void testSeekForwardNoSnapping()
[Test]
public void TestSeekForwardNoSnapping()
{
reset();
@@ -159,7 +147,8 @@ namespace osu.Game.Tests.Visual
/// <summary>
/// Tests that when seeking forward with beat snapping, all beats are snapped to and timing points are never skipped.
/// </summary>
private void testSeekForwardSnappingOnBeat()
[Test]
public void TestSeekForwardSnappingOnBeat()
{
reset();
@@ -181,7 +170,8 @@ namespace osu.Game.Tests.Visual
/// Tests that when seeking forward from in-between two beats, the next beat or timing point is snapped to, and no beats are skipped.
/// This will also test being extremely close to the next beat/timing point, to ensure rounding is not an issue.
/// </summary>
private void testSeekForwardSnappingFromInBetweenBeat()
[Test]
public void TestSeekForwardSnappingFromInBetweenBeat()
{
reset();
@@ -214,21 +204,20 @@ namespace osu.Game.Tests.Visual
/// <summary>
/// Tests that when seeking backward with no beat snapping, beats are never explicitly snapped to, nor the next timing point (if we've skipped it).
/// </summary>
private void testSeekBackwardNoSnapping()
[Test]
public void TestSeekBackwardNoSnapping()
{
reset();
AddStep("Seek(450)", () => Clock.Seek(450));
AddStep("SeekBackward", () => Clock.SeekBackward());
AddAssert("Time = 425", () => Clock.CurrentTime == 425);
AddAssert("Time = 400", () => Clock.CurrentTime == 400);
AddStep("SeekBackward", () => Clock.SeekBackward());
AddAssert("Time = 375", () => Clock.CurrentTime == 375);
AddAssert("Time = 350", () => Clock.CurrentTime == 350);
AddStep("SeekBackward", () => Clock.SeekBackward());
AddAssert("Time = 325", () => Clock.CurrentTime == 325);
AddAssert("Time = 150", () => Clock.CurrentTime == 150);
AddStep("SeekBackward", () => Clock.SeekBackward());
AddAssert("Time = 125", () => Clock.CurrentTime == 125);
AddStep("SeekBackward", () => Clock.SeekBackward());
AddAssert("Time = 25", () => Clock.CurrentTime == 25);
AddAssert("Time = 50", () => Clock.CurrentTime == 50);
AddStep("SeekBackward", () => Clock.SeekBackward());
AddAssert("Time = 0", () => Clock.CurrentTime == 0);
}
@@ -236,7 +225,8 @@ namespace osu.Game.Tests.Visual
/// <summary>
/// Tests that when seeking backward with beat snapping, all beats are snapped to and timing points are never skipped.
/// </summary>
private void testSeekBackwardSnappingOnBeat()
[Test]
public void TestSeekBackwardSnappingOnBeat()
{
reset();
@@ -259,7 +249,8 @@ namespace osu.Game.Tests.Visual
/// Tests that when seeking backward from in-between two beats, the previous beat or timing point is snapped to, and no beats are skipped.
/// This will also test being extremely close to the previous beat/timing point, to ensure rounding is not an issue.
/// </summary>
private void testSeekBackwardSnappingFromInBetweenBeat()
[Test]
public void TestSeekBackwardSnappingFromInBetweenBeat()
{
reset();
@@ -280,7 +271,8 @@ namespace osu.Game.Tests.Visual
/// <summary>
/// Tests that there are no rounding issues when snapping to beats within a timing point with a floating-point beatlength.
/// </summary>
private void testSeekingWithFloatingPointBeatLength()
[Test]
public void TestSeekingWithFloatingPointBeatLength()
{
reset();
@@ -288,7 +280,7 @@ namespace osu.Game.Tests.Visual
AddStep("Seek(0)", () => Clock.Seek(0));
for (int i = 0; i < 20; i++)
for (int i = 0; i < 9; i++)
{
AddStep("SeekForward, Snap", () =>
{
@@ -298,7 +290,7 @@ namespace osu.Game.Tests.Visual
AddAssert("Time > lastTime", () => Clock.CurrentTime > lastTime);
}
for (int i = 0; i < 20; i++)
for (int i = 0; i < 9; i++)
{
AddStep("SeekBackward, Snap", () =>
{
@@ -316,16 +308,6 @@ namespace osu.Game.Tests.Visual
AddStep("Reset", () => Clock.Seek(0));
}
private class TestHitObjectComposer : HitObjectComposer
{
public TestHitObjectComposer(Ruleset ruleset)
: base(ruleset)
{
}
protected override IReadOnlyList<ICompositionTool> CompositionTools => new ICompositionTool[0];
}
private class TimingPointVisualiser : CompositeDrawable
{
private readonly double length;
@@ -1,6 +1,8 @@
// 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 System.ComponentModel;
using osu.Framework.Graphics;
using osu.Game.Rulesets.Scoring;
@@ -17,6 +19,12 @@ namespace osu.Game.Tests.Visual
[Description("PlaySongSelect leaderboard")]
public class TestCaseLeaderboard : OsuTestCase
{
public override IReadOnlyList<Type> RequiredTypes => new[] {
typeof(Placeholder),
typeof(MessagePlaceholder),
typeof(RetrievalFailurePlaceholder),
};
private RulesetStore rulesets;
private readonly FailableLeaderboard leaderboard;
@@ -0,0 +1,63 @@
// 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.Graphics;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Testing;
using osu.Game.Graphics.UserInterface;
using OpenTK.Graphics;
namespace osu.Game.Tests.Visual
{
public class TestCaseLoadingAnimation : GridTestCase
{
public TestCaseLoadingAnimation()
: base(2, 2)
{
LoadingAnimation loading;
Cell(0).AddRange(new Drawable[]
{
new Box
{
Colour = Color4.Black,
RelativeSizeAxes = Axes.Both
},
loading = new LoadingAnimation()
});
loading.Show();
Cell(1).AddRange(new Drawable[]
{
new Box
{
Colour = Color4.White,
RelativeSizeAxes = Axes.Both
},
loading = new LoadingAnimation()
});
loading.Show();
Cell(2).AddRange(new Drawable[]
{
new Box
{
Colour = Color4.Gray,
RelativeSizeAxes = Axes.Both
},
loading = new LoadingAnimation()
});
loading.Show();
Cell(3).AddRange(new Drawable[]
{
loading = new LoadingAnimation()
});
Scheduler.AddDelayed(() => loading.ToggleVisibility(), 200, true);
}
}
}
+1 -1
View File
@@ -138,7 +138,7 @@ namespace osu.Game.Beatmaps
PostNotification?.Invoke(new SimpleNotification
{
Icon = FontAwesome.fa_superpowers,
Text = "You gotta be a supporter to download for now 'yo"
Text = "You gotta be an osu!supporter to download for now 'yo"
});
return;
}
@@ -69,11 +69,22 @@ namespace osu.Game.Beatmaps
}
catch
{
return new TrackVirtual();
return null;
}
}
protected override Waveform GetWaveform() => new Waveform(store.GetStream(getPathForFile(Metadata.AudioFile)));
protected override Waveform GetWaveform()
{
try
{
var trackData = store.GetStream(getPathForFile(Metadata.AudioFile));
return trackData == null ? null : new Waveform(trackData);
}
catch
{
return null;
}
}
protected override Storyboard GetStoryboard()
{
+1 -1
View File
@@ -45,7 +45,7 @@ namespace osu.Game.Beatmaps
protected override Texture GetBackground() => game?.Textures.Get(@"Backgrounds/bg4");
protected override Track GetTrack() => new TrackVirtual();
protected override Track GetTrack() => new TrackVirtual { Length = 1000 };
private class DummyRulesetInfo : RulesetInfo
{
+2 -2
View File
@@ -19,7 +19,7 @@ using osu.Game.Skinning;
namespace osu.Game.Beatmaps
{
public abstract class WorkingBeatmap : IDisposable
public abstract partial class WorkingBeatmap : IDisposable
{
public readonly BeatmapInfo BeatmapInfo;
@@ -145,7 +145,7 @@ namespace osu.Game.Beatmaps
private Track populateTrack()
{
// we want to ensure that we always have a track, even if it's a fake one.
var t = GetTrack() ?? new TrackVirtual();
var t = GetTrack() ?? new VirtualBeatmapTrack(Beatmap);
applyRateAdjustments(t);
return t;
}
@@ -0,0 +1,38 @@
// 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.Linq;
using osu.Framework.Audio.Track;
using osu.Game.Rulesets.Objects.Types;
namespace osu.Game.Beatmaps
{
public partial class WorkingBeatmap
{
/// <summary>
/// A type of <see cref="TrackVirtual"/> which provides a valid length based on the <see cref="HitObject"/>s of an <see cref="IBeatmap"/>.
/// </summary>
protected class VirtualBeatmapTrack : TrackVirtual
{
private const double excess_length = 1000;
public VirtualBeatmapTrack(IBeatmap beatmap)
{
var lastObject = beatmap.HitObjects.LastOrDefault();
switch (lastObject)
{
case null:
Length = excess_length;
break;
case IHasEndTime endTime:
Length = endTime.EndTime + excess_length;
break;
default:
Length = lastObject.StartTime + excess_length;
break;
}
}
}
}
}
@@ -2,6 +2,7 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics.Sprites;
@@ -16,6 +17,8 @@ namespace osu.Game.Graphics.Containers
protected override SpriteText CreateSpriteText() => new OsuSpriteText();
public void AddArbitraryDrawable(Drawable drawable) => AddInternal(drawable);
public void AddIcon(FontAwesome icon, Action<SpriteText> creationParameters = null) => AddText(((char)icon).ToString(), creationParameters);
}
}
+7 -5
View File
@@ -12,14 +12,14 @@ namespace osu.Game.Graphics
{
public class DrawableDate : OsuSpriteText, IHasTooltip
{
private readonly DateTimeOffset date;
protected readonly DateTimeOffset Date;
public DrawableDate(DateTimeOffset date)
{
AutoSizeAxes = Axes.Both;
Font = "Exo2.0-RegularItalic";
this.date = date.ToLocalTime();
Date = date.ToLocalTime();
}
[BackgroundDependencyLoader]
@@ -38,7 +38,7 @@ namespace osu.Game.Graphics
{
updateTime();
var diffToNow = DateTimeOffset.Now.Subtract(date);
var diffToNow = DateTimeOffset.Now.Subtract(Date);
double timeUntilNextUpdate = 1000;
if (diffToNow.TotalSeconds > 60)
@@ -58,8 +58,10 @@ namespace osu.Game.Graphics
public override bool HandleMouseInput => true;
private void updateTime() => Text = date.Humanize();
protected virtual string Format() => Date.Humanize();
public string TooltipText => date.ToString();
private void updateTime() => Text = Format();
public virtual string TooltipText => string.Format($"{Date:MMMM d, yyyy h:mm tt \"UTC\"z}");
}
}
@@ -4,12 +4,17 @@
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using OpenTK;
using OpenTK.Graphics;
namespace osu.Game.Graphics.UserInterface
{
public class LoadingAnimation : VisibilityContainer
{
private readonly SpriteIcon spinner;
private readonly SpriteIcon spinnerShadow;
private const float spin_duration = 600;
private const float transition_duration = 200;
public LoadingAnimation()
{
@@ -20,12 +25,22 @@ namespace osu.Game.Graphics.UserInterface
Children = new Drawable[]
{
spinner = new SpriteIcon
spinnerShadow = new SpriteIcon
{
Size = new Vector2(20),
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Icon = FontAwesome.fa_spinner
RelativeSizeAxes = Axes.Both,
Position = new Vector2(1, 1),
Colour = Color4.Black,
Alpha = 0.4f,
Icon = FontAwesome.fa_circle_o_notch
},
spinner = new SpriteIcon
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Icon = FontAwesome.fa_circle_o_notch
}
};
}
@@ -34,12 +49,11 @@ namespace osu.Game.Graphics.UserInterface
{
base.LoadComplete();
spinner.Spin(2000, RotationDirection.Clockwise);
spinner.Spin(spin_duration, RotationDirection.Clockwise);
spinnerShadow.Spin(spin_duration, RotationDirection.Clockwise);
}
private const float transition_duration = 500;
protected override void PopIn() => this.FadeIn(transition_duration * 5, Easing.OutQuint);
protected override void PopIn() => this.FadeIn(transition_duration * 2, Easing.OutQuint);
protected override void PopOut() => this.FadeOut(transition_duration, Easing.OutQuint);
}
+11 -1
View File
@@ -10,6 +10,7 @@ using osu.Game.Audio;
using osu.Game.Beatmaps;
using osu.Game.Graphics;
using osu.Game.Graphics.UserInterface;
using OpenTK;
using OpenTK.Graphics;
namespace osu.Game.Overlays.Direct
@@ -48,9 +49,15 @@ namespace osu.Game.Overlays.Direct
set
{
if (value)
{
icon.FadeTo(0.5f, transition_duration, Easing.OutQuint);
loadingAnimation.Show();
}
else
{
icon.FadeTo(1, transition_duration, Easing.OutQuint);
loadingAnimation.Hide();
}
}
}
@@ -67,7 +74,10 @@ namespace osu.Game.Overlays.Direct
RelativeSizeAxes = Axes.Both,
Icon = FontAwesome.fa_play,
},
loadingAnimation = new LoadingAnimation(),
loadingAnimation = new LoadingAnimation
{
Size = new Vector2(15),
},
});
Playing.ValueChanged += playingStateChanged;
@@ -0,0 +1,20 @@
// 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.Game.Graphics;
namespace osu.Game.Overlays.Profile.Components
{
public class DrawableJoinDate : DrawableDate
{
public DrawableJoinDate(DateTimeOffset date)
: base(date)
{
}
protected override string Format() => Text = Date.ToUniversalTime().Year < 2008 ? "Here since the beginning" : $"{Date:MMMM yyyy}";
public override string TooltipText => $"{Date:MMMM d, yyyy}";
}
}
@@ -0,0 +1,50 @@
// 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.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
using osu.Game.Graphics.Sprites;
namespace osu.Game.Overlays.Profile.Components
{
public class GradeBadge : Container
{
private const float width = 50;
private readonly string grade;
private readonly Sprite badge;
private readonly SpriteText numberText;
public int DisplayCount
{
set => numberText.Text = value.ToString(@"#,0");
}
public GradeBadge(string grade)
{
this.grade = grade;
Width = width;
Height = 41;
Add(badge = new Sprite
{
Width = width,
Height = 26
});
Add(numberText = new OsuSpriteText
{
Anchor = Anchor.BottomCentre,
Origin = Anchor.BottomCentre,
TextSize = 14,
Font = @"Exo2.0-Bold"
});
}
[BackgroundDependencyLoader]
private void load(TextureStore textures)
{
badge.Texture = textures.Get($"Grades/{grade}");
}
}
}
+3 -40
View File
@@ -16,6 +16,7 @@ using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
using osu.Game.Overlays.Profile.Components;
using osu.Game.Overlays.Profile.Header;
using osu.Game.Users;
@@ -375,12 +376,12 @@ namespace osu.Game.Overlays.Profile
if (user.JoinDate.ToUniversalTime().Year < 2008)
{
infoTextLeft.AddText("Here since the beginning", boldItalic);
infoTextLeft.AddText(new DrawableJoinDate(user.JoinDate), lightText);
}
else
{
infoTextLeft.AddText("Joined ", lightText);
infoTextLeft.AddText(new DrawableDate(user.JoinDate), boldItalic);
infoTextLeft.AddText(new DrawableJoinDate(user.JoinDate), boldItalic);
}
infoTextLeft.NewLine();
@@ -470,43 +471,5 @@ namespace osu.Game.Overlays.Profile
infoTextRight.NewLine();
}
private class GradeBadge : Container
{
private const float width = 50;
private readonly string grade;
private readonly Sprite badge;
private readonly SpriteText numberText;
public int DisplayCount
{
set { numberText.Text = value.ToString(@"#,0"); }
}
public GradeBadge(string grade)
{
this.grade = grade;
Width = width;
Height = 41;
Add(badge = new Sprite
{
Width = width,
Height = 26
});
Add(numberText = new OsuSpriteText
{
Anchor = Anchor.BottomCentre,
Origin = Anchor.BottomCentre,
TextSize = 14,
Font = @"Exo2.0-Bold"
});
}
[BackgroundDependencyLoader]
private void load(TextureStore textures)
{
badge.Texture = textures.Get($"Grades/{grade}");
}
}
}
}
@@ -141,11 +141,11 @@ namespace osu.Game.Overlays.Profile.Sections.Recent
break;
case RecentActivityType.UserSupportFirst:
message = $"{userLinkTemplate()} has become an osu! supporter - thanks for your generosity!";
message = $"{userLinkTemplate()} has become an osu!supporter - thanks for your generosity!";
break;
case RecentActivityType.UserSupportGift:
message = $"{userLinkTemplate()} has received the gift of osu! supporter!";
message = $"{userLinkTemplate()} has received the gift of osu!supporter!";
break;
case RecentActivityType.UsernameChange:
@@ -10,7 +10,7 @@ using osu.Game.Beatmaps.ControlPoints;
namespace osu.Game.Rulesets.Objects.Legacy
{
internal abstract class ConvertSlider : HitObject, IHasCurve
internal abstract class ConvertSlider : HitObject, IHasCurve, IHasLegacyLastTickOffset
{
/// <summary>
/// Scoring distance with a speed-adjusted beat length of 1 second.
@@ -45,5 +45,7 @@ namespace osu.Game.Rulesets.Objects.Legacy
Velocity = scoringDistance / timingPoint.BeatLength;
}
public double LegacyLastTickOffset => 36;
}
}
@@ -0,0 +1,14 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
namespace osu.Game.Rulesets.Objects.Types
{
/// <summary>
/// A type of <see cref="HitObject"/> which may require the last tick to be offset.
/// This is specific to osu!stable conversion, and should not be used elsewhere.
/// </summary>
public interface IHasLegacyLastTickOffset
{
double LegacyLastTickOffset { get; }
}
}
+4 -3
View File
@@ -84,10 +84,11 @@ namespace osu.Game.Rulesets
{
try
{
var instance = r.CreateInstance();
var instanceInfo = ((Ruleset)Activator.CreateInstance(Type.GetType(r.InstantiationInfo), (RulesetInfo)null)).RulesetInfo;
r.Name = instance.Description;
r.ShortName = instance.ShortName;
r.Name = instanceInfo.Name;
r.ShortName = instanceInfo.ShortName;
r.InstantiationInfo = instanceInfo.InstantiationInfo;
r.Available = true;
}
@@ -52,8 +52,6 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts
if (Beatmap.Value == null)
return;
if (Beatmap.Value.Track.Length == double.PositiveInfinity) return;
float markerPos = MathHelper.Clamp(ToLocalSpace(screenPosition).X, 0, DrawWidth);
adjustableClock.Seek(markerPos / DrawWidth * Beatmap.Value.Track.Length);
}
@@ -47,8 +47,7 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts
return;
}
// Todo: This should be handled more gracefully
timeline.RelativeChildSize = Beatmap.Value.Track.Length == double.PositiveInfinity ? Vector2.One : new Vector2((float)Math.Max(1, Beatmap.Value.Track.Length), 1);
timeline.RelativeChildSize = new Vector2((float)Math.Max(1, Beatmap.Value.Track.Length), 1);
}
protected void Add(Drawable visualisation) => timeline.Add(visualisation);
@@ -52,17 +52,20 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline
WaveformVisible.ValueChanged += visible => waveform.FadeTo(visible ? 1 : 0, 200, Easing.OutQuint);
Beatmap.BindTo(beatmap);
}
protected override void LoadComplete()
{
base.LoadComplete();
Beatmap.BindValueChanged(b => waveform.Waveform = b.Waveform);
waveform.Waveform = Beatmap.Value.Waveform;
Beatmap.BindValueChanged(b =>
{
waveform.Waveform = b.Waveform;
track = b.Track;
}, true);
}
/// <summary>
/// The track's time in the previous frame.
/// The timeline's scroll position in the last frame.
/// </summary>
private float lastScrollPosition;
/// <summary>
/// The track time in the last frame.
/// </summary>
private double lastTrackTime;
@@ -76,6 +79,8 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline
/// </summary>
private bool trackWasPlaying;
private Track track;
protected override void Update()
{
base.Update();
@@ -83,49 +88,48 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline
// The extrema of track time should be positioned at the centre of the container when scrolled to the start or end
Content.Margin = new MarginPadding { Horizontal = DrawWidth / 2 };
if (handlingDragInput)
{
// The user is dragging - the track should always follow the timeline
seekTrackToCurrent();
}
else if (adjustableClock.IsRunning)
{
// If the user hasn't provided mouse input but the track is running, always follow the track
// This needs to happen after transforms are updated, but before the scroll position is updated in base.UpdateAfterChildren
if (adjustableClock.IsRunning)
scrollToTrackTime();
}
else
}
protected override void UpdateAfterChildren()
{
base.UpdateAfterChildren();
if (handlingDragInput)
seekTrackToCurrent();
else if (!adjustableClock.IsRunning)
{
// The track isn't playing, so we want to smooth-scroll once more, and re-enable wheel scrolling
// There are two cases we have to be wary of:
// 1) The user scrolls on this timeline: We want the track to follow us
// The track isn't running. There are two cases we have to be wary of:
// 1) The user flick-drags on this timeline: We want the track to follow us
// 2) The user changes the track time through some other means (scrolling in the editor or overview timeline): We want to follow the track time
// The simplest way to cover both cases is by checking that inter-frame track times are identical
if (adjustableClock.CurrentTime == lastTrackTime)
{
// The track hasn't been seeked externally
// The simplest way to cover both cases is by checking whether the scroll position has changed and the audio hasn't been changed externally
if (Current != lastScrollPosition && adjustableClock.CurrentTime == lastTrackTime)
seekTrackToCurrent();
}
else
{
// The track has been seeked externally
scrollToTrackTime();
}
}
lastScrollPosition = Current;
lastTrackTime = adjustableClock.CurrentTime;
}
void seekTrackToCurrent()
{
if (!(Beatmap.Value.Track is TrackVirtual))
adjustableClock.Seek(Current / Content.DrawWidth * Beatmap.Value.Track.Length);
}
private void seekTrackToCurrent()
{
if (!track.IsLoaded)
return;
void scrollToTrackTime()
{
if (!(Beatmap.Value.Track is TrackVirtual))
ScrollTo((float)(adjustableClock.CurrentTime / Beatmap.Value.Track.Length) * Content.DrawWidth, false);
}
adjustableClock.Seek(Current / Content.DrawWidth * track.Length);
}
private void scrollToTrackTime()
{
if (!track.IsLoaded)
return;
ScrollTo((float)(adjustableClock.CurrentTime / track.Length) * Content.DrawWidth, false);
}
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
@@ -146,7 +146,7 @@ namespace osu.Game.Screens.Select.Leaderboards
replacePlaceholder(new MessagePlaceholder(@"Please sign in to view online leaderboards!"));
break;
case PlaceholderState.NotSupporter:
replacePlaceholder(new MessagePlaceholder(@"Please invest in a supporter tag to view this leaderboard!"));
replacePlaceholder(new MessagePlaceholder(@"Please invest in an osu!supporter tag to view this leaderboard!"));
break;
default:
replacePlaceholder(null);
@@ -331,23 +331,4 @@ namespace osu.Game.Screens.Select.Leaderboards
}
}
}
public enum LeaderboardScope
{
Local,
Country,
Global,
Friend,
}
public enum PlaceholderState
{
Successful,
Retrieving,
NetworkFailure,
Unavailable,
NoScores,
NotLoggedIn,
NotSupporter,
}
}
@@ -0,0 +1,13 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
namespace osu.Game.Screens.Select.Leaderboards
{
public enum LeaderboardScope
{
Local,
Country,
Global,
Friend,
}
}
@@ -2,10 +2,7 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using OpenTK;
namespace osu.Game.Screens.Select.Leaderboards
{
@@ -15,22 +12,13 @@ namespace osu.Game.Screens.Select.Leaderboards
public MessagePlaceholder(string message)
{
Direction = FillDirection.Horizontal;
AutoSizeAxes = Axes.Both;
Children = new Drawable[]
AddIcon(FontAwesome.fa_exclamation_circle, cp =>
{
new SpriteIcon
{
Icon = FontAwesome.fa_exclamation_circle,
Size = new Vector2(26),
Margin = new MarginPadding { Right = 10 },
},
new OsuSpriteText
{
Text = this.message = message,
TextSize = 22,
},
};
cp.TextSize = TEXT_SIZE;
cp.Padding = new MarginPadding { Right = 10 };
});
AddText(this.message = message);
}
public override bool Equals(Placeholder other) => (other as MessagePlaceholder)?.message == message;
@@ -3,16 +3,27 @@
using System;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Graphics.Containers;
namespace osu.Game.Screens.Select.Leaderboards
{
public abstract class Placeholder : FillFlowContainer, IEquatable<Placeholder>
public abstract class Placeholder : OsuTextFlowContainer, IEquatable<Placeholder>
{
protected const float TEXT_SIZE = 22;
public override bool HandleMouseInput => true;
protected Placeholder()
: base(cp => cp.TextSize = TEXT_SIZE)
{
Anchor = Anchor.Centre;
Origin = Anchor.Centre;
TextAnchor = Anchor.TopCentre;
Padding = new MarginPadding(20);
AutoSizeAxes = Axes.Y;
RelativeSizeAxes = Axes.X;
}
public virtual bool Equals(Placeholder other) => GetType() == other?.GetType();
@@ -0,0 +1,16 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
namespace osu.Game.Screens.Select.Leaderboards
{
public enum PlaceholderState
{
Successful,
Retrieving,
NetworkFailure,
Unavailable,
NoScores,
NotLoggedIn,
NotSupporter,
}
}
@@ -3,11 +3,9 @@
using System;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Input;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites;
using OpenTK;
namespace osu.Game.Screens.Select.Leaderboards
@@ -18,22 +16,13 @@ namespace osu.Game.Screens.Select.Leaderboards
public RetrievalFailurePlaceholder()
{
Direction = FillDirection.Horizontal;
AutoSizeAxes = Axes.Both;
Children = new Drawable[]
AddArbitraryDrawable(new RetryButton
{
new RetryButton
{
Action = () => OnRetry?.Invoke(),
Margin = new MarginPadding { Right = 10 },
},
new OsuSpriteText
{
Anchor = Anchor.TopLeft,
Text = @"Couldn't retrieve scores!",
TextSize = 22,
},
};
Action = () => OnRetry?.Invoke(),
Padding = new MarginPadding { Right = 10 }
});
AddText(@"Couldn't retrieve scores!");
}
public class RetryButton : OsuHoverContainer
@@ -44,18 +33,16 @@ namespace osu.Game.Screens.Select.Leaderboards
public RetryButton()
{
Height = 26;
Width = 26;
AutoSizeAxes = Axes.Both;
Child = new OsuClickableContainer
{
AutoSizeAxes = Axes.Both,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Action = () => Action?.Invoke(),
Child = icon = new SpriteIcon
{
Icon = FontAwesome.fa_refresh,
Size = new Vector2(26),
Size = new Vector2(TEXT_SIZE),
Shadow = true,
},
};
+1 -18
View File
@@ -1,12 +1,10 @@
// 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.Linq;
using osu.Framework.Audio.Track;
using osu.Framework.Graphics.Textures;
using osu.Game.Beatmaps;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Objects.Types;
namespace osu.Game.Tests.Beatmaps
{
@@ -26,21 +24,6 @@ namespace osu.Game.Tests.Beatmaps
private readonly IBeatmap beatmap;
protected override IBeatmap GetBeatmap() => beatmap;
protected override Texture GetBackground() => null;
protected override Track GetTrack()
{
var lastObject = beatmap.HitObjects.LastOrDefault();
if (lastObject != null)
return new TestTrack(((lastObject as IHasEndTime)?.EndTime ?? lastObject.StartTime) + 1000);
return new TrackVirtual();
}
private class TestTrack : TrackVirtual
{
public TestTrack(double length)
{
Length = length;
}
}
protected override Track GetTrack() => null;
}
}