mirror of
https://github.com/ppy/osu.git
synced 2024-12-15 10:42:54 +08:00
Merge branch 'master' into editor/checks/delayed-hitsounds
This commit is contained in:
commit
12bff9659b
@ -10,7 +10,7 @@
|
|||||||
<EmbedAssembliesIntoApk>true</EmbedAssembliesIntoApk>
|
<EmbedAssembliesIntoApk>true</EmbedAssembliesIntoApk>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2023.817.0" />
|
<PackageReference Include="ppy.osu.Framework.Android" Version="2023.823.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<!-- Fody does not handle Android build well, and warns when unchanged.
|
<!-- Fody does not handle Android build well, and warns when unchanged.
|
||||||
|
@ -1,17 +1,19 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Text;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Extensions;
|
||||||
using osu.Framework.Extensions.TypeExtensions;
|
using osu.Framework.Extensions.TypeExtensions;
|
||||||
using osu.Framework.Screens;
|
using osu.Framework.Screens;
|
||||||
using osu.Framework.Utils;
|
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
|
using osu.Game.Beatmaps.Formats;
|
||||||
using osu.Game.Replays;
|
using osu.Game.Replays;
|
||||||
using osu.Game.Rulesets.Judgements;
|
using osu.Game.Rulesets.Judgements;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
@ -19,9 +21,11 @@ using osu.Game.Rulesets.Objects.Types;
|
|||||||
using osu.Game.Rulesets.Osu.Mods;
|
using osu.Game.Rulesets.Osu.Mods;
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
using osu.Game.Rulesets.Osu.Replays;
|
using osu.Game.Rulesets.Osu.Replays;
|
||||||
|
using osu.Game.Rulesets.Osu.Scoring;
|
||||||
using osu.Game.Rulesets.Replays;
|
using osu.Game.Rulesets.Replays;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Scoring;
|
using osu.Game.Scoring;
|
||||||
|
using osu.Game.Scoring.Legacy;
|
||||||
using osu.Game.Screens.Play;
|
using osu.Game.Screens.Play;
|
||||||
using osu.Game.Tests.Visual;
|
using osu.Game.Tests.Visual;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
@ -30,8 +34,20 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
{
|
{
|
||||||
public partial class TestSceneObjectOrderedHitPolicy : RateAdjustedBeatmapTestScene
|
public partial class TestSceneObjectOrderedHitPolicy : RateAdjustedBeatmapTestScene
|
||||||
{
|
{
|
||||||
private const double early_miss_window = 1000; // time after -1000 to -500 is considered a miss
|
private readonly OsuHitWindows referenceHitWindows;
|
||||||
private const double late_miss_window = 500; // time after +500 is considered a miss
|
|
||||||
|
/// <summary>
|
||||||
|
/// This is provided as a convenience for testing note lock behaviour against osu!stable.
|
||||||
|
/// Setting this field to a non-null path will cause beatmap files and replays used in all test cases
|
||||||
|
/// to be exported to disk so that they can be cross-checked against stable.
|
||||||
|
/// </summary>
|
||||||
|
private readonly string? exportLocation = null;
|
||||||
|
|
||||||
|
public TestSceneObjectOrderedHitPolicy()
|
||||||
|
{
|
||||||
|
referenceHitWindows = new OsuHitWindows();
|
||||||
|
referenceHitWindows.SetDifficulty(0);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tests clicking a future circle before the first circle's start time, while the first circle HAS NOT been judged.
|
/// Tests clicking a future circle before the first circle's start time, while the first circle HAS NOT been judged.
|
||||||
@ -46,12 +62,12 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
|
|
||||||
var hitObjects = new List<OsuHitObject>
|
var hitObjects = new List<OsuHitObject>
|
||||||
{
|
{
|
||||||
new TestHitCircle
|
new HitCircle
|
||||||
{
|
{
|
||||||
StartTime = time_first_circle,
|
StartTime = time_first_circle,
|
||||||
Position = positionFirstCircle
|
Position = positionFirstCircle
|
||||||
},
|
},
|
||||||
new TestHitCircle
|
new HitCircle
|
||||||
{
|
{
|
||||||
StartTime = time_second_circle,
|
StartTime = time_second_circle,
|
||||||
Position = positionSecondCircle
|
Position = positionSecondCircle
|
||||||
@ -65,7 +81,8 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
|
|
||||||
addJudgementAssert(hitObjects[0], HitResult.Miss);
|
addJudgementAssert(hitObjects[0], HitResult.Miss);
|
||||||
addJudgementAssert(hitObjects[1], HitResult.Miss);
|
addJudgementAssert(hitObjects[1], HitResult.Miss);
|
||||||
addJudgementOffsetAssert(hitObjects[0], late_miss_window);
|
// note lock prevented the object from being hit, so the judgement offset should be very late.
|
||||||
|
addJudgementOffsetAssert(hitObjects[0], referenceHitWindows.WindowFor(HitResult.Meh));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -81,12 +98,12 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
|
|
||||||
var hitObjects = new List<OsuHitObject>
|
var hitObjects = new List<OsuHitObject>
|
||||||
{
|
{
|
||||||
new TestHitCircle
|
new HitCircle
|
||||||
{
|
{
|
||||||
StartTime = time_first_circle,
|
StartTime = time_first_circle,
|
||||||
Position = positionFirstCircle
|
Position = positionFirstCircle
|
||||||
},
|
},
|
||||||
new TestHitCircle
|
new HitCircle
|
||||||
{
|
{
|
||||||
StartTime = time_second_circle,
|
StartTime = time_second_circle,
|
||||||
Position = positionSecondCircle
|
Position = positionSecondCircle
|
||||||
@ -100,7 +117,8 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
|
|
||||||
addJudgementAssert(hitObjects[0], HitResult.Miss);
|
addJudgementAssert(hitObjects[0], HitResult.Miss);
|
||||||
addJudgementAssert(hitObjects[1], HitResult.Miss);
|
addJudgementAssert(hitObjects[1], HitResult.Miss);
|
||||||
addJudgementOffsetAssert(hitObjects[0], late_miss_window);
|
// note lock prevented the object from being hit, so the judgement offset should be very late.
|
||||||
|
addJudgementOffsetAssert(hitObjects[0], referenceHitWindows.WindowFor(HitResult.Meh));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -116,12 +134,12 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
|
|
||||||
var hitObjects = new List<OsuHitObject>
|
var hitObjects = new List<OsuHitObject>
|
||||||
{
|
{
|
||||||
new TestHitCircle
|
new HitCircle
|
||||||
{
|
{
|
||||||
StartTime = time_first_circle,
|
StartTime = time_first_circle,
|
||||||
Position = positionFirstCircle
|
Position = positionFirstCircle
|
||||||
},
|
},
|
||||||
new TestHitCircle
|
new HitCircle
|
||||||
{
|
{
|
||||||
StartTime = time_second_circle,
|
StartTime = time_second_circle,
|
||||||
Position = positionSecondCircle
|
Position = positionSecondCircle
|
||||||
@ -135,7 +153,8 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
|
|
||||||
addJudgementAssert(hitObjects[0], HitResult.Miss);
|
addJudgementAssert(hitObjects[0], HitResult.Miss);
|
||||||
addJudgementAssert(hitObjects[1], HitResult.Miss);
|
addJudgementAssert(hitObjects[1], HitResult.Miss);
|
||||||
addJudgementOffsetAssert(hitObjects[0], late_miss_window);
|
// note lock prevented the object from being hit, so the judgement offset should be very late.
|
||||||
|
addJudgementOffsetAssert(hitObjects[0], referenceHitWindows.WindowFor(HitResult.Meh));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -151,12 +170,12 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
|
|
||||||
var hitObjects = new List<OsuHitObject>
|
var hitObjects = new List<OsuHitObject>
|
||||||
{
|
{
|
||||||
new TestHitCircle
|
new HitCircle
|
||||||
{
|
{
|
||||||
StartTime = time_first_circle,
|
StartTime = time_first_circle,
|
||||||
Position = positionFirstCircle
|
Position = positionFirstCircle
|
||||||
},
|
},
|
||||||
new TestHitCircle
|
new HitCircle
|
||||||
{
|
{
|
||||||
StartTime = time_second_circle,
|
StartTime = time_second_circle,
|
||||||
Position = positionSecondCircle
|
Position = positionSecondCircle
|
||||||
@ -165,14 +184,14 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
|
|
||||||
performTest(hitObjects, new List<ReplayFrame>
|
performTest(hitObjects, new List<ReplayFrame>
|
||||||
{
|
{
|
||||||
new OsuReplayFrame { Time = time_first_circle - 200, Position = positionFirstCircle, Actions = { OsuAction.LeftButton } },
|
new OsuReplayFrame { Time = time_first_circle - 190, Position = positionFirstCircle, Actions = { OsuAction.LeftButton } },
|
||||||
new OsuReplayFrame { Time = time_first_circle - 100, Position = positionSecondCircle, Actions = { OsuAction.RightButton } }
|
new OsuReplayFrame { Time = time_first_circle - 90, Position = positionSecondCircle, Actions = { OsuAction.RightButton } }
|
||||||
});
|
});
|
||||||
|
|
||||||
addJudgementAssert(hitObjects[0], HitResult.Great);
|
addJudgementAssert(hitObjects[0], HitResult.Meh);
|
||||||
addJudgementAssert(hitObjects[1], HitResult.Great);
|
addJudgementAssert(hitObjects[1], HitResult.Meh);
|
||||||
addJudgementOffsetAssert(hitObjects[0], -200); // time_first_circle - 200
|
addJudgementOffsetAssert(hitObjects[0], -190); // time_first_circle - 190
|
||||||
addJudgementOffsetAssert(hitObjects[0], -200); // time_second_circle - first_circle_time - 100
|
addJudgementOffsetAssert(hitObjects[0], -90); // time_second_circle - first_circle_time - 90
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -188,12 +207,12 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
|
|
||||||
var hitObjects = new List<OsuHitObject>
|
var hitObjects = new List<OsuHitObject>
|
||||||
{
|
{
|
||||||
new TestHitCircle
|
new HitCircle
|
||||||
{
|
{
|
||||||
StartTime = time_first_circle,
|
StartTime = time_first_circle,
|
||||||
Position = positionFirstCircle
|
Position = positionFirstCircle
|
||||||
},
|
},
|
||||||
new TestHitCircle
|
new HitCircle
|
||||||
{
|
{
|
||||||
StartTime = time_second_circle,
|
StartTime = time_second_circle,
|
||||||
Position = positionSecondCircle
|
Position = positionSecondCircle
|
||||||
@ -202,13 +221,13 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
|
|
||||||
performTest(hitObjects, new List<ReplayFrame>
|
performTest(hitObjects, new List<ReplayFrame>
|
||||||
{
|
{
|
||||||
new OsuReplayFrame { Time = time_first_circle - 200, Position = positionFirstCircle, Actions = { OsuAction.LeftButton } },
|
new OsuReplayFrame { Time = time_first_circle - 190, Position = positionFirstCircle, Actions = { OsuAction.LeftButton } },
|
||||||
new OsuReplayFrame { Time = time_first_circle, Position = positionSecondCircle, Actions = { OsuAction.RightButton } }
|
new OsuReplayFrame { Time = time_first_circle, Position = positionSecondCircle, Actions = { OsuAction.RightButton } }
|
||||||
});
|
});
|
||||||
|
|
||||||
addJudgementAssert(hitObjects[0], HitResult.Great);
|
addJudgementAssert(hitObjects[0], HitResult.Meh);
|
||||||
addJudgementAssert(hitObjects[1], HitResult.Great);
|
addJudgementAssert(hitObjects[1], HitResult.Ok);
|
||||||
addJudgementOffsetAssert(hitObjects[0], -200); // time_first_circle - 200
|
addJudgementOffsetAssert(hitObjects[0], -190); // time_first_circle - 190
|
||||||
addJudgementOffsetAssert(hitObjects[1], -100); // time_second_circle - first_circle_time
|
addJudgementOffsetAssert(hitObjects[1], -100); // time_second_circle - first_circle_time
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -225,19 +244,19 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
|
|
||||||
var hitObjects = new List<OsuHitObject>
|
var hitObjects = new List<OsuHitObject>
|
||||||
{
|
{
|
||||||
new TestHitCircle
|
new HitCircle
|
||||||
{
|
{
|
||||||
StartTime = time_circle,
|
StartTime = time_circle,
|
||||||
Position = positionCircle
|
Position = positionCircle
|
||||||
},
|
},
|
||||||
new TestSlider
|
new Slider
|
||||||
{
|
{
|
||||||
StartTime = time_slider,
|
StartTime = time_slider,
|
||||||
Position = positionSlider,
|
Position = positionSlider,
|
||||||
Path = new SliderPath(PathType.Linear, new[]
|
Path = new SliderPath(PathType.Linear, new[]
|
||||||
{
|
{
|
||||||
Vector2.Zero,
|
Vector2.Zero,
|
||||||
new Vector2(25, 0),
|
new Vector2(50, 0),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -267,19 +286,19 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
|
|
||||||
var hitObjects = new List<OsuHitObject>
|
var hitObjects = new List<OsuHitObject>
|
||||||
{
|
{
|
||||||
new TestHitCircle
|
new HitCircle
|
||||||
{
|
{
|
||||||
StartTime = time_circle,
|
StartTime = time_circle,
|
||||||
Position = positionCircle
|
Position = positionCircle
|
||||||
},
|
},
|
||||||
new TestSlider
|
new Slider
|
||||||
{
|
{
|
||||||
StartTime = time_slider,
|
StartTime = time_slider,
|
||||||
Position = positionSlider,
|
Position = positionSlider,
|
||||||
Path = new SliderPath(PathType.Linear, new[]
|
Path = new SliderPath(PathType.Linear, new[]
|
||||||
{
|
{
|
||||||
Vector2.Zero,
|
Vector2.Zero,
|
||||||
new Vector2(25, 0),
|
new Vector2(50, 0),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -287,11 +306,11 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
performTest(hitObjects, new List<ReplayFrame>
|
performTest(hitObjects, new List<ReplayFrame>
|
||||||
{
|
{
|
||||||
new OsuReplayFrame { Time = time_slider, Position = positionSlider, Actions = { OsuAction.LeftButton } },
|
new OsuReplayFrame { Time = time_slider, Position = positionSlider, Actions = { OsuAction.LeftButton } },
|
||||||
new OsuReplayFrame { Time = time_circle + late_miss_window - 100, Position = positionCircle, Actions = { OsuAction.RightButton } },
|
new OsuReplayFrame { Time = time_circle + referenceHitWindows.WindowFor(HitResult.Meh) - 100, Position = positionCircle, Actions = { OsuAction.RightButton } },
|
||||||
new OsuReplayFrame { Time = time_circle + late_miss_window - 90, Position = positionSlider, Actions = { OsuAction.LeftButton } },
|
new OsuReplayFrame { Time = time_circle + referenceHitWindows.WindowFor(HitResult.Meh) - 90, Position = positionSlider, Actions = { OsuAction.LeftButton } },
|
||||||
});
|
});
|
||||||
|
|
||||||
addJudgementAssert(hitObjects[0], HitResult.Great);
|
addJudgementAssert(hitObjects[0], HitResult.Ok);
|
||||||
addJudgementAssert(hitObjects[1], HitResult.Great);
|
addJudgementAssert(hitObjects[1], HitResult.Great);
|
||||||
addJudgementAssert("slider head", () => ((Slider)hitObjects[1]).HeadCircle, HitResult.LargeTickHit);
|
addJudgementAssert("slider head", () => ((Slider)hitObjects[1]).HeadCircle, HitResult.LargeTickHit);
|
||||||
addJudgementAssert("slider tick", () => ((Slider)hitObjects[1]).NestedHitObjects[1] as SliderTick, HitResult.LargeTickHit);
|
addJudgementAssert("slider tick", () => ((Slider)hitObjects[1]).NestedHitObjects[1] as SliderTick, HitResult.LargeTickHit);
|
||||||
@ -304,7 +323,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
public void TestHitCircleBeforeSpinner()
|
public void TestHitCircleBeforeSpinner()
|
||||||
{
|
{
|
||||||
const double time_spinner = 1500;
|
const double time_spinner = 1500;
|
||||||
const double time_circle = 1800;
|
const double time_circle = 1600;
|
||||||
Vector2 positionCircle = Vector2.Zero;
|
Vector2 positionCircle = Vector2.Zero;
|
||||||
|
|
||||||
var hitObjects = new List<OsuHitObject>
|
var hitObjects = new List<OsuHitObject>
|
||||||
@ -315,7 +334,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
Position = new Vector2(256, 192),
|
Position = new Vector2(256, 192),
|
||||||
EndTime = time_spinner + 1000,
|
EndTime = time_spinner + 1000,
|
||||||
},
|
},
|
||||||
new TestHitCircle
|
new HitCircle
|
||||||
{
|
{
|
||||||
StartTime = time_circle,
|
StartTime = time_circle,
|
||||||
Position = positionCircle
|
Position = positionCircle
|
||||||
@ -324,7 +343,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
|
|
||||||
performTest(hitObjects, new List<ReplayFrame>
|
performTest(hitObjects, new List<ReplayFrame>
|
||||||
{
|
{
|
||||||
new OsuReplayFrame { Time = time_spinner - 100, Position = positionCircle, Actions = { OsuAction.LeftButton } },
|
new OsuReplayFrame { Time = time_spinner - 90, Position = positionCircle, Actions = { OsuAction.LeftButton } },
|
||||||
new OsuReplayFrame { Time = time_spinner + 10, Position = new Vector2(236, 192), Actions = { OsuAction.RightButton } },
|
new OsuReplayFrame { Time = time_spinner + 10, Position = new Vector2(236, 192), Actions = { OsuAction.RightButton } },
|
||||||
new OsuReplayFrame { Time = time_spinner + 20, Position = new Vector2(256, 172), Actions = { OsuAction.RightButton } },
|
new OsuReplayFrame { Time = time_spinner + 20, Position = new Vector2(256, 172), Actions = { OsuAction.RightButton } },
|
||||||
new OsuReplayFrame { Time = time_spinner + 30, Position = new Vector2(276, 192), Actions = { OsuAction.RightButton } },
|
new OsuReplayFrame { Time = time_spinner + 30, Position = new Vector2(276, 192), Actions = { OsuAction.RightButton } },
|
||||||
@ -333,7 +352,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
});
|
});
|
||||||
|
|
||||||
addJudgementAssert(hitObjects[0], HitResult.Great);
|
addJudgementAssert(hitObjects[0], HitResult.Great);
|
||||||
addJudgementAssert(hitObjects[1], HitResult.Great);
|
addJudgementAssert(hitObjects[1], HitResult.Meh);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@ -346,12 +365,12 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
|
|
||||||
var hitObjects = new List<OsuHitObject>
|
var hitObjects = new List<OsuHitObject>
|
||||||
{
|
{
|
||||||
new TestHitCircle
|
new HitCircle
|
||||||
{
|
{
|
||||||
StartTime = time_circle,
|
StartTime = time_circle,
|
||||||
Position = positionCircle
|
Position = positionCircle
|
||||||
},
|
},
|
||||||
new TestSlider
|
new Slider
|
||||||
{
|
{
|
||||||
StartTime = time_slider,
|
StartTime = time_slider,
|
||||||
Position = positionSlider,
|
Position = positionSlider,
|
||||||
@ -380,38 +399,105 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
() => judgementResults.Single(r => r.HitObject == hitObject).Type, () => Is.EqualTo(result));
|
() => judgementResults.Single(r => r.HitObject == hitObject).Type, () => Is.EqualTo(result));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addJudgementAssert(string name, Func<OsuHitObject> hitObject, HitResult result)
|
private void addJudgementAssert(string name, Func<OsuHitObject?> hitObject, HitResult result)
|
||||||
{
|
{
|
||||||
AddAssert($"{name} judgement is {result}",
|
AddAssert($"{name} judgement is {result}",
|
||||||
() => judgementResults.Single(r => r.HitObject == hitObject()).Type == result);
|
() => judgementResults.Single(r => r.HitObject == hitObject()).Type, () => Is.EqualTo(result));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addJudgementOffsetAssert(OsuHitObject hitObject, double offset)
|
private void addJudgementOffsetAssert(OsuHitObject hitObject, double offset)
|
||||||
{
|
{
|
||||||
AddAssert($"({hitObject.GetType().ReadableName()} @ {hitObject.StartTime}) judged at {offset}",
|
AddAssert($"({hitObject.GetType().ReadableName()} @ {hitObject.StartTime}) judged at {offset}",
|
||||||
() => Precision.AlmostEquals(judgementResults.Single(r => r.HitObject == hitObject).TimeOffset, offset, 100));
|
() => judgementResults.Single(r => r.HitObject == hitObject).TimeOffset, () => Is.EqualTo(offset).Within(100));
|
||||||
}
|
}
|
||||||
|
|
||||||
private ScoreAccessibleReplayPlayer currentPlayer;
|
private ScoreAccessibleReplayPlayer currentPlayer = null!;
|
||||||
private List<JudgementResult> judgementResults;
|
private List<JudgementResult> judgementResults = null!;
|
||||||
|
|
||||||
private void performTest(List<OsuHitObject> hitObjects, List<ReplayFrame> frames)
|
private void performTest(List<OsuHitObject> hitObjects, List<ReplayFrame> frames, [CallerMemberName] string testCaseName = "")
|
||||||
{
|
{
|
||||||
AddStep("load player", () =>
|
IBeatmap playableBeatmap = null!;
|
||||||
|
Score score = null!;
|
||||||
|
|
||||||
|
AddStep("create beatmap", () =>
|
||||||
{
|
{
|
||||||
|
var cpi = new ControlPointInfo();
|
||||||
|
cpi.Add(0, new TimingControlPoint { BeatLength = 1000 });
|
||||||
Beatmap.Value = CreateWorkingBeatmap(new Beatmap<OsuHitObject>
|
Beatmap.Value = CreateWorkingBeatmap(new Beatmap<OsuHitObject>
|
||||||
{
|
{
|
||||||
|
Metadata =
|
||||||
|
{
|
||||||
|
Title = testCaseName
|
||||||
|
},
|
||||||
HitObjects = hitObjects,
|
HitObjects = hitObjects,
|
||||||
Difficulty = new BeatmapDifficulty { SliderTickRate = 3 },
|
Difficulty = new BeatmapDifficulty
|
||||||
|
{
|
||||||
|
OverallDifficulty = 0,
|
||||||
|
SliderTickRate = 3
|
||||||
|
},
|
||||||
BeatmapInfo =
|
BeatmapInfo =
|
||||||
{
|
{
|
||||||
Ruleset = new OsuRuleset().RulesetInfo
|
Ruleset = new OsuRuleset().RulesetInfo,
|
||||||
|
BeatmapVersion = LegacyBeatmapEncoder.FIRST_LAZER_VERSION // for correct offset treatment by score encoder
|
||||||
},
|
},
|
||||||
|
ControlPointInfo = cpi
|
||||||
|
});
|
||||||
|
playableBeatmap = Beatmap.Value.GetPlayableBeatmap(new OsuRuleset().RulesetInfo);
|
||||||
|
});
|
||||||
|
|
||||||
|
AddStep("create score", () =>
|
||||||
|
{
|
||||||
|
score = new Score
|
||||||
|
{
|
||||||
|
Replay = new Replay
|
||||||
|
{
|
||||||
|
Frames = new List<ReplayFrame>
|
||||||
|
{
|
||||||
|
// required for correct playback in stable
|
||||||
|
new OsuReplayFrame(0, new Vector2(256, -500)),
|
||||||
|
new OsuReplayFrame(0, new Vector2(256, -500))
|
||||||
|
}.Concat(frames).ToList()
|
||||||
|
},
|
||||||
|
ScoreInfo =
|
||||||
|
{
|
||||||
|
Ruleset = new OsuRuleset().RulesetInfo,
|
||||||
|
BeatmapInfo = playableBeatmap.BeatmapInfo
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
if (exportLocation != null)
|
||||||
|
{
|
||||||
|
AddStep("export beatmap", () =>
|
||||||
|
{
|
||||||
|
var beatmapEncoder = new LegacyBeatmapEncoder(playableBeatmap, null);
|
||||||
|
|
||||||
|
using (var stream = File.Open(Path.Combine(exportLocation, $"{testCaseName}.osu"), FileMode.Create))
|
||||||
|
{
|
||||||
|
var memoryStream = new MemoryStream();
|
||||||
|
using (var writer = new StreamWriter(memoryStream, Encoding.UTF8, leaveOpen: true))
|
||||||
|
beatmapEncoder.Encode(writer);
|
||||||
|
|
||||||
|
memoryStream.Seek(0, SeekOrigin.Begin);
|
||||||
|
memoryStream.CopyTo(stream);
|
||||||
|
memoryStream.Seek(0, SeekOrigin.Begin);
|
||||||
|
playableBeatmap.BeatmapInfo.MD5Hash = memoryStream.ComputeMD5Hash();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
AddStep("export score", () =>
|
||||||
|
{
|
||||||
|
using var stream = File.Open(Path.Combine(exportLocation, $"{testCaseName}.osr"), FileMode.Create);
|
||||||
|
var encoder = new LegacyScoreEncoder(score, playableBeatmap);
|
||||||
|
encoder.Encode(stream);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
AddStep("load player", () =>
|
||||||
|
{
|
||||||
SelectedMods.Value = new[] { new OsuModClassic() };
|
SelectedMods.Value = new[] { new OsuModClassic() };
|
||||||
|
|
||||||
var p = new ScoreAccessibleReplayPlayer(new Score { Replay = new Replay { Frames = frames } });
|
var p = new ScoreAccessibleReplayPlayer(score);
|
||||||
|
|
||||||
p.OnLoadComplete += _ =>
|
p.OnLoadComplete += _ =>
|
||||||
{
|
{
|
||||||
@ -430,28 +516,6 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
AddUntilStep("Wait for completion", () => currentPlayer.ScoreProcessor.HasCompleted.Value);
|
AddUntilStep("Wait for completion", () => currentPlayer.ScoreProcessor.HasCompleted.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TestHitCircle : HitCircle
|
|
||||||
{
|
|
||||||
protected override HitWindows CreateHitWindows() => new TestHitWindows();
|
|
||||||
}
|
|
||||||
|
|
||||||
private class TestSlider : Slider
|
|
||||||
{
|
|
||||||
public TestSlider()
|
|
||||||
{
|
|
||||||
SliderVelocity = 0.1f;
|
|
||||||
|
|
||||||
DefaultsApplied += _ =>
|
|
||||||
{
|
|
||||||
HeadCircle.HitWindows = new TestHitWindows();
|
|
||||||
TailCircle.HitWindows = new TestHitWindows();
|
|
||||||
|
|
||||||
HeadCircle.HitWindows.SetDifficulty(0);
|
|
||||||
TailCircle.HitWindows.SetDifficulty(0);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class TestSpinner : Spinner
|
private class TestSpinner : Spinner
|
||||||
{
|
{
|
||||||
protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, IBeatmapDifficultyInfo difficulty)
|
protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, IBeatmapDifficultyInfo difficulty)
|
||||||
@ -461,19 +525,6 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TestHitWindows : HitWindows
|
|
||||||
{
|
|
||||||
private static readonly DifficultyRange[] ranges =
|
|
||||||
{
|
|
||||||
new DifficultyRange(HitResult.Great, 500, 500, 500),
|
|
||||||
new DifficultyRange(HitResult.Miss, early_miss_window, early_miss_window, early_miss_window),
|
|
||||||
};
|
|
||||||
|
|
||||||
public override bool IsHitResultAllowed(HitResult result) => result == HitResult.Great || result == HitResult.Miss;
|
|
||||||
|
|
||||||
protected override DifficultyRange[] GetRanges() => ranges;
|
|
||||||
}
|
|
||||||
|
|
||||||
private partial class ScoreAccessibleReplayPlayer : ReplayPlayer
|
private partial class ScoreAccessibleReplayPlayer : ReplayPlayer
|
||||||
{
|
{
|
||||||
public new ScoreProcessor ScoreProcessor => base.ScoreProcessor;
|
public new ScoreProcessor ScoreProcessor => base.ScoreProcessor;
|
||||||
|
@ -23,6 +23,9 @@ namespace osu.Game.Collections
|
|||||||
|
|
||||||
private AudioFilter lowPassFilter = null!;
|
private AudioFilter lowPassFilter = null!;
|
||||||
|
|
||||||
|
protected override string PopInSampleName => @"UI/overlay-big-pop-in";
|
||||||
|
protected override string PopOutSampleName => @"UI/overlay-big-pop-out";
|
||||||
|
|
||||||
public ManageCollectionsDialog()
|
public ManageCollectionsDialog()
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre;
|
Anchor = Anchor.Centre;
|
||||||
|
@ -24,6 +24,7 @@ namespace osu.Game.Graphics.Containers
|
|||||||
private Sample samplePopOut;
|
private Sample samplePopOut;
|
||||||
protected virtual string PopInSampleName => "UI/overlay-pop-in";
|
protected virtual string PopInSampleName => "UI/overlay-pop-in";
|
||||||
protected virtual string PopOutSampleName => "UI/overlay-pop-out";
|
protected virtual string PopOutSampleName => "UI/overlay-pop-out";
|
||||||
|
protected virtual double PopInOutSampleBalance => 0;
|
||||||
|
|
||||||
protected override bool BlockNonPositionalInput => true;
|
protected override bool BlockNonPositionalInput => true;
|
||||||
|
|
||||||
@ -133,15 +134,21 @@ namespace osu.Game.Graphics.Containers
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (didChange)
|
if (didChange && samplePopIn != null)
|
||||||
samplePopIn?.Play();
|
{
|
||||||
|
samplePopIn.Balance.Value = PopInOutSampleBalance;
|
||||||
|
samplePopIn.Play();
|
||||||
|
}
|
||||||
|
|
||||||
if (BlockScreenWideMouse && DimMainContent) overlayManager?.ShowBlockingOverlay(this);
|
if (BlockScreenWideMouse && DimMainContent) overlayManager?.ShowBlockingOverlay(this);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Visibility.Hidden:
|
case Visibility.Hidden:
|
||||||
if (didChange)
|
if (didChange && samplePopOut != null)
|
||||||
samplePopOut?.Play();
|
{
|
||||||
|
samplePopOut.Balance.Value = PopInOutSampleBalance;
|
||||||
|
samplePopOut.Play();
|
||||||
|
}
|
||||||
|
|
||||||
if (BlockScreenWideMouse) overlayManager?.HideBlockingOverlay(this);
|
if (BlockScreenWideMouse) overlayManager?.HideBlockingOverlay(this);
|
||||||
break;
|
break;
|
||||||
|
@ -2,6 +2,9 @@
|
|||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Audio;
|
||||||
|
using osu.Framework.Audio.Sample;
|
||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
@ -32,6 +35,12 @@ namespace osu.Game.Graphics.Containers
|
|||||||
|
|
||||||
protected override bool StartHidden => true;
|
protected override bool StartHidden => true;
|
||||||
|
|
||||||
|
private Sample? samplePopIn;
|
||||||
|
private Sample? samplePopOut;
|
||||||
|
|
||||||
|
// required due to LoadAsyncComplete() in `VisibilityContainer` calling PopOut() during load - similar workaround to `OsuDropdownMenu`
|
||||||
|
private bool wasShown;
|
||||||
|
|
||||||
public Color4 FirstWaveColour
|
public Color4 FirstWaveColour
|
||||||
{
|
{
|
||||||
get => firstWave.Colour;
|
get => firstWave.Colour;
|
||||||
@ -56,6 +65,13 @@ namespace osu.Game.Graphics.Containers
|
|||||||
set => fourthWave.Colour = value;
|
set => fourthWave.Colour = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader(true)]
|
||||||
|
private void load(AudioManager audio)
|
||||||
|
{
|
||||||
|
samplePopIn = audio.Samples.Get("UI/wave-pop-in");
|
||||||
|
samplePopOut = audio.Samples.Get("UI/overlay-big-pop-out");
|
||||||
|
}
|
||||||
|
|
||||||
public WaveContainer()
|
public WaveContainer()
|
||||||
{
|
{
|
||||||
Masking = true;
|
Masking = true;
|
||||||
@ -110,6 +126,8 @@ namespace osu.Game.Graphics.Containers
|
|||||||
w.Show();
|
w.Show();
|
||||||
|
|
||||||
contentContainer.MoveToY(0, APPEAR_DURATION, Easing.OutQuint);
|
contentContainer.MoveToY(0, APPEAR_DURATION, Easing.OutQuint);
|
||||||
|
samplePopIn?.Play();
|
||||||
|
wasShown = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void PopOut()
|
protected override void PopOut()
|
||||||
@ -118,6 +136,9 @@ namespace osu.Game.Graphics.Containers
|
|||||||
w.Hide();
|
w.Hide();
|
||||||
|
|
||||||
contentContainer.MoveToY(2, DISAPPEAR_DURATION, Easing.In);
|
contentContainer.MoveToY(2, DISAPPEAR_DURATION, Easing.In);
|
||||||
|
|
||||||
|
if (wasShown)
|
||||||
|
samplePopOut?.Play();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void UpdateAfterChildren()
|
protected override void UpdateAfterChildren()
|
||||||
|
@ -46,8 +46,8 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
private readonly Container content;
|
private readonly Container content;
|
||||||
private readonly Box hover;
|
private readonly Box hover;
|
||||||
|
|
||||||
public OsuAnimatedButton()
|
public OsuAnimatedButton(HoverSampleSet sampleSet = HoverSampleSet.Button)
|
||||||
: base(HoverSampleSet.Button)
|
: base(sampleSet)
|
||||||
{
|
{
|
||||||
base.Content.Add(content = new Container
|
base.Content.Add(content = new Container
|
||||||
{
|
{
|
||||||
|
@ -14,6 +14,12 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
private Sample? sampleOff;
|
private Sample? sampleOff;
|
||||||
private Sample? sampleOn;
|
private Sample? sampleOn;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sheared toggle buttons by default play two samples when toggled: a click and a toggle (on/off).
|
||||||
|
/// Sometimes this might be too much. Setting this to <c>false</c> will silence the toggle sound.
|
||||||
|
/// </summary>
|
||||||
|
protected virtual bool PlayToggleSamples => true;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether this button is currently toggled to an active state.
|
/// Whether this button is currently toggled to an active state.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -68,10 +74,13 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
{
|
{
|
||||||
sampleClick?.Play();
|
sampleClick?.Play();
|
||||||
|
|
||||||
if (Active.Value)
|
if (PlayToggleSamples)
|
||||||
sampleOn?.Play();
|
{
|
||||||
else
|
if (Active.Value)
|
||||||
sampleOff?.Play();
|
sampleOn?.Play();
|
||||||
|
else
|
||||||
|
sampleOff?.Play();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Audio;
|
||||||
|
using osu.Framework.Audio.Sample;
|
||||||
using osu.Framework.Extensions;
|
using osu.Framework.Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
@ -21,6 +23,14 @@ namespace osu.Game.Graphics.UserInterfaceV2
|
|||||||
private const float fade_duration = 250;
|
private const float fade_duration = 250;
|
||||||
private const double scale_duration = 500;
|
private const double scale_duration = 500;
|
||||||
|
|
||||||
|
private Sample? samplePopIn;
|
||||||
|
private Sample? samplePopOut;
|
||||||
|
protected virtual string PopInSampleName => "UI/overlay-pop-in";
|
||||||
|
protected virtual string PopOutSampleName => "UI/overlay-pop-out";
|
||||||
|
|
||||||
|
// required due to LoadAsyncComplete() in `VisibilityContainer` calling PopOut() during load - similar workaround to `OsuDropdownMenu`
|
||||||
|
private bool wasOpened;
|
||||||
|
|
||||||
public OsuPopover(bool withPadding = true)
|
public OsuPopover(bool withPadding = true)
|
||||||
{
|
{
|
||||||
Content.Padding = withPadding ? new MarginPadding(20) : new MarginPadding();
|
Content.Padding = withPadding ? new MarginPadding(20) : new MarginPadding();
|
||||||
@ -38,9 +48,11 @@ namespace osu.Game.Graphics.UserInterfaceV2
|
|||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader(true)]
|
[BackgroundDependencyLoader(true)]
|
||||||
private void load(OverlayColourProvider? colourProvider, OsuColour colours)
|
private void load(OverlayColourProvider? colourProvider, OsuColour colours, AudioManager audio)
|
||||||
{
|
{
|
||||||
Background.Colour = Arrow.Colour = colourProvider?.Background4 ?? colours.GreySeaFoamDarker;
|
Background.Colour = Arrow.Colour = colourProvider?.Background4 ?? colours.GreySeaFoamDarker;
|
||||||
|
samplePopIn = audio.Samples.Get(PopInSampleName);
|
||||||
|
samplePopOut = audio.Samples.Get(PopOutSampleName);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Drawable CreateArrow() => Empty();
|
protected override Drawable CreateArrow() => Empty();
|
||||||
@ -49,12 +61,18 @@ namespace osu.Game.Graphics.UserInterfaceV2
|
|||||||
{
|
{
|
||||||
this.ScaleTo(1, scale_duration, Easing.OutElasticHalf);
|
this.ScaleTo(1, scale_duration, Easing.OutElasticHalf);
|
||||||
this.FadeIn(fade_duration, Easing.OutQuint);
|
this.FadeIn(fade_duration, Easing.OutQuint);
|
||||||
|
|
||||||
|
samplePopIn?.Play();
|
||||||
|
wasOpened = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void PopOut()
|
protected override void PopOut()
|
||||||
{
|
{
|
||||||
this.ScaleTo(0.7f, scale_duration, Easing.OutQuint);
|
this.ScaleTo(0.7f, scale_duration, Easing.OutQuint);
|
||||||
this.FadeOut(fade_duration, Easing.OutQuint);
|
this.FadeOut(fade_duration, Easing.OutQuint);
|
||||||
|
|
||||||
|
if (wasOpened)
|
||||||
|
samplePopOut?.Play();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnKeyDown(KeyDownEvent e)
|
protected override bool OnKeyDown(KeyDownEvent e)
|
||||||
|
@ -55,6 +55,9 @@ namespace osu.Game.Overlays
|
|||||||
private const float side_bar_width = 190;
|
private const float side_bar_width = 190;
|
||||||
private const float chat_bar_height = 60;
|
private const float chat_bar_height = 60;
|
||||||
|
|
||||||
|
protected override string PopInSampleName => @"UI/overlay-big-pop-in";
|
||||||
|
protected override string PopOutSampleName => @"UI/overlay-big-pop-out";
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private OsuConfigManager config { get; set; } = null!;
|
private OsuConfigManager config { get; set; } = null!;
|
||||||
|
|
||||||
|
@ -20,6 +20,8 @@ namespace osu.Game.Overlays
|
|||||||
|
|
||||||
private const float transition_time = 400;
|
private const float transition_time = 400;
|
||||||
|
|
||||||
|
protected override double PopInOutSampleBalance => OsuGameBase.SFX_STEREO_STRENGTH;
|
||||||
|
|
||||||
[Cached]
|
[Cached]
|
||||||
private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple);
|
private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple);
|
||||||
|
|
||||||
|
@ -18,6 +18,8 @@ namespace osu.Game.Overlays.Mods
|
|||||||
{
|
{
|
||||||
public partial class AddPresetButton : ShearedToggleButton, IHasPopover
|
public partial class AddPresetButton : ShearedToggleButton, IHasPopover
|
||||||
{
|
{
|
||||||
|
protected override bool PlayToggleSamples => false;
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private OsuColour colours { get; set; } = null!;
|
private OsuColour colours { get; set; } = null!;
|
||||||
|
|
||||||
|
@ -31,6 +31,8 @@ namespace osu.Game.Overlays
|
|||||||
public LocalisableString Title => NotificationsStrings.HeaderTitle;
|
public LocalisableString Title => NotificationsStrings.HeaderTitle;
|
||||||
public LocalisableString Description => NotificationsStrings.HeaderDescription;
|
public LocalisableString Description => NotificationsStrings.HeaderDescription;
|
||||||
|
|
||||||
|
protected override double PopInOutSampleBalance => OsuGameBase.SFX_STEREO_STRENGTH;
|
||||||
|
|
||||||
public const float WIDTH = 320;
|
public const float WIDTH = 320;
|
||||||
|
|
||||||
public const float TRANSITION_LENGTH = 600;
|
public const float TRANSITION_LENGTH = 600;
|
||||||
|
@ -56,6 +56,7 @@ namespace osu.Game.Overlays
|
|||||||
private SeekLimitedSearchTextBox searchTextBox;
|
private SeekLimitedSearchTextBox searchTextBox;
|
||||||
|
|
||||||
protected override string PopInSampleName => "UI/settings-pop-in";
|
protected override string PopInSampleName => "UI/settings-pop-in";
|
||||||
|
protected override double PopInOutSampleBalance => -OsuGameBase.SFX_STEREO_STRENGTH;
|
||||||
|
|
||||||
private readonly bool showSidebar;
|
private readonly bool showSidebar;
|
||||||
|
|
||||||
|
@ -18,7 +18,9 @@ namespace osu.Game.Overlays
|
|||||||
|
|
||||||
protected override bool StartHidden => true;
|
protected override bool StartHidden => true;
|
||||||
|
|
||||||
protected override string PopInSampleName => "UI/wave-pop-in";
|
// `WaveContainer` plays PopIn/PopOut samples, so we disable the overlay-level one as to not double-up sample playback.
|
||||||
|
protected override string PopInSampleName => string.Empty;
|
||||||
|
protected override string PopOutSampleName => string.Empty;
|
||||||
|
|
||||||
public const float HORIZONTAL_PADDING = 50;
|
public const float HORIZONTAL_PADDING = 50;
|
||||||
|
|
||||||
|
@ -71,8 +71,21 @@ namespace osu.Game.Rulesets.Mods
|
|||||||
{
|
{
|
||||||
var bindable = (IBindable)property.GetValue(this)!;
|
var bindable = (IBindable)property.GetValue(this)!;
|
||||||
|
|
||||||
|
string valueText;
|
||||||
|
|
||||||
|
switch (bindable)
|
||||||
|
{
|
||||||
|
case Bindable<bool> b:
|
||||||
|
valueText = b.Value ? "on" : "off";
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
valueText = bindable.ToString() ?? string.Empty;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (!bindable.IsDefault)
|
if (!bindable.IsDefault)
|
||||||
tooltipTexts.Add($"{attr.Label} {bindable}");
|
tooltipTexts.Add($"{attr.Label}: {valueText}");
|
||||||
}
|
}
|
||||||
|
|
||||||
return string.Join(", ", tooltipTexts.Where(s => !string.IsNullOrEmpty(s)));
|
return string.Join(", ", tooltipTexts.Where(s => !string.IsNullOrEmpty(s)));
|
||||||
|
@ -262,6 +262,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
private readonly OsuSpriteText divisorText;
|
private readonly OsuSpriteText divisorText;
|
||||||
|
|
||||||
public DivisorDisplay()
|
public DivisorDisplay()
|
||||||
|
: base(HoverSampleSet.Default)
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre;
|
Anchor = Anchor.Centre;
|
||||||
Origin = Anchor.Centre;
|
Origin = Anchor.Centre;
|
||||||
|
@ -114,6 +114,9 @@ namespace osu.Game.Screens.Edit.Setup
|
|||||||
|
|
||||||
private partial class FileChooserPopover : OsuPopover
|
private partial class FileChooserPopover : OsuPopover
|
||||||
{
|
{
|
||||||
|
protected override string PopInSampleName => "UI/overlay-big-pop-in";
|
||||||
|
protected override string PopOutSampleName => "UI/overlay-big-pop-out";
|
||||||
|
|
||||||
public FileChooserPopover(string[] handledExtensions, Bindable<FileInfo?> currentFile, string? chooserPath)
|
public FileChooserPopover(string[] handledExtensions, Bindable<FileInfo?> currentFile, string? chooserPath)
|
||||||
{
|
{
|
||||||
Child = new Container
|
Child = new Container
|
||||||
|
@ -170,7 +170,6 @@ namespace osu.Game.Screens.OnlinePlay.Lounge
|
|||||||
|
|
||||||
if (Room.HasPassword.Value)
|
if (Room.HasPassword.Value)
|
||||||
{
|
{
|
||||||
sampleJoin?.Play();
|
|
||||||
this.ShowPopover();
|
this.ShowPopover();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,9 @@ namespace osu.Game.Screens.Select.Options
|
|||||||
|
|
||||||
public override bool BlockScreenWideMouse => false;
|
public override bool BlockScreenWideMouse => false;
|
||||||
|
|
||||||
|
protected override string PopInSampleName => "SongSelect/options-pop-in";
|
||||||
|
protected override string PopOutSampleName => "SongSelect/options-pop-out";
|
||||||
|
|
||||||
public BeatmapOptionsOverlay()
|
public BeatmapOptionsOverlay()
|
||||||
{
|
{
|
||||||
AutoSizeAxes = Axes.Y;
|
AutoSizeAxes = Axes.Y;
|
||||||
|
@ -47,6 +47,7 @@ namespace osu.Game.Utils
|
|||||||
|
|
||||||
options.AutoSessionTracking = true;
|
options.AutoSessionTracking = true;
|
||||||
options.IsEnvironmentUser = false;
|
options.IsEnvironmentUser = false;
|
||||||
|
options.IsGlobalModeEnabled = true;
|
||||||
// The reported release needs to match version as reported to Sentry in .github/workflows/sentry-release.yml
|
// The reported release needs to match version as reported to Sentry in .github/workflows/sentry-release.yml
|
||||||
options.Release = $"osu@{game.Version.Replace($@"-{OsuGameBase.BUILD_SUFFIX}", string.Empty)}";
|
options.Release = $"osu@{game.Version.Replace($@"-{OsuGameBase.BUILD_SUFFIX}", string.Empty)}";
|
||||||
});
|
});
|
||||||
|
@ -36,7 +36,7 @@
|
|||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Realm" Version="11.1.2" />
|
<PackageReference Include="Realm" Version="11.1.2" />
|
||||||
<PackageReference Include="ppy.osu.Framework" Version="2023.822.0" />
|
<PackageReference Include="ppy.osu.Framework" Version="2023.823.0" />
|
||||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2023.822.0" />
|
<PackageReference Include="ppy.osu.Game.Resources" Version="2023.822.0" />
|
||||||
<PackageReference Include="Sentry" Version="3.28.1" />
|
<PackageReference Include="Sentry" Version="3.28.1" />
|
||||||
<PackageReference Include="SharpCompress" Version="0.32.2" />
|
<PackageReference Include="SharpCompress" Version="0.32.2" />
|
||||||
|
@ -23,6 +23,6 @@
|
|||||||
<RuntimeIdentifier>iossimulator-x64</RuntimeIdentifier>
|
<RuntimeIdentifier>iossimulator-x64</RuntimeIdentifier>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="ppy.osu.Framework.iOS" Version="2023.817.0" />
|
<PackageReference Include="ppy.osu.Framework.iOS" Version="2023.823.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
Loading…
Reference in New Issue
Block a user