mirror of
https://github.com/osukey/osukey.git
synced 2025-06-08 21:07:59 +09:00
Merge branch 'master' into expandable-controls
This commit is contained in:
commit
b2efce2656
1
.gitignore
vendored
1
.gitignore
vendored
@ -339,3 +339,4 @@ inspectcode
|
|||||||
|
|
||||||
# Fody (pulled in by Realm) - schema file
|
# Fody (pulled in by Realm) - schema file
|
||||||
FodyWeavers.xsd
|
FodyWeavers.xsd
|
||||||
|
**/FodyWeavers.xml
|
||||||
|
147
Gemfile.lock
147
Gemfile.lock
@ -1,53 +1,75 @@
|
|||||||
GEM
|
GEM
|
||||||
remote: https://rubygems.org/
|
remote: https://rubygems.org/
|
||||||
specs:
|
specs:
|
||||||
CFPropertyList (3.0.3)
|
CFPropertyList (3.0.5)
|
||||||
addressable (2.7.0)
|
rexml
|
||||||
|
addressable (2.8.0)
|
||||||
public_suffix (>= 2.0.2, < 5.0)
|
public_suffix (>= 2.0.2, < 5.0)
|
||||||
|
artifactory (3.0.15)
|
||||||
atomos (0.1.3)
|
atomos (0.1.3)
|
||||||
aws-eventstream (1.1.0)
|
aws-eventstream (1.2.0)
|
||||||
aws-partitions (1.413.0)
|
aws-partitions (1.551.0)
|
||||||
aws-sdk-core (3.110.0)
|
aws-sdk-core (3.125.5)
|
||||||
aws-eventstream (~> 1, >= 1.0.2)
|
aws-eventstream (~> 1, >= 1.0.2)
|
||||||
aws-partitions (~> 1, >= 1.239.0)
|
aws-partitions (~> 1, >= 1.525.0)
|
||||||
aws-sigv4 (~> 1.1)
|
aws-sigv4 (~> 1.1)
|
||||||
jmespath (~> 1.0)
|
jmespath (~> 1.0)
|
||||||
aws-sdk-kms (1.40.0)
|
aws-sdk-kms (1.53.0)
|
||||||
aws-sdk-core (~> 3, >= 3.109.0)
|
aws-sdk-core (~> 3, >= 3.125.0)
|
||||||
aws-sigv4 (~> 1.1)
|
aws-sigv4 (~> 1.1)
|
||||||
aws-sdk-s3 (1.87.0)
|
aws-sdk-s3 (1.111.3)
|
||||||
aws-sdk-core (~> 3, >= 3.109.0)
|
aws-sdk-core (~> 3, >= 3.125.0)
|
||||||
aws-sdk-kms (~> 1)
|
aws-sdk-kms (~> 1)
|
||||||
aws-sigv4 (~> 1.1)
|
aws-sigv4 (~> 1.4)
|
||||||
aws-sigv4 (1.2.2)
|
aws-sigv4 (1.4.0)
|
||||||
aws-eventstream (~> 1, >= 1.0.2)
|
aws-eventstream (~> 1, >= 1.0.2)
|
||||||
babosa (1.0.4)
|
babosa (1.0.4)
|
||||||
claide (1.0.3)
|
claide (1.1.0)
|
||||||
colored (1.2)
|
colored (1.2)
|
||||||
colored2 (3.1.2)
|
colored2 (3.1.2)
|
||||||
commander-fastlane (4.4.6)
|
commander-fastlane (4.4.6)
|
||||||
highline (~> 1.7.2)
|
highline (~> 1.7.2)
|
||||||
declarative (0.0.20)
|
declarative (0.0.20)
|
||||||
declarative-option (0.1.0)
|
digest-crc (0.6.4)
|
||||||
digest-crc (0.6.3)
|
|
||||||
rake (>= 12.0.0, < 14.0.0)
|
rake (>= 12.0.0, < 14.0.0)
|
||||||
domain_name (0.5.20190701)
|
domain_name (0.5.20190701)
|
||||||
unf (>= 0.0.5, < 1.0.0)
|
unf (>= 0.0.5, < 1.0.0)
|
||||||
dotenv (2.7.6)
|
dotenv (2.7.6)
|
||||||
emoji_regex (3.2.1)
|
emoji_regex (3.2.3)
|
||||||
excon (0.78.1)
|
excon (0.90.0)
|
||||||
faraday (1.2.0)
|
faraday (1.9.3)
|
||||||
multipart-post (>= 1.2, < 3)
|
faraday-em_http (~> 1.0)
|
||||||
ruby2_keywords
|
faraday-em_synchrony (~> 1.0)
|
||||||
|
faraday-excon (~> 1.1)
|
||||||
|
faraday-httpclient (~> 1.0)
|
||||||
|
faraday-multipart (~> 1.0)
|
||||||
|
faraday-net_http (~> 1.0)
|
||||||
|
faraday-net_http_persistent (~> 1.0)
|
||||||
|
faraday-patron (~> 1.0)
|
||||||
|
faraday-rack (~> 1.0)
|
||||||
|
faraday-retry (~> 1.0)
|
||||||
|
ruby2_keywords (>= 0.0.4)
|
||||||
faraday-cookie_jar (0.0.7)
|
faraday-cookie_jar (0.0.7)
|
||||||
faraday (>= 0.8.0)
|
faraday (>= 0.8.0)
|
||||||
http-cookie (~> 1.0.0)
|
http-cookie (~> 1.0.0)
|
||||||
faraday_middleware (1.0.0)
|
faraday-em_http (1.0.0)
|
||||||
|
faraday-em_synchrony (1.0.0)
|
||||||
|
faraday-excon (1.1.0)
|
||||||
|
faraday-httpclient (1.0.1)
|
||||||
|
faraday-multipart (1.0.3)
|
||||||
|
multipart-post (>= 1.2, < 3)
|
||||||
|
faraday-net_http (1.0.1)
|
||||||
|
faraday-net_http_persistent (1.2.0)
|
||||||
|
faraday-patron (1.0.0)
|
||||||
|
faraday-rack (1.0.0)
|
||||||
|
faraday-retry (1.0.3)
|
||||||
|
faraday_middleware (1.2.0)
|
||||||
faraday (~> 1.0)
|
faraday (~> 1.0)
|
||||||
fastimage (2.2.1)
|
fastimage (2.2.6)
|
||||||
fastlane (2.170.0)
|
fastlane (2.181.0)
|
||||||
CFPropertyList (>= 2.3, < 4.0.0)
|
CFPropertyList (>= 2.3, < 4.0.0)
|
||||||
addressable (>= 2.3, < 3.0.0)
|
addressable (>= 2.3, < 3.0.0)
|
||||||
|
artifactory (~> 3.0)
|
||||||
aws-sdk-s3 (~> 1.0)
|
aws-sdk-s3 (~> 1.0)
|
||||||
babosa (>= 1.0.3, < 2.0.0)
|
babosa (>= 1.0.3, < 2.0.0)
|
||||||
bundler (>= 1.12.0, < 3.0.0)
|
bundler (>= 1.12.0, < 3.0.0)
|
||||||
@ -68,6 +90,7 @@ GEM
|
|||||||
jwt (>= 2.1.0, < 3)
|
jwt (>= 2.1.0, < 3)
|
||||||
mini_magick (>= 4.9.4, < 5.0.0)
|
mini_magick (>= 4.9.4, < 5.0.0)
|
||||||
multipart-post (~> 2.0.0)
|
multipart-post (~> 2.0.0)
|
||||||
|
naturally (~> 2.2)
|
||||||
plist (>= 3.1.0, < 4.0.0)
|
plist (>= 3.1.0, < 4.0.0)
|
||||||
rubyzip (>= 2.0.0, < 3.0.0)
|
rubyzip (>= 2.0.0, < 3.0.0)
|
||||||
security (= 0.1.3)
|
security (= 0.1.3)
|
||||||
@ -94,65 +117,80 @@ GEM
|
|||||||
representable (~> 3.0)
|
representable (~> 3.0)
|
||||||
retriable (>= 2.0, < 4.0)
|
retriable (>= 2.0, < 4.0)
|
||||||
signet (~> 0.12)
|
signet (~> 0.12)
|
||||||
google-cloud-core (1.5.0)
|
google-apis-core (0.4.2)
|
||||||
|
addressable (~> 2.5, >= 2.5.1)
|
||||||
|
googleauth (>= 0.16.2, < 2.a)
|
||||||
|
httpclient (>= 2.8.1, < 3.a)
|
||||||
|
mini_mime (~> 1.0)
|
||||||
|
representable (~> 3.0)
|
||||||
|
retriable (>= 2.0, < 4.a)
|
||||||
|
rexml
|
||||||
|
webrick
|
||||||
|
google-apis-iamcredentials_v1 (0.10.0)
|
||||||
|
google-apis-core (>= 0.4, < 2.a)
|
||||||
|
google-apis-storage_v1 (0.11.0)
|
||||||
|
google-apis-core (>= 0.4, < 2.a)
|
||||||
|
google-cloud-core (1.6.0)
|
||||||
google-cloud-env (~> 1.0)
|
google-cloud-env (~> 1.0)
|
||||||
google-cloud-errors (~> 1.0)
|
google-cloud-errors (~> 1.0)
|
||||||
google-cloud-env (1.4.0)
|
google-cloud-env (1.5.0)
|
||||||
faraday (>= 0.17.3, < 2.0)
|
faraday (>= 0.17.3, < 2.0)
|
||||||
google-cloud-errors (1.0.1)
|
google-cloud-errors (1.2.0)
|
||||||
google-cloud-storage (1.29.2)
|
google-cloud-storage (1.36.0)
|
||||||
addressable (~> 2.5)
|
addressable (~> 2.8)
|
||||||
digest-crc (~> 0.4)
|
digest-crc (~> 0.4)
|
||||||
google-api-client (~> 0.33)
|
google-apis-iamcredentials_v1 (~> 0.1)
|
||||||
google-cloud-core (~> 1.2)
|
google-apis-storage_v1 (~> 0.1)
|
||||||
googleauth (~> 0.9)
|
google-cloud-core (~> 1.6)
|
||||||
|
googleauth (>= 0.16.2, < 2.a)
|
||||||
mini_mime (~> 1.0)
|
mini_mime (~> 1.0)
|
||||||
googleauth (0.14.0)
|
googleauth (0.17.1)
|
||||||
faraday (>= 0.17.3, < 2.0)
|
faraday (>= 0.17.3, < 2.0)
|
||||||
jwt (>= 1.4, < 3.0)
|
jwt (>= 1.4, < 3.0)
|
||||||
memoist (~> 0.16)
|
memoist (~> 0.16)
|
||||||
multi_json (~> 1.11)
|
multi_json (~> 1.11)
|
||||||
os (>= 0.9, < 2.0)
|
os (>= 0.9, < 2.0)
|
||||||
signet (~> 0.14)
|
signet (~> 0.15)
|
||||||
highline (1.7.10)
|
highline (1.7.10)
|
||||||
http-cookie (1.0.3)
|
http-cookie (1.0.4)
|
||||||
domain_name (~> 0.5)
|
domain_name (~> 0.5)
|
||||||
httpclient (2.8.3)
|
httpclient (2.8.3)
|
||||||
jmespath (1.4.0)
|
jmespath (1.5.0)
|
||||||
json (2.5.1)
|
json (2.6.1)
|
||||||
jwt (2.2.2)
|
jwt (2.3.0)
|
||||||
memoist (0.16.2)
|
memoist (0.16.2)
|
||||||
mini_magick (4.11.0)
|
mini_magick (4.11.0)
|
||||||
mini_mime (1.0.2)
|
mini_mime (1.1.2)
|
||||||
mini_portile2 (2.4.0)
|
mini_portile2 (2.4.0)
|
||||||
multi_json (1.15.0)
|
multi_json (1.15.0)
|
||||||
multipart-post (2.0.0)
|
multipart-post (2.0.0)
|
||||||
nanaimo (0.3.0)
|
nanaimo (0.3.0)
|
||||||
naturally (2.2.0)
|
naturally (2.2.1)
|
||||||
nokogiri (1.10.10)
|
nokogiri (1.10.10)
|
||||||
mini_portile2 (~> 2.4.0)
|
mini_portile2 (~> 2.4.0)
|
||||||
os (1.1.1)
|
os (1.1.4)
|
||||||
plist (3.5.0)
|
plist (3.6.0)
|
||||||
public_suffix (4.0.6)
|
public_suffix (4.0.6)
|
||||||
rake (13.0.3)
|
rake (13.0.6)
|
||||||
representable (3.0.4)
|
representable (3.1.1)
|
||||||
declarative (< 0.1.0)
|
declarative (< 0.1.0)
|
||||||
declarative-option (< 0.2.0)
|
trailblazer-option (>= 0.1.1, < 0.2.0)
|
||||||
uber (< 0.2.0)
|
uber (< 0.2.0)
|
||||||
retriable (3.1.2)
|
retriable (3.1.2)
|
||||||
|
rexml (3.2.5)
|
||||||
rouge (2.0.7)
|
rouge (2.0.7)
|
||||||
ruby2_keywords (0.0.2)
|
ruby2_keywords (0.0.5)
|
||||||
rubyzip (2.3.0)
|
rubyzip (2.3.2)
|
||||||
security (0.1.3)
|
security (0.1.3)
|
||||||
signet (0.14.0)
|
signet (0.16.0)
|
||||||
addressable (~> 2.3)
|
addressable (~> 2.8)
|
||||||
faraday (>= 0.17.3, < 2.0)
|
faraday (>= 0.17.3, < 2.0)
|
||||||
jwt (>= 1.5, < 3.0)
|
jwt (>= 1.5, < 3.0)
|
||||||
multi_json (~> 1.10)
|
multi_json (~> 1.10)
|
||||||
simctl (1.6.8)
|
simctl (1.6.8)
|
||||||
CFPropertyList
|
CFPropertyList
|
||||||
naturally
|
naturally
|
||||||
slack-notifier (2.3.2)
|
slack-notifier (2.4.0)
|
||||||
souyuz (0.9.1)
|
souyuz (0.9.1)
|
||||||
fastlane (>= 1.103.0)
|
fastlane (>= 1.103.0)
|
||||||
highline (~> 1.7)
|
highline (~> 1.7)
|
||||||
@ -160,6 +198,7 @@ GEM
|
|||||||
terminal-notifier (2.0.0)
|
terminal-notifier (2.0.0)
|
||||||
terminal-table (1.8.0)
|
terminal-table (1.8.0)
|
||||||
unicode-display_width (~> 1.1, >= 1.1.1)
|
unicode-display_width (~> 1.1, >= 1.1.1)
|
||||||
|
trailblazer-option (0.1.2)
|
||||||
tty-cursor (0.7.1)
|
tty-cursor (0.7.1)
|
||||||
tty-screen (0.8.1)
|
tty-screen (0.8.1)
|
||||||
tty-spinner (0.9.3)
|
tty-spinner (0.9.3)
|
||||||
@ -167,18 +206,20 @@ GEM
|
|||||||
uber (0.1.0)
|
uber (0.1.0)
|
||||||
unf (0.1.4)
|
unf (0.1.4)
|
||||||
unf_ext
|
unf_ext
|
||||||
unf_ext (0.0.7.7)
|
unf_ext (0.0.8)
|
||||||
unicode-display_width (1.7.0)
|
unicode-display_width (1.8.0)
|
||||||
|
webrick (1.7.0)
|
||||||
word_wrap (1.0.0)
|
word_wrap (1.0.0)
|
||||||
xcodeproj (1.19.0)
|
xcodeproj (1.21.0)
|
||||||
CFPropertyList (>= 2.3.3, < 4.0)
|
CFPropertyList (>= 2.3.3, < 4.0)
|
||||||
atomos (~> 0.1.3)
|
atomos (~> 0.1.3)
|
||||||
claide (>= 1.0.2, < 2.0)
|
claide (>= 1.0.2, < 2.0)
|
||||||
colored2 (~> 3.1)
|
colored2 (~> 3.1)
|
||||||
nanaimo (~> 0.3.0)
|
nanaimo (~> 0.3.0)
|
||||||
|
rexml (~> 3.2.4)
|
||||||
xcpretty (0.3.0)
|
xcpretty (0.3.0)
|
||||||
rouge (~> 2.0.7)
|
rouge (~> 2.0.7)
|
||||||
xcpretty-travis-formatter (1.0.0)
|
xcpretty-travis-formatter (1.0.1)
|
||||||
xcpretty (~> 0.2, >= 0.0.7)
|
xcpretty (~> 0.2, >= 0.0.7)
|
||||||
|
|
||||||
PLATFORMS
|
PLATFORMS
|
||||||
|
@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.EmptyFreeform.Replays
|
|||||||
|
|
||||||
protected override bool IsImportant(EmptyFreeformReplayFrame frame) => frame.Actions.Any();
|
protected override bool IsImportant(EmptyFreeformReplayFrame frame) => frame.Actions.Any();
|
||||||
|
|
||||||
public override void CollectPendingInputs(List<IInput> inputs)
|
protected override void CollectReplayInputs(List<IInput> inputs)
|
||||||
{
|
{
|
||||||
var position = Interpolation.ValueAt(CurrentTime, StartFrame.Position, EndFrame.Position, StartFrame.Time, EndFrame.Time);
|
var position = Interpolation.ValueAt(CurrentTime, StartFrame.Position, EndFrame.Position, StartFrame.Time, EndFrame.Time);
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ namespace osu.Game.Rulesets.Pippidon.Replays
|
|||||||
|
|
||||||
protected override bool IsImportant(PippidonReplayFrame frame) => true;
|
protected override bool IsImportant(PippidonReplayFrame frame) => true;
|
||||||
|
|
||||||
public override void CollectPendingInputs(List<IInput> inputs)
|
protected override void CollectReplayInputs(List<IInput> inputs)
|
||||||
{
|
{
|
||||||
var position = Interpolation.ValueAt(CurrentTime, StartFrame.Position, EndFrame.Position, StartFrame.Time, EndFrame.Time);
|
var position = Interpolation.ValueAt(CurrentTime, StartFrame.Position, EndFrame.Position, StartFrame.Time, EndFrame.Time);
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ namespace osu.Game.Rulesets.EmptyScrolling.Replays
|
|||||||
|
|
||||||
protected override bool IsImportant(EmptyScrollingReplayFrame frame) => frame.Actions.Any();
|
protected override bool IsImportant(EmptyScrollingReplayFrame frame) => frame.Actions.Any();
|
||||||
|
|
||||||
public override void CollectPendingInputs(List<IInput> inputs)
|
protected override void CollectReplayInputs(List<IInput> inputs)
|
||||||
{
|
{
|
||||||
inputs.Add(new ReplayState<EmptyScrollingAction>
|
inputs.Add(new ReplayState<EmptyScrollingAction>
|
||||||
{
|
{
|
||||||
|
@ -18,7 +18,7 @@ namespace osu.Game.Rulesets.Pippidon.Replays
|
|||||||
|
|
||||||
protected override bool IsImportant(PippidonReplayFrame frame) => frame.Actions.Any();
|
protected override bool IsImportant(PippidonReplayFrame frame) => frame.Actions.Any();
|
||||||
|
|
||||||
public override void CollectPendingInputs(List<IInput> inputs)
|
protected override void CollectReplayInputs(List<IInput> inputs)
|
||||||
{
|
{
|
||||||
inputs.Add(new ReplayState<PippidonAction>
|
inputs.Add(new ReplayState<PippidonAction>
|
||||||
{
|
{
|
||||||
|
@ -12,7 +12,7 @@ Install _fastlane_ using
|
|||||||
```
|
```
|
||||||
[sudo] gem install fastlane -NV
|
[sudo] gem install fastlane -NV
|
||||||
```
|
```
|
||||||
or alternatively using `brew cask install fastlane`
|
or alternatively using `brew install fastlane`
|
||||||
|
|
||||||
# Available Actions
|
# Available Actions
|
||||||
## Android
|
## Android
|
||||||
|
@ -51,8 +51,8 @@
|
|||||||
<Reference Include="Java.Interop" />
|
<Reference Include="Java.Interop" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2022.115.0" />
|
<PackageReference Include="ppy.osu.Game.Resources" Version="2022.202.0" />
|
||||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2022.125.0" />
|
<PackageReference Include="ppy.osu.Framework.Android" Version="2022.128.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup Label="Transitive Dependencies">
|
<ItemGroup Label="Transitive Dependencies">
|
||||||
<!-- Realm needs to be directly referenced in all Xamarin projects, as it will not pull in its transitive dependencies otherwise. -->
|
<!-- Realm needs to be directly referenced in all Xamarin projects, as it will not pull in its transitive dependencies otherwise. -->
|
||||||
|
@ -17,7 +17,7 @@ namespace osu.Game.Rulesets.Catch.Mods
|
|||||||
public override double ScoreMultiplier => 1.12;
|
public override double ScoreMultiplier => 1.12;
|
||||||
|
|
||||||
[SettingSource("Flashlight size", "Multiplier applied to the default flashlight size.")]
|
[SettingSource("Flashlight size", "Multiplier applied to the default flashlight size.")]
|
||||||
public override BindableNumber<float> SizeMultiplier { get; } = new BindableNumber<float>
|
public override BindableFloat SizeMultiplier { get; } = new BindableFloat
|
||||||
{
|
{
|
||||||
MinValue = 0.5f,
|
MinValue = 0.5f,
|
||||||
MaxValue = 1.5f,
|
MaxValue = 1.5f,
|
||||||
|
@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Catch.Replays
|
|||||||
|
|
||||||
protected override bool IsImportant(CatchReplayFrame frame) => frame.Actions.Any();
|
protected override bool IsImportant(CatchReplayFrame frame) => frame.Actions.Any();
|
||||||
|
|
||||||
public override void CollectPendingInputs(List<IInput> inputs)
|
protected override void CollectReplayInputs(List<IInput> inputs)
|
||||||
{
|
{
|
||||||
float position = Interpolation.ValueAt(CurrentTime, StartFrame.Position, EndFrame.Position, StartFrame.Time, EndFrame.Time);
|
float position = Interpolation.ValueAt(CurrentTime, StartFrame.Position, EndFrame.Position, StartFrame.Time, EndFrame.Time);
|
||||||
|
|
||||||
|
@ -81,7 +81,7 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy
|
|||||||
|
|
||||||
case CatchSkinComponents.CatchComboCounter:
|
case CatchSkinComponents.CatchComboCounter:
|
||||||
if (providesComboCounter)
|
if (providesComboCounter)
|
||||||
return new LegacyCatchComboCounter(Skin);
|
return new LegacyCatchComboCounter();
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy
|
|||||||
|
|
||||||
private readonly LegacyRollingCounter explosion;
|
private readonly LegacyRollingCounter explosion;
|
||||||
|
|
||||||
public LegacyCatchComboCounter(ISkin skin)
|
public LegacyCatchComboCounter()
|
||||||
{
|
{
|
||||||
AutoSizeAxes = Axes.Both;
|
AutoSizeAxes = Axes.Both;
|
||||||
|
|
||||||
|
103
osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModHoldOff.cs
Normal file
103
osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModHoldOff.cs
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
using System.Linq;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Mania.Mods;
|
||||||
|
using osu.Game.Tests.Visual;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using osu.Game.Rulesets.Mania.Objects;
|
||||||
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
|
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Mania.Tests.Mods
|
||||||
|
{
|
||||||
|
public class TestSceneManiaModHoldOff : ModTestScene
|
||||||
|
{
|
||||||
|
protected override Ruleset CreatePlayerRuleset() => new ManiaRuleset();
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestMapHasNoHoldNotes()
|
||||||
|
{
|
||||||
|
var testBeatmap = createModdedBeatmap();
|
||||||
|
Assert.False(testBeatmap.HitObjects.OfType<HoldNote>().Any());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestCorrectNoteValues()
|
||||||
|
{
|
||||||
|
var testBeatmap = createRawBeatmap();
|
||||||
|
var noteValues = new List<double>(testBeatmap.HitObjects.OfType<HoldNote>().Count());
|
||||||
|
|
||||||
|
foreach (HoldNote h in testBeatmap.HitObjects.OfType<HoldNote>())
|
||||||
|
{
|
||||||
|
noteValues.Add(ManiaModHoldOff.GetNoteDurationInBeatLength(h, testBeatmap));
|
||||||
|
}
|
||||||
|
|
||||||
|
noteValues.Sort();
|
||||||
|
Assert.AreEqual(noteValues, new List<double> { 0.125, 0.250, 0.500, 1.000, 2.000 });
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestCorrectObjectCount()
|
||||||
|
{
|
||||||
|
// Ensure that the mod produces the expected number of objects when applied.
|
||||||
|
|
||||||
|
var rawBeatmap = createRawBeatmap();
|
||||||
|
var testBeatmap = createModdedBeatmap();
|
||||||
|
|
||||||
|
// Calculate expected number of objects
|
||||||
|
int expectedObjectCount = 0;
|
||||||
|
|
||||||
|
foreach (ManiaHitObject h in rawBeatmap.HitObjects)
|
||||||
|
{
|
||||||
|
// Both notes and hold notes account for at least one object
|
||||||
|
expectedObjectCount++;
|
||||||
|
|
||||||
|
if (h.GetType() == typeof(HoldNote))
|
||||||
|
{
|
||||||
|
double noteValue = ManiaModHoldOff.GetNoteDurationInBeatLength((HoldNote)h, rawBeatmap);
|
||||||
|
|
||||||
|
if (noteValue >= ManiaModHoldOff.END_NOTE_ALLOW_THRESHOLD)
|
||||||
|
{
|
||||||
|
// Should generate an end note if it's longer than the minimum note value
|
||||||
|
expectedObjectCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.That(testBeatmap.HitObjects.Count == expectedObjectCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ManiaBeatmap createModdedBeatmap()
|
||||||
|
{
|
||||||
|
var beatmap = createRawBeatmap();
|
||||||
|
var holdOffMod = new ManiaModHoldOff();
|
||||||
|
|
||||||
|
foreach (var hitObject in beatmap.HitObjects)
|
||||||
|
hitObject.ApplyDefaults(beatmap.ControlPointInfo, new BeatmapDifficulty());
|
||||||
|
|
||||||
|
holdOffMod.ApplyToBeatmap(beatmap);
|
||||||
|
|
||||||
|
return beatmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ManiaBeatmap createRawBeatmap()
|
||||||
|
{
|
||||||
|
var beatmap = new ManiaBeatmap(new StageDefinition { Columns = 1 });
|
||||||
|
beatmap.ControlPointInfo.Add(0.0, new TimingControlPoint { BeatLength = 1000 }); // Set BPM to 60
|
||||||
|
|
||||||
|
// Add test hit objects
|
||||||
|
beatmap.HitObjects.Add(new Note { StartTime = 4000 });
|
||||||
|
beatmap.HitObjects.Add(new Note { StartTime = 4500 });
|
||||||
|
beatmap.HitObjects.Add(new HoldNote { StartTime = 0, EndTime = 125 }); // 1/8 note
|
||||||
|
beatmap.HitObjects.Add(new HoldNote { StartTime = 0, EndTime = 250 }); // 1/4 note
|
||||||
|
beatmap.HitObjects.Add(new HoldNote { StartTime = 0, EndTime = 500 }); // 1/2 note
|
||||||
|
beatmap.HitObjects.Add(new HoldNote { StartTime = 0, EndTime = 1000 }); // 1/1 note
|
||||||
|
beatmap.HitObjects.Add(new HoldNote { StartTime = 0, EndTime = 2000 }); // 2/1 note
|
||||||
|
|
||||||
|
return beatmap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -28,7 +28,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning
|
|||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Width = 0.5f,
|
Width = 0.5f,
|
||||||
Child = new ColumnHitObjectArea(0, new HitObjectContainer())
|
Child = new ColumnHitObjectArea(new HitObjectContainer())
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both
|
RelativeSizeAxes = Axes.Both
|
||||||
}
|
}
|
||||||
@ -37,7 +37,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning
|
|||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Width = 0.5f,
|
Width = 0.5f,
|
||||||
Child = new ColumnHitObjectArea(1, new HitObjectContainer())
|
Child = new ColumnHitObjectArea(new HitObjectContainer())
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both
|
RelativeSizeAxes = Axes.Both
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ namespace osu.Game.Rulesets.Mania
|
|||||||
|
|
||||||
public bool Matches(BeatmapInfo beatmapInfo)
|
public bool Matches(BeatmapInfo beatmapInfo)
|
||||||
{
|
{
|
||||||
return !keys.HasFilter || (beatmapInfo.RulesetID == new ManiaRuleset().LegacyID && keys.IsInRange(ManiaBeatmapConverter.GetColumnCountForNonConvert(beatmapInfo)));
|
return !keys.HasFilter || (beatmapInfo.Ruleset.OnlineID == new ManiaRuleset().LegacyID && keys.IsInRange(ManiaBeatmapConverter.GetColumnCountForNonConvert(beatmapInfo)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryParseCustomKeywordCriteria(string key, Operator op, string value)
|
public bool TryParseCustomKeywordCriteria(string key, Operator op, string value)
|
||||||
|
@ -2,11 +2,13 @@
|
|||||||
// 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.ComponentModel;
|
using System.ComponentModel;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Input.Bindings;
|
using osu.Framework.Input.Bindings;
|
||||||
using osu.Game.Rulesets.UI;
|
using osu.Game.Rulesets.UI;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania
|
namespace osu.Game.Rulesets.Mania
|
||||||
{
|
{
|
||||||
|
[Cached] // Used for touch input, see ColumnTouchInputArea.
|
||||||
public class ManiaInputManager : RulesetInputManager<ManiaAction>
|
public class ManiaInputManager : RulesetInputManager<ManiaAction>
|
||||||
{
|
{
|
||||||
public ManiaInputManager(RulesetInfo ruleset, int variant)
|
public ManiaInputManager(RulesetInfo ruleset, int variant)
|
||||||
|
@ -243,7 +243,8 @@ namespace osu.Game.Rulesets.Mania
|
|||||||
new ManiaModDifficultyAdjust(),
|
new ManiaModDifficultyAdjust(),
|
||||||
new ManiaModClassic(),
|
new ManiaModClassic(),
|
||||||
new ManiaModInvert(),
|
new ManiaModInvert(),
|
||||||
new ManiaModConstantSpeed()
|
new ManiaModConstantSpeed(),
|
||||||
|
new ManiaModHoldOff()
|
||||||
};
|
};
|
||||||
|
|
||||||
case ModType.Automation:
|
case ModType.Automation:
|
||||||
|
@ -18,7 +18,7 @@ namespace osu.Game.Rulesets.Mania.Mods
|
|||||||
public override Type[] IncompatibleMods => new[] { typeof(ModHidden) };
|
public override Type[] IncompatibleMods => new[] { typeof(ModHidden) };
|
||||||
|
|
||||||
[SettingSource("Flashlight size", "Multiplier applied to the default flashlight size.")]
|
[SettingSource("Flashlight size", "Multiplier applied to the default flashlight size.")]
|
||||||
public override BindableNumber<float> SizeMultiplier { get; } = new BindableNumber<float>
|
public override BindableFloat SizeMultiplier { get; } = new BindableFloat
|
||||||
{
|
{
|
||||||
MinValue = 0.5f,
|
MinValue = 0.5f,
|
||||||
MaxValue = 3f,
|
MaxValue = 3f,
|
||||||
|
72
osu.Game.Rulesets.Mania/Mods/ManiaModHoldOff.cs
Normal file
72
osu.Game.Rulesets.Mania/Mods/ManiaModHoldOff.cs
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Mania.Objects;
|
||||||
|
using osu.Game.Rulesets.Mods;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Mania.Mods
|
||||||
|
{
|
||||||
|
public class ManiaModHoldOff : Mod, IApplicableAfterBeatmapConversion
|
||||||
|
{
|
||||||
|
public override string Name => "Hold Off";
|
||||||
|
|
||||||
|
public override string Acronym => "HO";
|
||||||
|
|
||||||
|
public override double ScoreMultiplier => 1;
|
||||||
|
|
||||||
|
public override string Description => @"Replaces all hold notes with normal notes.";
|
||||||
|
|
||||||
|
public override IconUsage? Icon => FontAwesome.Solid.DotCircle;
|
||||||
|
|
||||||
|
public override ModType Type => ModType.Conversion;
|
||||||
|
|
||||||
|
public override Type[] IncompatibleMods => new[] { typeof(ManiaModInvert) };
|
||||||
|
|
||||||
|
public const double END_NOTE_ALLOW_THRESHOLD = 0.5;
|
||||||
|
|
||||||
|
public void ApplyToBeatmap(IBeatmap beatmap)
|
||||||
|
{
|
||||||
|
var maniaBeatmap = (ManiaBeatmap)beatmap;
|
||||||
|
|
||||||
|
var newObjects = new List<ManiaHitObject>();
|
||||||
|
|
||||||
|
foreach (var h in beatmap.HitObjects.OfType<HoldNote>())
|
||||||
|
{
|
||||||
|
// Add a note for the beginning of the hold note
|
||||||
|
newObjects.Add(new Note
|
||||||
|
{
|
||||||
|
Column = h.Column,
|
||||||
|
StartTime = h.StartTime,
|
||||||
|
Samples = h.GetNodeSamples(0)
|
||||||
|
});
|
||||||
|
|
||||||
|
// Don't add an end note if the duration is shorter than the threshold
|
||||||
|
double noteValue = GetNoteDurationInBeatLength(h, maniaBeatmap); // 1/1, 1/2, 1/4, etc.
|
||||||
|
|
||||||
|
if (noteValue >= END_NOTE_ALLOW_THRESHOLD)
|
||||||
|
{
|
||||||
|
newObjects.Add(new Note
|
||||||
|
{
|
||||||
|
Column = h.Column,
|
||||||
|
StartTime = h.EndTime,
|
||||||
|
Samples = h.GetNodeSamples((h.NodeSamples?.Count - 1) ?? 1)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
maniaBeatmap.HitObjects = maniaBeatmap.HitObjects.OfType<Note>().Concat(newObjects).OrderBy(h => h.StartTime).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double GetNoteDurationInBeatLength(HoldNote holdNote, ManiaBeatmap beatmap)
|
||||||
|
{
|
||||||
|
double beatLength = beatmap.ControlPointInfo.TimingPointAt(holdNote.StartTime).BeatLength;
|
||||||
|
return holdNote.Duration / beatLength;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -26,6 +26,8 @@ namespace osu.Game.Rulesets.Mania.Mods
|
|||||||
|
|
||||||
public override ModType Type => ModType.Conversion;
|
public override ModType Type => ModType.Conversion;
|
||||||
|
|
||||||
|
public override Type[] IncompatibleMods => new[] { typeof(ManiaModHoldOff) };
|
||||||
|
|
||||||
public void ApplyToBeatmap(IBeatmap beatmap)
|
public void ApplyToBeatmap(IBeatmap beatmap)
|
||||||
{
|
{
|
||||||
var maniaBeatmap = (ManiaBeatmap)beatmap;
|
var maniaBeatmap = (ManiaBeatmap)beatmap;
|
||||||
|
@ -18,7 +18,7 @@ namespace osu.Game.Rulesets.Mania.Replays
|
|||||||
|
|
||||||
protected override bool IsImportant(ManiaReplayFrame frame) => frame.Actions.Any();
|
protected override bool IsImportant(ManiaReplayFrame frame) => frame.Actions.Any();
|
||||||
|
|
||||||
public override void CollectPendingInputs(List<IInput> inputs)
|
protected override void CollectReplayInputs(List<IInput> inputs)
|
||||||
{
|
{
|
||||||
inputs.Add(new ReplayState<ManiaAction> { PressedActions = CurrentFrame?.Actions ?? new List<ManiaAction>() });
|
inputs.Add(new ReplayState<ManiaAction> { PressedActions = CurrentFrame?.Actions ?? new List<ManiaAction>() });
|
||||||
}
|
}
|
||||||
|
@ -62,13 +62,14 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
sampleTriggerSource = new GameplaySampleTriggerSource(HitObjectContainer),
|
sampleTriggerSource = new GameplaySampleTriggerSource(HitObjectContainer),
|
||||||
// For input purposes, the background is added at the highest depth, but is then proxied back below all other elements
|
// For input purposes, the background is added at the highest depth, but is then proxied back below all other elements
|
||||||
background.CreateProxy(),
|
background.CreateProxy(),
|
||||||
HitObjectArea = new ColumnHitObjectArea(Index, HitObjectContainer) { RelativeSizeAxes = Axes.Both },
|
HitObjectArea = new ColumnHitObjectArea(HitObjectContainer) { RelativeSizeAxes = Axes.Both },
|
||||||
new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.KeyArea), _ => new DefaultKeyArea())
|
new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.KeyArea), _ => new DefaultKeyArea())
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both
|
RelativeSizeAxes = Axes.Both
|
||||||
},
|
},
|
||||||
background,
|
background,
|
||||||
TopLevelContainer = new Container { RelativeSizeAxes = Axes.Both }
|
TopLevelContainer = new Container { RelativeSizeAxes = Axes.Both },
|
||||||
|
new ColumnTouchInputArea(this)
|
||||||
};
|
};
|
||||||
|
|
||||||
hitPolicy = new OrderedHitPolicy(HitObjectContainer);
|
hitPolicy = new OrderedHitPolicy(HitObjectContainer);
|
||||||
@ -139,5 +140,50 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos)
|
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos)
|
||||||
// This probably shouldn't exist as is, but the columns in the stage are separated by a 1px border
|
// This probably shouldn't exist as is, but the columns in the stage are separated by a 1px border
|
||||||
=> DrawRectangle.Inflate(new Vector2(Stage.COLUMN_SPACING / 2, 0)).Contains(ToLocalSpace(screenSpacePos));
|
=> DrawRectangle.Inflate(new Vector2(Stage.COLUMN_SPACING / 2, 0)).Contains(ToLocalSpace(screenSpacePos));
|
||||||
|
|
||||||
|
public class ColumnTouchInputArea : Drawable
|
||||||
|
{
|
||||||
|
private readonly Column column;
|
||||||
|
|
||||||
|
[Resolved(canBeNull: true)]
|
||||||
|
private ManiaInputManager maniaInputManager { get; set; }
|
||||||
|
|
||||||
|
private KeyBindingContainer<ManiaAction> keyBindingContainer;
|
||||||
|
|
||||||
|
public ColumnTouchInputArea(Column column)
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both;
|
||||||
|
|
||||||
|
this.column = column;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
keyBindingContainer = maniaInputManager?.KeyBindingContainer;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool OnMouseDown(MouseDownEvent e)
|
||||||
|
{
|
||||||
|
keyBindingContainer?.TriggerPressed(column.Action.Value);
|
||||||
|
return base.OnMouseDown(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnMouseUp(MouseUpEvent e)
|
||||||
|
{
|
||||||
|
keyBindingContainer?.TriggerReleased(column.Action.Value);
|
||||||
|
base.OnMouseUp(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool OnTouchDown(TouchDownEvent e)
|
||||||
|
{
|
||||||
|
keyBindingContainer?.TriggerPressed(column.Action.Value);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnTouchUp(TouchUpEvent e)
|
||||||
|
{
|
||||||
|
keyBindingContainer?.TriggerReleased(column.Action.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ namespace osu.Game.Rulesets.Mania.UI.Components
|
|||||||
|
|
||||||
private readonly Drawable hitTarget;
|
private readonly Drawable hitTarget;
|
||||||
|
|
||||||
public ColumnHitObjectArea(int columnIndex, HitObjectContainer hitObjectContainer)
|
public ColumnHitObjectArea(HitObjectContainer hitObjectContainer)
|
||||||
: base(hitObjectContainer)
|
: base(hitObjectContainer)
|
||||||
{
|
{
|
||||||
AddRangeInternal(new[]
|
AddRangeInternal(new[]
|
||||||
|
@ -69,7 +69,7 @@ namespace osu.Game.Rulesets.Mania.UI.Components
|
|||||||
AlwaysPresent = true
|
AlwaysPresent = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
27
osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModAimAssist.cs
Normal file
27
osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModAimAssist.cs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
using NUnit.Framework;
|
||||||
|
using osu.Game.Rulesets.Osu.Mods;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Osu.Tests.Mods
|
||||||
|
{
|
||||||
|
public class TestSceneOsuModAimAssist : OsuModTestScene
|
||||||
|
{
|
||||||
|
[TestCase(0.1f)]
|
||||||
|
[TestCase(0.5f)]
|
||||||
|
[TestCase(1)]
|
||||||
|
public void TestAimAssist(float strength)
|
||||||
|
{
|
||||||
|
CreateModTest(new ModTestData
|
||||||
|
{
|
||||||
|
Mod = new OsuModAimAssist
|
||||||
|
{
|
||||||
|
AssistStrength = { Value = strength },
|
||||||
|
},
|
||||||
|
PassCondition = () => true,
|
||||||
|
Autoplay = false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
154
osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModAlternate.cs
Normal file
154
osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModAlternate.cs
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Beatmaps.Timing;
|
||||||
|
using osu.Game.Rulesets.Objects;
|
||||||
|
using osu.Game.Rulesets.Osu.Mods;
|
||||||
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
|
using osu.Game.Rulesets.Osu.Replays;
|
||||||
|
using osu.Game.Rulesets.Replays;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Osu.Tests.Mods
|
||||||
|
{
|
||||||
|
public class TestSceneOsuModAlternate : OsuModTestScene
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public void TestInputAtIntro() => CreateModTest(new ModTestData
|
||||||
|
{
|
||||||
|
Mod = new OsuModAlternate(),
|
||||||
|
PassCondition = () => Player.ScoreProcessor.Combo.Value == 1,
|
||||||
|
Autoplay = false,
|
||||||
|
Beatmap = new Beatmap
|
||||||
|
{
|
||||||
|
HitObjects = new List<HitObject>
|
||||||
|
{
|
||||||
|
new HitCircle
|
||||||
|
{
|
||||||
|
StartTime = 1000,
|
||||||
|
Position = new Vector2(100),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ReplayFrames = new List<ReplayFrame>
|
||||||
|
{
|
||||||
|
new OsuReplayFrame(500, new Vector2(200), OsuAction.LeftButton),
|
||||||
|
new OsuReplayFrame(501, new Vector2(200)),
|
||||||
|
new OsuReplayFrame(1000, new Vector2(100), OsuAction.LeftButton),
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestInputAlternating() => CreateModTest(new ModTestData
|
||||||
|
{
|
||||||
|
Mod = new OsuModAlternate(),
|
||||||
|
PassCondition = () => Player.ScoreProcessor.Combo.Value == 4,
|
||||||
|
Autoplay = false,
|
||||||
|
Beatmap = new Beatmap
|
||||||
|
{
|
||||||
|
HitObjects = new List<HitObject>
|
||||||
|
{
|
||||||
|
new HitCircle
|
||||||
|
{
|
||||||
|
StartTime = 500,
|
||||||
|
Position = new Vector2(100),
|
||||||
|
},
|
||||||
|
new HitCircle
|
||||||
|
{
|
||||||
|
StartTime = 1000,
|
||||||
|
Position = new Vector2(200, 100),
|
||||||
|
},
|
||||||
|
new HitCircle
|
||||||
|
{
|
||||||
|
StartTime = 1500,
|
||||||
|
Position = new Vector2(300, 100),
|
||||||
|
},
|
||||||
|
new HitCircle
|
||||||
|
{
|
||||||
|
StartTime = 2000,
|
||||||
|
Position = new Vector2(400, 100),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ReplayFrames = new List<ReplayFrame>
|
||||||
|
{
|
||||||
|
new OsuReplayFrame(500, new Vector2(100), OsuAction.LeftButton),
|
||||||
|
new OsuReplayFrame(501, new Vector2(100)),
|
||||||
|
new OsuReplayFrame(1000, new Vector2(200, 100), OsuAction.RightButton),
|
||||||
|
new OsuReplayFrame(1001, new Vector2(200, 100)),
|
||||||
|
new OsuReplayFrame(1500, new Vector2(300, 100), OsuAction.LeftButton),
|
||||||
|
new OsuReplayFrame(1501, new Vector2(300, 100)),
|
||||||
|
new OsuReplayFrame(2000, new Vector2(400, 100), OsuAction.RightButton),
|
||||||
|
new OsuReplayFrame(2001, new Vector2(400, 100)),
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestInputSingular() => CreateModTest(new ModTestData
|
||||||
|
{
|
||||||
|
Mod = new OsuModAlternate(),
|
||||||
|
PassCondition = () => Player.ScoreProcessor.Combo.Value == 0 && Player.ScoreProcessor.HighestCombo.Value == 1,
|
||||||
|
Autoplay = false,
|
||||||
|
Beatmap = new Beatmap
|
||||||
|
{
|
||||||
|
HitObjects = new List<HitObject>
|
||||||
|
{
|
||||||
|
new HitCircle
|
||||||
|
{
|
||||||
|
StartTime = 500,
|
||||||
|
Position = new Vector2(100),
|
||||||
|
},
|
||||||
|
new HitCircle
|
||||||
|
{
|
||||||
|
StartTime = 1000,
|
||||||
|
Position = new Vector2(200, 100),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ReplayFrames = new List<ReplayFrame>
|
||||||
|
{
|
||||||
|
new OsuReplayFrame(500, new Vector2(100), OsuAction.LeftButton),
|
||||||
|
new OsuReplayFrame(501, new Vector2(100)),
|
||||||
|
new OsuReplayFrame(1000, new Vector2(200, 100), OsuAction.LeftButton),
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestInputSingularWithBreak() => CreateModTest(new ModTestData
|
||||||
|
{
|
||||||
|
Mod = new OsuModAlternate(),
|
||||||
|
PassCondition = () => Player.ScoreProcessor.Combo.Value == 2,
|
||||||
|
Autoplay = false,
|
||||||
|
Beatmap = new Beatmap
|
||||||
|
{
|
||||||
|
Breaks = new List<BreakPeriod>
|
||||||
|
{
|
||||||
|
new BreakPeriod(500, 2250),
|
||||||
|
},
|
||||||
|
HitObjects = new List<HitObject>
|
||||||
|
{
|
||||||
|
new HitCircle
|
||||||
|
{
|
||||||
|
StartTime = 500,
|
||||||
|
Position = new Vector2(100),
|
||||||
|
},
|
||||||
|
new HitCircle
|
||||||
|
{
|
||||||
|
StartTime = 2500,
|
||||||
|
Position = new Vector2(100),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ReplayFrames = new List<ReplayFrame>
|
||||||
|
{
|
||||||
|
new OsuReplayFrame(500, new Vector2(100), OsuAction.LeftButton),
|
||||||
|
new OsuReplayFrame(501, new Vector2(100)),
|
||||||
|
new OsuReplayFrame(2500, new Vector2(100), OsuAction.LeftButton),
|
||||||
|
new OsuReplayFrame(2501, new Vector2(100)),
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -145,6 +145,6 @@ namespace osu.Game.Rulesets.Osu.Tests.Mods
|
|||||||
|
|
||||||
private bool isBreak() => Player.IsBreakTime.Value;
|
private bool isBreak() => Player.IsBreakTime.Value;
|
||||||
|
|
||||||
private bool cursorAlphaAlmostEquals(float alpha) => Precision.AlmostEquals(Player.DrawableRuleset.Cursor.Alpha, alpha);
|
private bool cursorAlphaAlmostEquals(float alpha) => Precision.AlmostEquals(Player.DrawableRuleset.Cursor.Alpha, alpha, 0.1f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -118,7 +118,6 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
public Drawable GetDrawableComponent(ISkinComponent component) => null;
|
public Drawable GetDrawableComponent(ISkinComponent component) => null;
|
||||||
public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => null;
|
public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => null;
|
||||||
public ISample GetSample(ISampleInfo sampleInfo) => null;
|
public ISample GetSample(ISampleInfo sampleInfo) => null;
|
||||||
public ISkin FindProvider(Func<ISkin, bool> lookupFunction) => null;
|
|
||||||
|
|
||||||
public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup)
|
public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup)
|
||||||
{
|
{
|
||||||
|
83
osu.Game.Rulesets.Osu/Mods/OsuModAimAssist.cs
Normal file
83
osu.Game.Rulesets.Osu/Mods/OsuModAimAssist.cs
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Framework.Utils;
|
||||||
|
using osu.Game.Configuration;
|
||||||
|
using osu.Game.Rulesets.Mods;
|
||||||
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
|
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||||
|
using osu.Game.Rulesets.Osu.UI;
|
||||||
|
using osu.Game.Rulesets.UI;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Osu.Mods
|
||||||
|
{
|
||||||
|
internal class OsuModAimAssist : Mod, IUpdatableByPlayfield, IApplicableToDrawableRuleset<OsuHitObject>
|
||||||
|
{
|
||||||
|
public override string Name => "Aim Assist";
|
||||||
|
public override string Acronym => "AA";
|
||||||
|
public override IconUsage? Icon => FontAwesome.Solid.MousePointer;
|
||||||
|
public override ModType Type => ModType.Fun;
|
||||||
|
public override string Description => "No need to chase the circle – the circle chases you!";
|
||||||
|
public override double ScoreMultiplier => 1;
|
||||||
|
public override Type[] IncompatibleMods => new[] { typeof(OsuModAutopilot), typeof(OsuModWiggle), typeof(OsuModTransform), typeof(ModAutoplay) };
|
||||||
|
|
||||||
|
private IFrameStableClock gameplayClock;
|
||||||
|
|
||||||
|
[SettingSource("Assist strength", "How much this mod will assist you.", 0)]
|
||||||
|
public BindableFloat AssistStrength { get; } = new BindableFloat(0.5f)
|
||||||
|
{
|
||||||
|
Precision = 0.05f,
|
||||||
|
MinValue = 0.05f,
|
||||||
|
MaxValue = 1.0f,
|
||||||
|
};
|
||||||
|
|
||||||
|
public void ApplyToDrawableRuleset(DrawableRuleset<OsuHitObject> drawableRuleset)
|
||||||
|
{
|
||||||
|
gameplayClock = drawableRuleset.FrameStableClock;
|
||||||
|
|
||||||
|
// Hide judgment displays and follow points as they won't make any sense.
|
||||||
|
// Judgements can potentially be turned on in a future where they display at a position relative to their drawable counterpart.
|
||||||
|
drawableRuleset.Playfield.DisplayJudgements.Value = false;
|
||||||
|
(drawableRuleset.Playfield as OsuPlayfield)?.FollowPoints.Hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Update(Playfield playfield)
|
||||||
|
{
|
||||||
|
var cursorPos = playfield.Cursor.ActiveCursor.DrawPosition;
|
||||||
|
|
||||||
|
foreach (var drawable in playfield.HitObjectContainer.AliveObjects)
|
||||||
|
{
|
||||||
|
switch (drawable)
|
||||||
|
{
|
||||||
|
case DrawableHitCircle circle:
|
||||||
|
easeTo(circle, cursorPos);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DrawableSlider slider:
|
||||||
|
|
||||||
|
if (!slider.HeadCircle.Result.HasResult)
|
||||||
|
easeTo(slider, cursorPos);
|
||||||
|
else
|
||||||
|
easeTo(slider, cursorPos - slider.Ball.DrawPosition);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void easeTo(DrawableHitObject hitObject, Vector2 destination)
|
||||||
|
{
|
||||||
|
double dampLength = Interpolation.Lerp(3000, 40, AssistStrength.Value);
|
||||||
|
|
||||||
|
float x = (float)Interpolation.DampContinuously(hitObject.X, destination.X, dampLength, gameplayClock.ElapsedFrameTime);
|
||||||
|
float y = (float)Interpolation.DampContinuously(hitObject.Y, destination.Y, dampLength, gameplayClock.ElapsedFrameTime);
|
||||||
|
|
||||||
|
hitObject.Position = new Vector2(x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
106
osu.Game.Rulesets.Osu/Mods/OsuModAlternate.cs
Normal file
106
osu.Game.Rulesets.Osu/Mods/OsuModAlternate.cs
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Framework.Input.Bindings;
|
||||||
|
using osu.Framework.Input.Events;
|
||||||
|
using osu.Game.Rulesets.Mods;
|
||||||
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
using osu.Game.Rulesets.UI;
|
||||||
|
using osu.Game.Screens.Play;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Osu.Mods
|
||||||
|
{
|
||||||
|
public class OsuModAlternate : Mod, IApplicableToDrawableRuleset<OsuHitObject>, IApplicableToPlayer
|
||||||
|
{
|
||||||
|
public override string Name => @"Alternate";
|
||||||
|
public override string Acronym => @"AL";
|
||||||
|
public override string Description => @"Don't use the same key twice in a row!";
|
||||||
|
public override double ScoreMultiplier => 1.0;
|
||||||
|
public override Type[] IncompatibleMods => new[] { typeof(ModAutoplay) };
|
||||||
|
public override ModType Type => ModType.Conversion;
|
||||||
|
public override IconUsage? Icon => FontAwesome.Solid.Keyboard;
|
||||||
|
|
||||||
|
private double firstObjectValidJudgementTime;
|
||||||
|
private IBindable<bool> isBreakTime;
|
||||||
|
private const double flash_duration = 1000;
|
||||||
|
private OsuAction? lastActionPressed;
|
||||||
|
private DrawableRuleset<OsuHitObject> ruleset;
|
||||||
|
|
||||||
|
private IFrameStableClock gameplayClock;
|
||||||
|
|
||||||
|
public void ApplyToDrawableRuleset(DrawableRuleset<OsuHitObject> drawableRuleset)
|
||||||
|
{
|
||||||
|
ruleset = drawableRuleset;
|
||||||
|
drawableRuleset.KeyBindingInputManager.Add(new InputInterceptor(this));
|
||||||
|
|
||||||
|
var firstHitObject = ruleset.Objects.FirstOrDefault();
|
||||||
|
firstObjectValidJudgementTime = (firstHitObject?.StartTime ?? 0) - (firstHitObject?.HitWindows.WindowFor(HitResult.Meh) ?? 0);
|
||||||
|
|
||||||
|
gameplayClock = drawableRuleset.FrameStableClock;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ApplyToPlayer(Player player)
|
||||||
|
{
|
||||||
|
isBreakTime = player.IsBreakTime.GetBoundCopy();
|
||||||
|
isBreakTime.ValueChanged += e =>
|
||||||
|
{
|
||||||
|
if (e.NewValue)
|
||||||
|
lastActionPressed = null;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool checkCorrectAction(OsuAction action)
|
||||||
|
{
|
||||||
|
if (isBreakTime.Value)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (gameplayClock.CurrentTime < firstObjectValidJudgementTime)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
switch (action)
|
||||||
|
{
|
||||||
|
case OsuAction.LeftButton:
|
||||||
|
case OsuAction.RightButton:
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Any action which is not left or right button should be ignored.
|
||||||
|
default:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lastActionPressed != action)
|
||||||
|
{
|
||||||
|
// User alternated correctly.
|
||||||
|
lastActionPressed = action;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ruleset.Cursor.FlashColour(Colour4.Red, flash_duration, Easing.OutQuint);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class InputInterceptor : Component, IKeyBindingHandler<OsuAction>
|
||||||
|
{
|
||||||
|
private readonly OsuModAlternate mod;
|
||||||
|
|
||||||
|
public InputInterceptor(OsuModAlternate mod)
|
||||||
|
{
|
||||||
|
this.mod = mod;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool OnPressed(KeyBindingPressEvent<OsuAction> e)
|
||||||
|
// if the pressed action is incorrect, block it from reaching gameplay.
|
||||||
|
=> !mod.checkCorrectAction(e.Action);
|
||||||
|
|
||||||
|
public void OnReleased(KeyBindingReleaseEvent<OsuAction> e)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
public override ModType Type => ModType.Automation;
|
public override ModType Type => ModType.Automation;
|
||||||
public override string Description => @"Automatic cursor movement - just follow the rhythm.";
|
public override string Description => @"Automatic cursor movement - just follow the rhythm.";
|
||||||
public override double ScoreMultiplier => 1;
|
public override double ScoreMultiplier => 1;
|
||||||
public override Type[] IncompatibleMods => new[] { typeof(OsuModSpunOut), typeof(ModRelax), typeof(ModFailCondition), typeof(ModNoFail), typeof(ModAutoplay) };
|
public override Type[] IncompatibleMods => new[] { typeof(OsuModSpunOut), typeof(ModRelax), typeof(ModFailCondition), typeof(ModNoFail), typeof(ModAutoplay), typeof(OsuModAimAssist) };
|
||||||
|
|
||||||
public bool PerformFail() => false;
|
public bool PerformFail() => false;
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
{
|
{
|
||||||
public class OsuModAutoplay : ModAutoplay
|
public class OsuModAutoplay : ModAutoplay
|
||||||
{
|
{
|
||||||
public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(OsuModAutopilot)).Append(typeof(OsuModSpunOut)).ToArray();
|
public override Type[] IncompatibleMods => base.IncompatibleMods.Concat(new[] { typeof(OsuModAimAssist), typeof(OsuModAutopilot), typeof(OsuModSpunOut) }).ToArray();
|
||||||
|
|
||||||
public override Score CreateReplayScore(IBeatmap beatmap, IReadOnlyList<Mod> mods) => new Score
|
public override Score CreateReplayScore(IBeatmap beatmap, IReadOnlyList<Mod> mods) => new Score
|
||||||
{
|
{
|
||||||
|
@ -15,7 +15,7 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
{
|
{
|
||||||
public class OsuModCinema : ModCinema<OsuHitObject>
|
public class OsuModCinema : ModCinema<OsuHitObject>
|
||||||
{
|
{
|
||||||
public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(OsuModAutopilot)).Append(typeof(OsuModSpunOut)).ToArray();
|
public override Type[] IncompatibleMods => base.IncompatibleMods.Concat(new[] { typeof(OsuModAimAssist), typeof(OsuModAutopilot), typeof(OsuModSpunOut) }).ToArray();
|
||||||
|
|
||||||
public override Score CreateReplayScore(IBeatmap beatmap, IReadOnlyList<Mod> mods) => new Score
|
public override Score CreateReplayScore(IBeatmap beatmap, IReadOnlyList<Mod> mods) => new Score
|
||||||
{
|
{
|
||||||
|
@ -31,7 +31,7 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
};
|
};
|
||||||
|
|
||||||
[SettingSource("Flashlight size", "Multiplier applied to the default flashlight size.")]
|
[SettingSource("Flashlight size", "Multiplier applied to the default flashlight size.")]
|
||||||
public override BindableNumber<float> SizeMultiplier { get; } = new BindableNumber<float>
|
public override BindableFloat SizeMultiplier { get; } = new BindableFloat
|
||||||
{
|
{
|
||||||
MinValue = 0.5f,
|
MinValue = 0.5f,
|
||||||
MaxValue = 2f,
|
MaxValue = 2f,
|
||||||
|
@ -20,7 +20,7 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
public override ModType Type => ModType.Fun;
|
public override ModType Type => ModType.Fun;
|
||||||
public override string Description => "Everything rotates. EVERYTHING.";
|
public override string Description => "Everything rotates. EVERYTHING.";
|
||||||
public override double ScoreMultiplier => 1;
|
public override double ScoreMultiplier => 1;
|
||||||
public override Type[] IncompatibleMods => new[] { typeof(OsuModWiggle) };
|
public override Type[] IncompatibleMods => new[] { typeof(OsuModWiggle), typeof(OsuModAimAssist) };
|
||||||
|
|
||||||
private float theta;
|
private float theta;
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
public override ModType Type => ModType.Fun;
|
public override ModType Type => ModType.Fun;
|
||||||
public override string Description => "They just won't stay still...";
|
public override string Description => "They just won't stay still...";
|
||||||
public override double ScoreMultiplier => 1;
|
public override double ScoreMultiplier => 1;
|
||||||
public override Type[] IncompatibleMods => new[] { typeof(OsuModTransform) };
|
public override Type[] IncompatibleMods => new[] { typeof(OsuModTransform), typeof(OsuModAimAssist) };
|
||||||
|
|
||||||
private const int wiggle_duration = 90; // (ms) Higher = fewer wiggles
|
private const int wiggle_duration = 90; // (ms) Higher = fewer wiggles
|
||||||
private const int wiggle_strength = 10; // Higher = stronger wiggles
|
private const int wiggle_strength = 10; // Higher = stronger wiggles
|
||||||
|
@ -169,6 +169,7 @@ namespace osu.Game.Rulesets.Osu
|
|||||||
new OsuModClassic(),
|
new OsuModClassic(),
|
||||||
new OsuModRandom(),
|
new OsuModRandom(),
|
||||||
new OsuModMirror(),
|
new OsuModMirror(),
|
||||||
|
new OsuModAlternate(),
|
||||||
};
|
};
|
||||||
|
|
||||||
case ModType.Automation:
|
case ModType.Automation:
|
||||||
@ -193,6 +194,7 @@ namespace osu.Game.Rulesets.Osu
|
|||||||
new OsuModApproachDifferent(),
|
new OsuModApproachDifferent(),
|
||||||
new OsuModMuted(),
|
new OsuModMuted(),
|
||||||
new OsuModNoScope(),
|
new OsuModNoScope(),
|
||||||
|
new OsuModAimAssist(),
|
||||||
};
|
};
|
||||||
|
|
||||||
case ModType.System:
|
case ModType.System:
|
||||||
|
@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Osu.Replays
|
|||||||
|
|
||||||
protected override bool IsImportant(OsuReplayFrame frame) => frame.Actions.Any();
|
protected override bool IsImportant(OsuReplayFrame frame) => frame.Actions.Any();
|
||||||
|
|
||||||
public override void CollectPendingInputs(List<IInput> inputs)
|
protected override void CollectReplayInputs(List<IInput> inputs)
|
||||||
{
|
{
|
||||||
var position = Interpolation.ValueAt(CurrentTime, StartFrame.Position, EndFrame.Position, StartFrame.Time, EndFrame.Time);
|
var position = Interpolation.ValueAt(CurrentTime, StartFrame.Position, EndFrame.Position, StartFrame.Time, EndFrame.Time);
|
||||||
|
|
||||||
|
@ -31,7 +31,8 @@ namespace osu.Game.Rulesets.Osu.UI
|
|||||||
private readonly ProxyContainer approachCircles;
|
private readonly ProxyContainer approachCircles;
|
||||||
private readonly ProxyContainer spinnerProxies;
|
private readonly ProxyContainer spinnerProxies;
|
||||||
private readonly JudgementContainer<DrawableOsuJudgement> judgementLayer;
|
private readonly JudgementContainer<DrawableOsuJudgement> judgementLayer;
|
||||||
private readonly FollowPointRenderer followPoints;
|
|
||||||
|
public FollowPointRenderer FollowPoints { get; }
|
||||||
|
|
||||||
public static readonly Vector2 BASE_SIZE = new Vector2(512, 384);
|
public static readonly Vector2 BASE_SIZE = new Vector2(512, 384);
|
||||||
|
|
||||||
@ -50,7 +51,7 @@ namespace osu.Game.Rulesets.Osu.UI
|
|||||||
{
|
{
|
||||||
playfieldBorder = new PlayfieldBorder { RelativeSizeAxes = Axes.Both },
|
playfieldBorder = new PlayfieldBorder { RelativeSizeAxes = Axes.Both },
|
||||||
spinnerProxies = new ProxyContainer { RelativeSizeAxes = Axes.Both },
|
spinnerProxies = new ProxyContainer { RelativeSizeAxes = Axes.Both },
|
||||||
followPoints = new FollowPointRenderer { RelativeSizeAxes = Axes.Both },
|
FollowPoints = new FollowPointRenderer { RelativeSizeAxes = Axes.Both },
|
||||||
judgementLayer = new JudgementContainer<DrawableOsuJudgement> { RelativeSizeAxes = Axes.Both },
|
judgementLayer = new JudgementContainer<DrawableOsuJudgement> { RelativeSizeAxes = Axes.Both },
|
||||||
HitObjectContainer,
|
HitObjectContainer,
|
||||||
judgementAboveHitObjectLayer = new Container { RelativeSizeAxes = Axes.Both },
|
judgementAboveHitObjectLayer = new Container { RelativeSizeAxes = Axes.Both },
|
||||||
@ -131,13 +132,13 @@ namespace osu.Game.Rulesets.Osu.UI
|
|||||||
protected override void OnHitObjectAdded(HitObject hitObject)
|
protected override void OnHitObjectAdded(HitObject hitObject)
|
||||||
{
|
{
|
||||||
base.OnHitObjectAdded(hitObject);
|
base.OnHitObjectAdded(hitObject);
|
||||||
followPoints.AddFollowPoints((OsuHitObject)hitObject);
|
FollowPoints.AddFollowPoints((OsuHitObject)hitObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnHitObjectRemoved(HitObject hitObject)
|
protected override void OnHitObjectRemoved(HitObject hitObject)
|
||||||
{
|
{
|
||||||
base.OnHitObjectRemoved(hitObject);
|
base.OnHitObjectRemoved(hitObject);
|
||||||
followPoints.RemoveFollowPoints((OsuHitObject)hitObject);
|
FollowPoints.RemoveFollowPoints((OsuHitObject)hitObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onNewResult(DrawableHitObject judgedObject, JudgementResult result)
|
private void onNewResult(DrawableHitObject judgedObject, JudgementResult result)
|
||||||
|
@ -55,7 +55,7 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
|
|||||||
|
|
||||||
Beatmap<TaikoHitObject> converted = base.ConvertBeatmap(original, cancellationToken);
|
Beatmap<TaikoHitObject> converted = base.ConvertBeatmap(original, cancellationToken);
|
||||||
|
|
||||||
if (original.BeatmapInfo.RulesetID == 3)
|
if (original.BeatmapInfo.Ruleset.OnlineID == 3)
|
||||||
{
|
{
|
||||||
// Post processing step to transform mania hit objects with the same start time into strong hits
|
// Post processing step to transform mania hit objects with the same start time into strong hits
|
||||||
converted.HitObjects = converted.HitObjects.GroupBy(t => t.StartTime).Select(x =>
|
converted.HitObjects = converted.HitObjects.GroupBy(t => t.StartTime).Select(x =>
|
||||||
|
@ -18,7 +18,7 @@ namespace osu.Game.Rulesets.Taiko.Mods
|
|||||||
public override double ScoreMultiplier => 1.12;
|
public override double ScoreMultiplier => 1.12;
|
||||||
|
|
||||||
[SettingSource("Flashlight size", "Multiplier applied to the default flashlight size.")]
|
[SettingSource("Flashlight size", "Multiplier applied to the default flashlight size.")]
|
||||||
public override BindableNumber<float> SizeMultiplier { get; } = new BindableNumber<float>
|
public override BindableFloat SizeMultiplier { get; } = new BindableFloat
|
||||||
{
|
{
|
||||||
MinValue = 0.5f,
|
MinValue = 0.5f,
|
||||||
MaxValue = 1.5f,
|
MaxValue = 1.5f,
|
||||||
|
@ -18,7 +18,7 @@ namespace osu.Game.Rulesets.Taiko.Replays
|
|||||||
|
|
||||||
protected override bool IsImportant(TaikoReplayFrame frame) => frame.Actions.Any();
|
protected override bool IsImportant(TaikoReplayFrame frame) => frame.Actions.Any();
|
||||||
|
|
||||||
public override void CollectPendingInputs(List<IInput> inputs)
|
protected override void CollectReplayInputs(List<IInput> inputs)
|
||||||
{
|
{
|
||||||
inputs.Add(new ReplayState<TaikoAction> { PressedActions = CurrentFrame?.Actions ?? new List<TaikoAction>() });
|
inputs.Add(new ReplayState<TaikoAction> { PressedActions = CurrentFrame?.Actions ?? new List<TaikoAction>() });
|
||||||
}
|
}
|
||||||
|
@ -60,7 +60,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
|||||||
Assert.AreEqual(0, beatmapInfo.AudioLeadIn);
|
Assert.AreEqual(0, beatmapInfo.AudioLeadIn);
|
||||||
Assert.AreEqual(164471, metadata.PreviewTime);
|
Assert.AreEqual(164471, metadata.PreviewTime);
|
||||||
Assert.AreEqual(0.7f, beatmapInfo.StackLeniency);
|
Assert.AreEqual(0.7f, beatmapInfo.StackLeniency);
|
||||||
Assert.IsTrue(beatmapInfo.RulesetID == 0);
|
Assert.IsTrue(beatmapInfo.Ruleset.OnlineID == 0);
|
||||||
Assert.IsFalse(beatmapInfo.LetterboxInBreaks);
|
Assert.IsFalse(beatmapInfo.LetterboxInBreaks);
|
||||||
Assert.IsFalse(beatmapInfo.SpecialStyle);
|
Assert.IsFalse(beatmapInfo.SpecialStyle);
|
||||||
Assert.IsFalse(beatmapInfo.WidescreenStoryboard);
|
Assert.IsFalse(beatmapInfo.WidescreenStoryboard);
|
||||||
@ -794,5 +794,74 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
|||||||
Assert.That(path.Distance, Is.EqualTo(1));
|
Assert.That(path.Distance, Is.EqualTo(1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestLegacyDefaultsPreserved()
|
||||||
|
{
|
||||||
|
var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false };
|
||||||
|
|
||||||
|
using (var memoryStream = new MemoryStream())
|
||||||
|
using (var stream = new LineBufferedReader(memoryStream))
|
||||||
|
{
|
||||||
|
var decoded = decoder.Decode(stream);
|
||||||
|
|
||||||
|
Assert.Multiple(() =>
|
||||||
|
{
|
||||||
|
Assert.That(decoded.BeatmapInfo.AudioLeadIn, Is.EqualTo(0));
|
||||||
|
Assert.That(decoded.BeatmapInfo.StackLeniency, Is.EqualTo(0.7f));
|
||||||
|
Assert.That(decoded.BeatmapInfo.SpecialStyle, Is.False);
|
||||||
|
Assert.That(decoded.BeatmapInfo.LetterboxInBreaks, Is.False);
|
||||||
|
Assert.That(decoded.BeatmapInfo.WidescreenStoryboard, Is.False);
|
||||||
|
Assert.That(decoded.BeatmapInfo.EpilepsyWarning, Is.False);
|
||||||
|
Assert.That(decoded.BeatmapInfo.SamplesMatchPlaybackRate, Is.False);
|
||||||
|
Assert.That(decoded.BeatmapInfo.Countdown, Is.EqualTo(CountdownType.Normal));
|
||||||
|
Assert.That(decoded.BeatmapInfo.CountdownOffset, Is.EqualTo(0));
|
||||||
|
Assert.That(decoded.BeatmapInfo.Metadata.PreviewTime, Is.EqualTo(-1));
|
||||||
|
Assert.That(decoded.BeatmapInfo.Ruleset.OnlineID, Is.EqualTo(0));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestUndefinedApproachRateInheritsOverallDifficulty()
|
||||||
|
{
|
||||||
|
var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false };
|
||||||
|
|
||||||
|
using (var resStream = TestResources.OpenResource("undefined-approach-rate.osu"))
|
||||||
|
using (var stream = new LineBufferedReader(resStream))
|
||||||
|
{
|
||||||
|
var decoded = decoder.Decode(stream);
|
||||||
|
Assert.That(decoded.Difficulty.ApproachRate, Is.EqualTo(1));
|
||||||
|
Assert.That(decoded.Difficulty.OverallDifficulty, Is.EqualTo(1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestApproachRateDefinedBeforeOverallDifficulty()
|
||||||
|
{
|
||||||
|
var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false };
|
||||||
|
|
||||||
|
using (var resStream = TestResources.OpenResource("approach-rate-before-overall-difficulty.osu"))
|
||||||
|
using (var stream = new LineBufferedReader(resStream))
|
||||||
|
{
|
||||||
|
var decoded = decoder.Decode(stream);
|
||||||
|
Assert.That(decoded.Difficulty.ApproachRate, Is.EqualTo(9));
|
||||||
|
Assert.That(decoded.Difficulty.OverallDifficulty, Is.EqualTo(1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestApproachRateDefinedAfterOverallDifficulty()
|
||||||
|
{
|
||||||
|
var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false };
|
||||||
|
|
||||||
|
using (var resStream = TestResources.OpenResource("approach-rate-after-overall-difficulty.osu"))
|
||||||
|
using (var stream = new LineBufferedReader(resStream))
|
||||||
|
{
|
||||||
|
var decoded = decoder.Decode(stream);
|
||||||
|
Assert.That(decoded.Difficulty.ApproachRate, Is.EqualTo(9));
|
||||||
|
Assert.That(decoded.Difficulty.OverallDifficulty, Is.EqualTo(1));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -195,7 +195,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
|||||||
|
|
||||||
private IBeatmap convert(IBeatmap beatmap)
|
private IBeatmap convert(IBeatmap beatmap)
|
||||||
{
|
{
|
||||||
switch (beatmap.BeatmapInfo.RulesetID)
|
switch (beatmap.BeatmapInfo.Ruleset.OnlineID)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
beatmap.BeatmapInfo.Ruleset = new OsuRuleset().RulesetInfo;
|
beatmap.BeatmapInfo.Ruleset = new OsuRuleset().RulesetInfo;
|
||||||
|
@ -52,7 +52,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
|||||||
Assert.AreEqual(0, beatmapInfo.AudioLeadIn);
|
Assert.AreEqual(0, beatmapInfo.AudioLeadIn);
|
||||||
Assert.AreEqual(0.7f, beatmapInfo.StackLeniency);
|
Assert.AreEqual(0.7f, beatmapInfo.StackLeniency);
|
||||||
Assert.AreEqual(false, beatmapInfo.SpecialStyle);
|
Assert.AreEqual(false, beatmapInfo.SpecialStyle);
|
||||||
Assert.IsTrue(beatmapInfo.RulesetID == 0);
|
Assert.IsTrue(beatmapInfo.Ruleset.OnlineID == 0);
|
||||||
Assert.AreEqual(false, beatmapInfo.LetterboxInBreaks);
|
Assert.AreEqual(false, beatmapInfo.LetterboxInBreaks);
|
||||||
Assert.AreEqual(false, beatmapInfo.WidescreenStoryboard);
|
Assert.AreEqual(false, beatmapInfo.WidescreenStoryboard);
|
||||||
Assert.AreEqual(CountdownType.None, beatmapInfo.Countdown);
|
Assert.AreEqual(CountdownType.None, beatmapInfo.Countdown);
|
||||||
|
@ -87,11 +87,6 @@ namespace osu.Game.Tests.Database
|
|||||||
|
|
||||||
hasThreadedUsage.Wait();
|
hasThreadedUsage.Wait();
|
||||||
|
|
||||||
// Usually the host would run the synchronization context work per frame.
|
|
||||||
// For the sake of keeping this test simple (there's only one update invocation),
|
|
||||||
// let's replace it so we can ensure work is run immediately.
|
|
||||||
SynchronizationContext.SetSynchronizationContext(new ImmediateExecuteSynchronizationContext());
|
|
||||||
|
|
||||||
Assert.Throws<TimeoutException>(() =>
|
Assert.Throws<TimeoutException>(() =>
|
||||||
{
|
{
|
||||||
using (realm.BlockAllOperations())
|
using (realm.BlockAllOperations())
|
||||||
@ -107,10 +102,5 @@ namespace osu.Game.Tests.Database
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ImmediateExecuteSynchronizationContext : SynchronizationContext
|
|
||||||
{
|
|
||||||
public override void Post(SendOrPostCallback d, object? state) => d(state);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,16 +47,14 @@ namespace osu.Game.Tests.Database
|
|||||||
liveBeatmap = beatmap.ToLive(realm);
|
liveBeatmap = beatmap.ToLive(realm);
|
||||||
});
|
});
|
||||||
|
|
||||||
using (realm.BlockAllOperations())
|
|
||||||
{
|
|
||||||
// recycle realm before migrating
|
|
||||||
}
|
|
||||||
|
|
||||||
using (var migratedStorage = new TemporaryNativeStorage("realm-test-migration-target"))
|
using (var migratedStorage = new TemporaryNativeStorage("realm-test-migration-target"))
|
||||||
{
|
{
|
||||||
migratedStorage.DeleteDirectory(string.Empty);
|
migratedStorage.DeleteDirectory(string.Empty);
|
||||||
|
|
||||||
|
using (realm.BlockAllOperations())
|
||||||
|
{
|
||||||
storage.Migrate(migratedStorage);
|
storage.Migrate(migratedStorage);
|
||||||
|
}
|
||||||
|
|
||||||
Assert.IsFalse(liveBeatmap?.PerformRead(l => l.Hidden));
|
Assert.IsFalse(liveBeatmap?.PerformRead(l => l.Hidden));
|
||||||
}
|
}
|
||||||
|
@ -114,7 +114,7 @@ namespace osu.Game.Tests.Database
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected static RulesetInfo CreateRuleset() =>
|
protected static RulesetInfo CreateRuleset() =>
|
||||||
new RulesetInfo(0, "osu!", "osu", true);
|
new RulesetInfo("osu", "osu!", string.Empty, 0) { Available = true };
|
||||||
|
|
||||||
private class RealmTestGame : Framework.Game
|
private class RealmTestGame : Framework.Game
|
||||||
{
|
{
|
||||||
|
@ -52,7 +52,7 @@ namespace osu.Game.Tests.Editing.Checks
|
|||||||
beatmap.BeatmapInfo.BeatmapSet.Files.Add(CheckTestHelpers.CreateMockFile("jpg"));
|
beatmap.BeatmapInfo.BeatmapSet.Files.Add(CheckTestHelpers.CreateMockFile("jpg"));
|
||||||
|
|
||||||
// Should fail to load, but not produce an error due to the extension not being expected to load.
|
// Should fail to load, but not produce an error due to the extension not being expected to load.
|
||||||
Assert.IsEmpty(check.Run(getContext(null, allowMissing: true)));
|
Assert.IsEmpty(check.Run(getContext(null)));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@ -91,7 +91,7 @@ namespace osu.Game.Tests.Editing.Checks
|
|||||||
{
|
{
|
||||||
using (var resourceStream = TestResources.OpenResource("Samples/missing.mp3"))
|
using (var resourceStream = TestResources.OpenResource("Samples/missing.mp3"))
|
||||||
{
|
{
|
||||||
Assert.IsEmpty(check.Run(getContext(resourceStream, allowMissing: true)));
|
Assert.IsEmpty(check.Run(getContext(resourceStream)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,7 +107,7 @@ namespace osu.Game.Tests.Editing.Checks
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private BeatmapVerifierContext getContext(Stream resourceStream, bool allowMissing = false)
|
private BeatmapVerifierContext getContext(Stream resourceStream)
|
||||||
{
|
{
|
||||||
var mockWorkingBeatmap = new Mock<TestWorkingBeatmap>(beatmap, null, null);
|
var mockWorkingBeatmap = new Mock<TestWorkingBeatmap>(beatmap, null, null);
|
||||||
mockWorkingBeatmap.Setup(w => w.GetStream(It.IsAny<string>())).Returns(resourceStream);
|
mockWorkingBeatmap.Setup(w => w.GetStream(It.IsAny<string>())).Returns(resourceStream);
|
||||||
|
@ -131,8 +131,6 @@ namespace osu.Game.Tests.Gameplay
|
|||||||
|
|
||||||
public ISample GetSample(ISampleInfo sampleInfo) => throw new NotImplementedException();
|
public ISample GetSample(ISampleInfo sampleInfo) => throw new NotImplementedException();
|
||||||
|
|
||||||
public ISkin FindProvider(Func<ISkin, bool> lookupFunction) => null;
|
|
||||||
|
|
||||||
public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup)
|
public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup)
|
||||||
{
|
{
|
||||||
switch (lookup)
|
switch (lookup)
|
||||||
|
@ -2,7 +2,13 @@
|
|||||||
// 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 NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Audio;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
|
using osu.Framework.Timing;
|
||||||
|
using osu.Framework.Utils;
|
||||||
|
using osu.Game.Configuration;
|
||||||
using osu.Game.Rulesets.Osu;
|
using osu.Game.Rulesets.Osu;
|
||||||
using osu.Game.Screens.Play;
|
using osu.Game.Screens.Play;
|
||||||
using osu.Game.Tests.Visual;
|
using osu.Game.Tests.Visual;
|
||||||
@ -12,47 +18,93 @@ namespace osu.Game.Tests.Gameplay
|
|||||||
[HeadlessTest]
|
[HeadlessTest]
|
||||||
public class TestSceneMasterGameplayClockContainer : OsuTestScene
|
public class TestSceneMasterGameplayClockContainer : OsuTestScene
|
||||||
{
|
{
|
||||||
|
private OsuConfigManager localConfig;
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
Dependencies.Cache(localConfig = new OsuConfigManager(LocalStorage));
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestStartThenElapsedTime()
|
public void TestStartThenElapsedTime()
|
||||||
{
|
{
|
||||||
GameplayClockContainer gcc = null;
|
GameplayClockContainer gameplayClockContainer = null;
|
||||||
|
|
||||||
AddStep("create container", () =>
|
AddStep("create container", () =>
|
||||||
{
|
{
|
||||||
var working = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo);
|
var working = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo);
|
||||||
working.LoadTrack();
|
working.LoadTrack();
|
||||||
|
|
||||||
Add(gcc = new MasterGameplayClockContainer(working, 0));
|
Add(gameplayClockContainer = new MasterGameplayClockContainer(working, 0));
|
||||||
});
|
});
|
||||||
|
|
||||||
AddStep("start clock", () => gcc.Start());
|
AddStep("start clock", () => gameplayClockContainer.Start());
|
||||||
AddUntilStep("elapsed greater than zero", () => gcc.GameplayClock.ElapsedFrameTime > 0);
|
AddUntilStep("elapsed greater than zero", () => gameplayClockContainer.GameplayClock.ElapsedFrameTime > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestElapseThenReset()
|
public void TestElapseThenReset()
|
||||||
{
|
{
|
||||||
GameplayClockContainer gcc = null;
|
GameplayClockContainer gameplayClockContainer = null;
|
||||||
|
|
||||||
AddStep("create container", () =>
|
AddStep("create container", () =>
|
||||||
{
|
{
|
||||||
var working = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo);
|
var working = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo);
|
||||||
working.LoadTrack();
|
working.LoadTrack();
|
||||||
|
|
||||||
Add(gcc = new MasterGameplayClockContainer(working, 0));
|
Add(gameplayClockContainer = new MasterGameplayClockContainer(working, 0));
|
||||||
});
|
});
|
||||||
|
|
||||||
AddStep("start clock", () => gcc.Start());
|
AddStep("start clock", () => gameplayClockContainer.Start());
|
||||||
AddUntilStep("current time greater 2000", () => gcc.GameplayClock.CurrentTime > 2000);
|
AddUntilStep("current time greater 2000", () => gameplayClockContainer.GameplayClock.CurrentTime > 2000);
|
||||||
|
|
||||||
double timeAtReset = 0;
|
double timeAtReset = 0;
|
||||||
AddStep("reset clock", () =>
|
AddStep("reset clock", () =>
|
||||||
{
|
{
|
||||||
timeAtReset = gcc.GameplayClock.CurrentTime;
|
timeAtReset = gameplayClockContainer.GameplayClock.CurrentTime;
|
||||||
gcc.Reset();
|
gameplayClockContainer.Reset();
|
||||||
});
|
});
|
||||||
|
|
||||||
AddAssert("current time < time at reset", () => gcc.GameplayClock.CurrentTime < timeAtReset);
|
AddAssert("current time < time at reset", () => gameplayClockContainer.GameplayClock.CurrentTime < timeAtReset);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestSeekPerformsInGameplayTime(
|
||||||
|
[Values(1.0, 0.5, 2.0)] double clockRate,
|
||||||
|
[Values(0.0, 200.0, -200.0)] double userOffset,
|
||||||
|
[Values(false, true)] bool whileStopped)
|
||||||
|
{
|
||||||
|
ClockBackedTestWorkingBeatmap working = null;
|
||||||
|
GameplayClockContainer gameplayClockContainer = null;
|
||||||
|
|
||||||
|
AddStep("create container", () =>
|
||||||
|
{
|
||||||
|
working = new ClockBackedTestWorkingBeatmap(new OsuRuleset().RulesetInfo, new FramedClock(new ManualClock()), Audio);
|
||||||
|
working.LoadTrack();
|
||||||
|
|
||||||
|
Add(gameplayClockContainer = new MasterGameplayClockContainer(working, 0));
|
||||||
|
|
||||||
|
if (whileStopped)
|
||||||
|
gameplayClockContainer.Stop();
|
||||||
|
|
||||||
|
gameplayClockContainer.Reset();
|
||||||
|
});
|
||||||
|
|
||||||
|
AddStep($"set clock rate to {clockRate}", () => working.Track.AddAdjustment(AdjustableProperty.Frequency, new BindableDouble(clockRate)));
|
||||||
|
AddStep($"set audio offset to {userOffset}", () => localConfig.SetValue(OsuSetting.AudioOffset, userOffset));
|
||||||
|
|
||||||
|
AddStep("seek to 2500", () => gameplayClockContainer.Seek(2500));
|
||||||
|
AddAssert("gameplay clock time = 2500", () => Precision.AlmostEquals(gameplayClockContainer.CurrentTime, 2500, 10f));
|
||||||
|
|
||||||
|
AddStep("seek to 10000", () => gameplayClockContainer.Seek(10000));
|
||||||
|
AddAssert("gameplay clock time = 10000", () => Precision.AlmostEquals(gameplayClockContainer.CurrentTime, 10000, 10f));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Dispose(bool isDisposing)
|
||||||
|
{
|
||||||
|
localConfig?.Dispose();
|
||||||
|
base.Dispose(isDisposing);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,17 @@
|
|||||||
// 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.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Online.Spectator;
|
||||||
using osu.Game.Rulesets.Judgements;
|
using osu.Game.Rulesets.Judgements;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
|
using osu.Game.Rulesets.Osu;
|
||||||
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
|
using osu.Game.Rulesets.Osu.Replays;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Tests.Visual;
|
using osu.Game.Tests.Visual;
|
||||||
|
|
||||||
@ -42,6 +48,43 @@ namespace osu.Game.Tests.Gameplay
|
|||||||
Assert.That(scoreProcessor.TotalScore.Value, Is.EqualTo(Judgement.LARGE_BONUS_SCORE));
|
Assert.That(scoreProcessor.TotalScore.Value, Is.EqualTo(Judgement.LARGE_BONUS_SCORE));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestResetFromReplayFrame()
|
||||||
|
{
|
||||||
|
var beatmap = new Beatmap<HitObject> { HitObjects = { new HitCircle() } };
|
||||||
|
|
||||||
|
var scoreProcessor = new ScoreProcessor();
|
||||||
|
scoreProcessor.ApplyBeatmap(beatmap);
|
||||||
|
|
||||||
|
scoreProcessor.ApplyResult(new JudgementResult(beatmap.HitObjects[0], new TestJudgement(HitResult.Great)) { Type = HitResult.Great });
|
||||||
|
Assert.That(scoreProcessor.TotalScore.Value, Is.EqualTo(1_000_000));
|
||||||
|
Assert.That(scoreProcessor.JudgedHits, Is.EqualTo(1));
|
||||||
|
|
||||||
|
// No header shouldn't cause any change
|
||||||
|
scoreProcessor.ResetFromReplayFrame(new OsuRuleset(), new OsuReplayFrame());
|
||||||
|
|
||||||
|
Assert.That(scoreProcessor.TotalScore.Value, Is.EqualTo(1_000_000));
|
||||||
|
Assert.That(scoreProcessor.JudgedHits, Is.EqualTo(1));
|
||||||
|
|
||||||
|
// Reset with a miss instead.
|
||||||
|
scoreProcessor.ResetFromReplayFrame(new OsuRuleset(), new OsuReplayFrame
|
||||||
|
{
|
||||||
|
Header = new FrameHeader(0, 0, 0, new Dictionary<HitResult, int> { { HitResult.Miss, 1 } }, DateTimeOffset.Now)
|
||||||
|
});
|
||||||
|
|
||||||
|
Assert.That(scoreProcessor.TotalScore.Value, Is.Zero);
|
||||||
|
Assert.That(scoreProcessor.JudgedHits, Is.EqualTo(1));
|
||||||
|
|
||||||
|
// Reset with no judged hit.
|
||||||
|
scoreProcessor.ResetFromReplayFrame(new OsuRuleset(), new OsuReplayFrame
|
||||||
|
{
|
||||||
|
Header = new FrameHeader(0, 0, 0, new Dictionary<HitResult, int>(), DateTimeOffset.Now)
|
||||||
|
});
|
||||||
|
|
||||||
|
Assert.That(scoreProcessor.TotalScore.Value, Is.Zero);
|
||||||
|
Assert.That(scoreProcessor.JudgedHits, Is.Zero);
|
||||||
|
}
|
||||||
|
|
||||||
private class TestJudgement : Judgement
|
private class TestJudgement : Judgement
|
||||||
{
|
{
|
||||||
public override HitResult MaxResult { get; }
|
public override HitResult MaxResult { get; }
|
||||||
|
@ -16,7 +16,11 @@ namespace osu.Game.Tests.NonVisual.Filtering
|
|||||||
{
|
{
|
||||||
private BeatmapInfo getExampleBeatmap() => new BeatmapInfo
|
private BeatmapInfo getExampleBeatmap() => new BeatmapInfo
|
||||||
{
|
{
|
||||||
Ruleset = new RulesetInfo { OnlineID = 0 },
|
Ruleset = new RulesetInfo
|
||||||
|
{
|
||||||
|
ShortName = "osu",
|
||||||
|
OnlineID = 0
|
||||||
|
},
|
||||||
StarRating = 4.0d,
|
StarRating = 4.0d,
|
||||||
Difficulty = new BeatmapDifficulty
|
Difficulty = new BeatmapDifficulty
|
||||||
{
|
{
|
||||||
@ -57,7 +61,7 @@ namespace osu.Game.Tests.NonVisual.Filtering
|
|||||||
var exampleBeatmapInfo = getExampleBeatmap();
|
var exampleBeatmapInfo = getExampleBeatmap();
|
||||||
var criteria = new FilterCriteria
|
var criteria = new FilterCriteria
|
||||||
{
|
{
|
||||||
Ruleset = new RulesetInfo { OnlineID = 6 }
|
Ruleset = new RulesetInfo { ShortName = "catch" }
|
||||||
};
|
};
|
||||||
var carouselItem = new CarouselBeatmap(exampleBeatmapInfo);
|
var carouselItem = new CarouselBeatmap(exampleBeatmapInfo);
|
||||||
carouselItem.Filter(criteria);
|
carouselItem.Filter(criteria);
|
||||||
@ -78,6 +82,20 @@ namespace osu.Game.Tests.NonVisual.Filtering
|
|||||||
Assert.IsFalse(carouselItem.Filtered.Value);
|
Assert.IsFalse(carouselItem.Filtered.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestCriteriaMatchingConvertedBeatmapsForCustomRulesets()
|
||||||
|
{
|
||||||
|
var exampleBeatmapInfo = getExampleBeatmap();
|
||||||
|
var criteria = new FilterCriteria
|
||||||
|
{
|
||||||
|
Ruleset = new RulesetInfo { OnlineID = -1 },
|
||||||
|
AllowConvertedBeatmaps = true
|
||||||
|
};
|
||||||
|
var carouselItem = new CarouselBeatmap(exampleBeatmapInfo);
|
||||||
|
carouselItem.Filter(criteria);
|
||||||
|
Assert.IsFalse(carouselItem.Filtered.Value);
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
[TestCase(true)]
|
[TestCase(true)]
|
||||||
[TestCase(false)]
|
[TestCase(false)]
|
||||||
|
38
osu.Game.Tests/NonVisual/RulesetInfoOrderingTest.cs
Normal file
38
osu.Game.Tests/NonVisual/RulesetInfoOrderingTest.cs
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
using System.Linq;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using osu.Game.Rulesets;
|
||||||
|
using osu.Game.Rulesets.Catch;
|
||||||
|
using osu.Game.Rulesets.Osu;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.NonVisual
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class RulesetInfoOrderingTest
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public void TestOrdering()
|
||||||
|
{
|
||||||
|
var rulesets = new[]
|
||||||
|
{
|
||||||
|
new RulesetInfo("custom2", "Custom Ruleset 2", string.Empty, -1),
|
||||||
|
new OsuRuleset().RulesetInfo,
|
||||||
|
new RulesetInfo("custom3", "Custom Ruleset 3", string.Empty, -1),
|
||||||
|
new RulesetInfo("custom2", "Custom Ruleset 2", string.Empty, -1),
|
||||||
|
new CatchRuleset().RulesetInfo,
|
||||||
|
new RulesetInfo("custom3", "Custom Ruleset 3", string.Empty, -1),
|
||||||
|
};
|
||||||
|
|
||||||
|
var orderedRulesets = rulesets.OrderBy(r => r);
|
||||||
|
|
||||||
|
// Ensure all customs are after official.
|
||||||
|
Assert.That(orderedRulesets.Select(r => r.OnlineID), Is.EqualTo(new[] { 0, 2, -1, -1, -1, -1 }));
|
||||||
|
|
||||||
|
// Ensure customs are grouped next to each other (ie. stably sorted).
|
||||||
|
Assert.That(orderedRulesets.SkipWhile(r => r.ShortName != "custom2").Skip(1).First().ShortName, Is.EqualTo("custom2"));
|
||||||
|
Assert.That(orderedRulesets.SkipWhile(r => r.ShortName != "custom3").Skip(1).First().ShortName, Is.EqualTo("custom3"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -26,12 +26,16 @@ namespace osu.Game.Tests.NonVisual
|
|||||||
|
|
||||||
score.Statistics[HitResult.Good]++;
|
score.Statistics[HitResult.Good]++;
|
||||||
score.Rank = ScoreRank.X;
|
score.Rank = ScoreRank.X;
|
||||||
|
score.RealmUser.Username = "test";
|
||||||
|
|
||||||
Assert.That(scoreCopy.Statistics[HitResult.Good], Is.EqualTo(10));
|
Assert.That(scoreCopy.Statistics[HitResult.Good], Is.EqualTo(10));
|
||||||
Assert.That(score.Statistics[HitResult.Good], Is.EqualTo(11));
|
Assert.That(score.Statistics[HitResult.Good], Is.EqualTo(11));
|
||||||
|
|
||||||
Assert.That(scoreCopy.Rank, Is.EqualTo(ScoreRank.B));
|
Assert.That(scoreCopy.Rank, Is.EqualTo(ScoreRank.B));
|
||||||
Assert.That(score.Rank, Is.EqualTo(ScoreRank.X));
|
Assert.That(score.Rank, Is.EqualTo(ScoreRank.X));
|
||||||
|
|
||||||
|
Assert.That(scoreCopy.RealmUser.Username, Is.Empty);
|
||||||
|
Assert.That(score.RealmUser.Username, Is.EqualTo("test"));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
@ -61,7 +61,6 @@ namespace osu.Game.Tests.NonVisual.Skinning
|
|||||||
public Drawable GetDrawableComponent(ISkinComponent component) => throw new NotSupportedException();
|
public Drawable GetDrawableComponent(ISkinComponent component) => throw new NotSupportedException();
|
||||||
public ISample GetSample(ISampleInfo sampleInfo) => throw new NotSupportedException();
|
public ISample GetSample(ISampleInfo sampleInfo) => throw new NotSupportedException();
|
||||||
public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) => throw new NotSupportedException();
|
public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) => throw new NotSupportedException();
|
||||||
public ISkin FindProvider(Func<ISkin, bool> lookupFunction) => null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TestAnimationTimeReference : IAnimationTimeReference
|
private class TestAnimationTimeReference : IAnimationTimeReference
|
||||||
|
@ -47,7 +47,7 @@ namespace osu.Game.Tests.Online
|
|||||||
{
|
{
|
||||||
Dependencies.Cache(rulesets = new RulesetStore(Realm));
|
Dependencies.Cache(rulesets = new RulesetStore(Realm));
|
||||||
Dependencies.CacheAs<BeatmapManager>(beatmaps = new TestBeatmapManager(LocalStorage, Realm, rulesets, API, audio, Resources, host, Beatmap.Default));
|
Dependencies.CacheAs<BeatmapManager>(beatmaps = new TestBeatmapManager(LocalStorage, Realm, rulesets, API, audio, Resources, host, Beatmap.Default));
|
||||||
Dependencies.CacheAs<BeatmapModelDownloader>(beatmapDownloader = new TestBeatmapModelDownloader(beatmaps, API, host));
|
Dependencies.CacheAs<BeatmapModelDownloader>(beatmapDownloader = new TestBeatmapModelDownloader(beatmaps, API));
|
||||||
}
|
}
|
||||||
|
|
||||||
[SetUp]
|
[SetUp]
|
||||||
@ -173,14 +173,14 @@ namespace osu.Game.Tests.Online
|
|||||||
|
|
||||||
protected override BeatmapModelManager CreateBeatmapModelManager(Storage storage, RealmAccess realm, RulesetStore rulesets, BeatmapOnlineLookupQueue onlineLookupQueue)
|
protected override BeatmapModelManager CreateBeatmapModelManager(Storage storage, RealmAccess realm, RulesetStore rulesets, BeatmapOnlineLookupQueue onlineLookupQueue)
|
||||||
{
|
{
|
||||||
return new TestBeatmapModelManager(this, storage, realm, rulesets, onlineLookupQueue);
|
return new TestBeatmapModelManager(this, storage, realm, onlineLookupQueue);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class TestBeatmapModelManager : BeatmapModelManager
|
internal class TestBeatmapModelManager : BeatmapModelManager
|
||||||
{
|
{
|
||||||
private readonly TestBeatmapManager testBeatmapManager;
|
private readonly TestBeatmapManager testBeatmapManager;
|
||||||
|
|
||||||
public TestBeatmapModelManager(TestBeatmapManager testBeatmapManager, Storage storage, RealmAccess databaseAccess, RulesetStore rulesetStore, BeatmapOnlineLookupQueue beatmapOnlineLookupQueue)
|
public TestBeatmapModelManager(TestBeatmapManager testBeatmapManager, Storage storage, RealmAccess databaseAccess, BeatmapOnlineLookupQueue beatmapOnlineLookupQueue)
|
||||||
: base(databaseAccess, storage, beatmapOnlineLookupQueue)
|
: base(databaseAccess, storage, beatmapOnlineLookupQueue)
|
||||||
{
|
{
|
||||||
this.testBeatmapManager = testBeatmapManager;
|
this.testBeatmapManager = testBeatmapManager;
|
||||||
@ -196,7 +196,7 @@ namespace osu.Game.Tests.Online
|
|||||||
|
|
||||||
internal class TestBeatmapModelDownloader : BeatmapModelDownloader
|
internal class TestBeatmapModelDownloader : BeatmapModelDownloader
|
||||||
{
|
{
|
||||||
public TestBeatmapModelDownloader(IModelImporter<BeatmapSetInfo> importer, IAPIProvider apiProvider, GameHost gameHost)
|
public TestBeatmapModelDownloader(IModelImporter<BeatmapSetInfo> importer, IAPIProvider apiProvider)
|
||||||
: base(importer, apiProvider)
|
: base(importer, apiProvider)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,3 @@
|
|||||||
|
[Difficulty]
|
||||||
|
OverallDifficulty:1
|
||||||
|
ApproachRate:9
|
@ -0,0 +1,3 @@
|
|||||||
|
[Difficulty]
|
||||||
|
ApproachRate:9
|
||||||
|
OverallDifficulty:1
|
2
osu.Game.Tests/Resources/undefined-approach-rate.osu
Normal file
2
osu.Game.Tests/Resources/undefined-approach-rate.osu
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
[Difficulty]
|
||||||
|
OverallDifficulty:1
|
@ -82,8 +82,8 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
AddStep("set target difficulty", () =>
|
AddStep("set target difficulty", () =>
|
||||||
{
|
{
|
||||||
targetDifficulty = sameRuleset
|
targetDifficulty = sameRuleset
|
||||||
? importedBeatmapSet.Beatmaps.Last(beatmap => !beatmap.Equals(Beatmap.Value.BeatmapInfo) && beatmap.RulesetID == Beatmap.Value.BeatmapInfo.RulesetID)
|
? importedBeatmapSet.Beatmaps.Last(beatmap => !beatmap.Equals(Beatmap.Value.BeatmapInfo) && beatmap.Ruleset.ShortName == Beatmap.Value.BeatmapInfo.Ruleset.ShortName)
|
||||||
: importedBeatmapSet.Beatmaps.Last(beatmap => !beatmap.Equals(Beatmap.Value.BeatmapInfo) && beatmap.RulesetID != Beatmap.Value.BeatmapInfo.RulesetID);
|
: importedBeatmapSet.Beatmaps.Last(beatmap => !beatmap.Equals(Beatmap.Value.BeatmapInfo) && beatmap.Ruleset.ShortName != Beatmap.Value.BeatmapInfo.Ruleset.ShortName);
|
||||||
});
|
});
|
||||||
switchToDifficulty(() => targetDifficulty);
|
switchToDifficulty(() => targetDifficulty);
|
||||||
confirmEditingBeatmap(() => targetDifficulty);
|
confirmEditingBeatmap(() => targetDifficulty);
|
||||||
|
@ -4,11 +4,13 @@
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Screens;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Framework.Utils;
|
using osu.Framework.Utils;
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Game.Screens.Edit;
|
using osu.Game.Screens.Edit;
|
||||||
using osu.Game.Screens.Edit.Compose.Components.Timeline;
|
using osu.Game.Screens.Edit.Compose.Components.Timeline;
|
||||||
|
using osu.Game.Screens.Select;
|
||||||
using osuTK.Input;
|
using osuTK.Input;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual.Editing
|
namespace osu.Game.Tests.Visual.Editing
|
||||||
@ -116,5 +118,24 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
EditorBeatmap.HitObjects[0].SampleControlPoint != SampleControlPoint.DEFAULT &&
|
EditorBeatmap.HitObjects[0].SampleControlPoint != SampleControlPoint.DEFAULT &&
|
||||||
EditorBeatmap.HitObjects[0].DifficultyControlPoint != DifficultyControlPoint.DEFAULT);
|
EditorBeatmap.HitObjects[0].DifficultyControlPoint != DifficultyControlPoint.DEFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestExitWithoutSaveFromExistingBeatmap()
|
||||||
|
{
|
||||||
|
const string tags_to_save = "these tags will be saved";
|
||||||
|
const string tags_to_discard = "these tags should be discarded";
|
||||||
|
|
||||||
|
AddStep("Set tags", () => EditorBeatmap.BeatmapInfo.Metadata.Tags = tags_to_save);
|
||||||
|
SaveEditor();
|
||||||
|
AddAssert("Tags saved correctly", () => EditorBeatmap.BeatmapInfo.Metadata.Tags == tags_to_save);
|
||||||
|
|
||||||
|
ReloadEditorToSameBeatmap();
|
||||||
|
AddAssert("Tags saved correctly", () => EditorBeatmap.BeatmapInfo.Metadata.Tags == tags_to_save);
|
||||||
|
AddStep("Set tags again", () => EditorBeatmap.BeatmapInfo.Metadata.Tags = tags_to_discard);
|
||||||
|
|
||||||
|
AddStep("Exit editor", () => Editor.Exit());
|
||||||
|
AddUntilStep("Wait for song select", () => Game.ScreenStack.CurrentScreen is PlaySongSelect);
|
||||||
|
AddAssert("Tags reverted correctly", () => Game.Beatmap.Value.BeatmapInfo.Metadata.Tags == tags_to_save);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,7 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap, Storyboard storyboard = null)
|
protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap, Storyboard storyboard = null)
|
||||||
=> beatmaps.GetWorkingBeatmap(importedBeatmapSet.Beatmaps.First(b => b.RulesetID == 0));
|
=> beatmaps.GetWorkingBeatmap(importedBeatmapSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0));
|
||||||
|
|
||||||
protected override void LoadEditor()
|
protected override void LoadEditor()
|
||||||
{
|
{
|
||||||
@ -70,7 +70,11 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
AddUntilStep("current screen is editor", () => Stack.CurrentScreen is Editor);
|
AddUntilStep("current screen is editor", () => Stack.CurrentScreen is Editor);
|
||||||
AddUntilStep("background has correct params", () =>
|
AddUntilStep("background has correct params", () =>
|
||||||
{
|
{
|
||||||
var background = this.ChildrenOfType<BackgroundScreenBeatmap>().Single();
|
// the test gameplay player's beatmap may be the "same" beatmap as the one being edited, *but* the `BeatmapInfo` references may differ
|
||||||
|
// due to the beatmap refetch logic ran on editor suspend.
|
||||||
|
// this test cares about checking the background belonging to the editor specifically, so check that using reference equality
|
||||||
|
// (as `.Equals()` cannot discern between the two, as they technically share the same database GUID).
|
||||||
|
var background = this.ChildrenOfType<BackgroundScreenBeatmap>().Single(b => ReferenceEquals(b.Beatmap.BeatmapInfo, EditorBeatmap.BeatmapInfo));
|
||||||
return background.Colour == Color4.DarkGray && background.BlurAmount.Value == 0;
|
return background.Colour == Color4.DarkGray && background.BlurAmount.Value == 0;
|
||||||
});
|
});
|
||||||
AddAssert("no mods selected", () => SelectedMods.Value.Count == 0);
|
AddAssert("no mods selected", () => SelectedMods.Value.Count == 0);
|
||||||
@ -99,7 +103,11 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
AddUntilStep("current screen is editor", () => Stack.CurrentScreen is Editor);
|
AddUntilStep("current screen is editor", () => Stack.CurrentScreen is Editor);
|
||||||
AddUntilStep("background has correct params", () =>
|
AddUntilStep("background has correct params", () =>
|
||||||
{
|
{
|
||||||
var background = this.ChildrenOfType<BackgroundScreenBeatmap>().Single();
|
// the test gameplay player's beatmap may be the "same" beatmap as the one being edited, *but* the `BeatmapInfo` references may differ
|
||||||
|
// due to the beatmap refetch logic ran on editor suspend.
|
||||||
|
// this test cares about checking the background belonging to the editor specifically, so check that using reference equality
|
||||||
|
// (as `.Equals()` cannot discern between the two, as they technically share the same database GUID).
|
||||||
|
var background = this.ChildrenOfType<BackgroundScreenBeatmap>().Single(b => ReferenceEquals(b.Beatmap.BeatmapInfo, EditorBeatmap.BeatmapInfo));
|
||||||
return background.Colour == Color4.DarkGray && background.BlurAmount.Value == 0;
|
return background.Colour == Color4.DarkGray && background.BlurAmount.Value == 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -3,9 +3,9 @@
|
|||||||
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Allocation;
|
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Screens.Play.HUD;
|
using osu.Game.Screens.Play.HUD;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osuTK.Input;
|
using osuTK.Input;
|
||||||
@ -19,28 +19,35 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
|
|
||||||
protected override double TimePerAction => 100; // required for the early exit test, since hold-to-confirm delay is 200ms
|
protected override double TimePerAction => 100; // required for the early exit test, since hold-to-confirm delay is 200ms
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
private HoldForMenuButton holdForMenuButton;
|
||||||
private void load()
|
|
||||||
{
|
|
||||||
HoldForMenuButton holdForMenuButton;
|
|
||||||
|
|
||||||
Add(holdForMenuButton = new HoldForMenuButton
|
[SetUpSteps]
|
||||||
|
public void SetUpSteps()
|
||||||
{
|
{
|
||||||
Origin = Anchor.BottomRight,
|
AddStep("create button", () =>
|
||||||
Anchor = Anchor.BottomRight,
|
{
|
||||||
|
exitAction = false;
|
||||||
|
|
||||||
|
Child = holdForMenuButton = new HoldForMenuButton
|
||||||
|
{
|
||||||
|
Scale = new Vector2(2),
|
||||||
|
Origin = Anchor.CentreRight,
|
||||||
|
Anchor = Anchor.CentreRight,
|
||||||
Action = () => exitAction = true
|
Action = () => exitAction = true
|
||||||
|
};
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
var text = holdForMenuButton.Children.OfType<SpriteText>().First();
|
[Test]
|
||||||
|
public void TestMovementAndTrigger()
|
||||||
|
{
|
||||||
AddStep("Trigger text fade in", () => InputManager.MoveMouseTo(holdForMenuButton));
|
AddStep("Trigger text fade in", () => InputManager.MoveMouseTo(holdForMenuButton));
|
||||||
AddUntilStep("Text visible", () => text.IsPresent && !exitAction);
|
AddUntilStep("Text visible", () => getSpriteText().IsPresent && !exitAction);
|
||||||
AddStep("Trigger text fade out", () => InputManager.MoveMouseTo(Vector2.One));
|
AddStep("Trigger text fade out", () => InputManager.MoveMouseTo(Vector2.One));
|
||||||
AddUntilStep("Text is not visible", () => !text.IsPresent && !exitAction);
|
AddUntilStep("Text is not visible", () => !getSpriteText().IsPresent && !exitAction);
|
||||||
|
|
||||||
AddStep("Trigger exit action", () =>
|
AddStep("Trigger exit action", () =>
|
||||||
{
|
{
|
||||||
exitAction = false;
|
|
||||||
InputManager.MoveMouseTo(holdForMenuButton);
|
InputManager.MoveMouseTo(holdForMenuButton);
|
||||||
InputManager.PressButton(MouseButton.Left);
|
InputManager.PressButton(MouseButton.Left);
|
||||||
});
|
});
|
||||||
@ -50,6 +57,17 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
|
|
||||||
AddStep("Trigger exit action", () => InputManager.PressButton(MouseButton.Left));
|
AddStep("Trigger exit action", () => InputManager.PressButton(MouseButton.Left));
|
||||||
AddUntilStep($"{nameof(holdForMenuButton.Action)} was triggered", () => exitAction);
|
AddUntilStep($"{nameof(holdForMenuButton.Action)} was triggered", () => exitAction);
|
||||||
}
|
AddStep("Release", () => InputManager.ReleaseButton(MouseButton.Left));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestFadeOnNoInput()
|
||||||
|
{
|
||||||
|
AddStep("move mouse away", () => InputManager.MoveMouseTo(Vector2.One));
|
||||||
|
AddUntilStep("wait for text fade out", () => !getSpriteText().IsPresent);
|
||||||
|
AddUntilStep("wait for button fade out", () => holdForMenuButton.Alpha < 0.1f);
|
||||||
|
}
|
||||||
|
|
||||||
|
private SpriteText getSpriteText() => holdForMenuButton.Children.OfType<SpriteText>().First();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -110,7 +110,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
|
|
||||||
AddUntilStep("results displayed", () => Player.GetChildScreen() is ResultsScreen);
|
AddUntilStep("results displayed", () => Player.GetChildScreen() is ResultsScreen);
|
||||||
AddAssert("ensure passing submission", () => Player.SubmittedScore?.ScoreInfo.Passed == true);
|
AddAssert("ensure passing submission", () => Player.SubmittedScore?.ScoreInfo.Passed == true);
|
||||||
AddAssert("submitted score has correct ruleset ID", () => Player.SubmittedScore?.ScoreInfo.RulesetID == new TaikoRuleset().RulesetInfo.ID);
|
AddAssert("submitted score has correct ruleset ID", () => Player.SubmittedScore?.ScoreInfo.Ruleset.ShortName == new TaikoRuleset().RulesetInfo.ShortName);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@ -130,7 +130,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
|
|
||||||
AddUntilStep("results displayed", () => Player.GetChildScreen() is ResultsScreen);
|
AddUntilStep("results displayed", () => Player.GetChildScreen() is ResultsScreen);
|
||||||
AddAssert("ensure passing submission", () => Player.SubmittedScore?.ScoreInfo.Passed == true);
|
AddAssert("ensure passing submission", () => Player.SubmittedScore?.ScoreInfo.Passed == true);
|
||||||
AddAssert("submitted score has correct ruleset ID", () => Player.SubmittedScore?.ScoreInfo.RulesetID == new ManiaRuleset().RulesetInfo.ID);
|
AddAssert("submitted score has correct ruleset ID", () => Player.SubmittedScore?.ScoreInfo.Ruleset.ShortName == new ManiaRuleset().RulesetInfo.ShortName);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
@ -210,7 +210,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void CollectPendingInputs(List<IInput> inputs)
|
protected override void CollectReplayInputs(List<IInput> inputs)
|
||||||
{
|
{
|
||||||
inputs.Add(new MousePositionAbsoluteInput { Position = GamefieldToScreenSpace(CurrentFrame?.Position ?? Vector2.Zero) });
|
inputs.Add(new MousePositionAbsoluteInput { Position = GamefieldToScreenSpace(CurrentFrame?.Position ?? Vector2.Zero) });
|
||||||
inputs.Add(new ReplayState<TestAction> { PressedActions = CurrentFrame?.Actions ?? new List<TestAction>() });
|
inputs.Add(new ReplayState<TestAction> { PressedActions = CurrentFrame?.Actions ?? new List<TestAction>() });
|
||||||
|
@ -301,8 +301,6 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
public ISample GetSample(ISampleInfo sampleInfo) => throw new NotImplementedException();
|
public ISample GetSample(ISampleInfo sampleInfo) => throw new NotImplementedException();
|
||||||
|
|
||||||
public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) => throw new NotImplementedException();
|
public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) => throw new NotImplementedException();
|
||||||
|
|
||||||
public ISkin FindProvider(Func<ISkin, bool> lookupFunction) => throw new NotImplementedException();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class SecondarySource : ISkin
|
private class SecondarySource : ISkin
|
||||||
@ -314,8 +312,6 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
public ISample GetSample(ISampleInfo sampleInfo) => throw new NotImplementedException();
|
public ISample GetSample(ISampleInfo sampleInfo) => throw new NotImplementedException();
|
||||||
|
|
||||||
public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) => throw new NotImplementedException();
|
public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) => throw new NotImplementedException();
|
||||||
|
|
||||||
public ISkin FindProvider(Func<ISkin, bool> lookupFunction) => throw new NotImplementedException();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Cached(typeof(ISkinSource))]
|
[Cached(typeof(ISkinSource))]
|
||||||
|
@ -15,11 +15,14 @@ using osu.Game.Online.Spectator;
|
|||||||
using osu.Game.Rulesets.Osu;
|
using osu.Game.Rulesets.Osu;
|
||||||
using osu.Game.Rulesets.Osu.Replays;
|
using osu.Game.Rulesets.Osu.Replays;
|
||||||
using osu.Game.Rulesets.UI;
|
using osu.Game.Rulesets.UI;
|
||||||
|
using osu.Game.Scoring;
|
||||||
using osu.Game.Screens;
|
using osu.Game.Screens;
|
||||||
using osu.Game.Screens.Play;
|
using osu.Game.Screens.Play;
|
||||||
|
using osu.Game.Tests.Beatmaps;
|
||||||
using osu.Game.Tests.Beatmaps.IO;
|
using osu.Game.Tests.Beatmaps.IO;
|
||||||
using osu.Game.Tests.Visual.Multiplayer;
|
using osu.Game.Tests.Visual.Multiplayer;
|
||||||
using osu.Game.Tests.Visual.Spectator;
|
using osu.Game.Tests.Visual.Spectator;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual.Gameplay
|
namespace osu.Game.Tests.Visual.Gameplay
|
||||||
{
|
{
|
||||||
@ -62,7 +65,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
AddStep("import beatmap", () =>
|
AddStep("import beatmap", () =>
|
||||||
{
|
{
|
||||||
importedBeatmap = BeatmapImportHelper.LoadOszIntoOsu(game, virtualTrack: true).GetResultSafely();
|
importedBeatmap = BeatmapImportHelper.LoadOszIntoOsu(game, virtualTrack: true).GetResultSafely();
|
||||||
importedBeatmapId = importedBeatmap.Beatmaps.First(b => b.RulesetID == 0).OnlineID;
|
importedBeatmapId = importedBeatmap.Beatmaps.First(b => b.Ruleset.OnlineID == 0).OnlineID;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -200,6 +203,37 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
AddAssert("screen didn't change", () => Stack.CurrentScreen is SoloSpectator);
|
AddAssert("screen didn't change", () => Stack.CurrentScreen is SoloSpectator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestFinalFramesPurgedBeforeEndingPlay()
|
||||||
|
{
|
||||||
|
AddStep("begin playing", () => spectatorClient.BeginPlaying(new GameplayState(new TestBeatmap(new OsuRuleset().RulesetInfo), new OsuRuleset()), new Score()));
|
||||||
|
|
||||||
|
AddStep("send frames and finish play", () =>
|
||||||
|
{
|
||||||
|
spectatorClient.HandleFrame(new OsuReplayFrame(1000, Vector2.Zero));
|
||||||
|
spectatorClient.EndPlaying();
|
||||||
|
});
|
||||||
|
|
||||||
|
// We can't access API because we're an "online" test.
|
||||||
|
AddAssert("last received frame has time = 1000", () => spectatorClient.LastReceivedUserFrames.First().Value.Time == 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestFinalFrameInBundleHasHeader()
|
||||||
|
{
|
||||||
|
FrameDataBundle lastBundle = null;
|
||||||
|
|
||||||
|
AddStep("bind to client", () => spectatorClient.OnNewFrames += (_, bundle) => lastBundle = bundle);
|
||||||
|
|
||||||
|
start(-1234);
|
||||||
|
sendFrames();
|
||||||
|
finish();
|
||||||
|
|
||||||
|
AddUntilStep("bundle received", () => lastBundle != null);
|
||||||
|
AddAssert("first frame does not have header", () => lastBundle.Frames[0].Header == null);
|
||||||
|
AddAssert("last frame has header", () => lastBundle.Frames[^1].Header != null);
|
||||||
|
}
|
||||||
|
|
||||||
private OsuFramedReplayInputHandler replayHandler =>
|
private OsuFramedReplayInputHandler replayHandler =>
|
||||||
(OsuFramedReplayInputHandler)Stack.ChildrenOfType<OsuInputManager>().First().ReplayInputHandler;
|
(OsuFramedReplayInputHandler)Stack.ChildrenOfType<OsuInputManager>().First().ReplayInputHandler;
|
||||||
|
|
||||||
|
@ -184,7 +184,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
|
|
||||||
private void onNewFrames(int userId, FrameDataBundle frames)
|
private void onNewFrames(int userId, FrameDataBundle frames)
|
||||||
{
|
{
|
||||||
Logger.Log($"Received {frames.Frames.Count()} new frames ({string.Join(',', frames.Frames.Select(f => ((int)f.Time).ToString()))})");
|
Logger.Log($"Received {frames.Frames.Count} new frames ({string.Join(',', frames.Frames.Select(f => ((int)f.Time).ToString()))})");
|
||||||
|
|
||||||
foreach (var legacyFrame in frames.Frames)
|
foreach (var legacyFrame in frames.Frames)
|
||||||
{
|
{
|
||||||
@ -259,7 +259,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void CollectPendingInputs(List<IInput> inputs)
|
protected override void CollectReplayInputs(List<IInput> inputs)
|
||||||
{
|
{
|
||||||
inputs.Add(new MousePositionAbsoluteInput { Position = GamefieldToScreenSpace(CurrentFrame?.Position ?? Vector2.Zero) });
|
inputs.Add(new MousePositionAbsoluteInput { Position = GamefieldToScreenSpace(CurrentFrame?.Position ?? Vector2.Zero) });
|
||||||
inputs.Add(new ReplayState<TestAction> { PressedActions = CurrentFrame?.Actions ?? new List<TestAction>() });
|
inputs.Add(new ReplayState<TestAction> { PressedActions = CurrentFrame?.Actions ?? new List<TestAction>() });
|
||||||
|
@ -5,6 +5,8 @@ using NUnit.Framework;
|
|||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Framework.Threading;
|
||||||
|
using osu.Game.Overlays;
|
||||||
using osu.Game.Screens;
|
using osu.Game.Screens;
|
||||||
using osu.Game.Screens.Menu;
|
using osu.Game.Screens.Menu;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
@ -18,10 +20,17 @@ namespace osu.Game.Tests.Visual.Menus
|
|||||||
[Cached]
|
[Cached]
|
||||||
private OsuLogo logo;
|
private OsuLogo logo;
|
||||||
|
|
||||||
|
protected abstract bool IntroReliesOnTrack { get; }
|
||||||
|
|
||||||
protected OsuScreenStack IntroStack;
|
protected OsuScreenStack IntroStack;
|
||||||
|
|
||||||
private IntroScreen intro;
|
private IntroScreen intro;
|
||||||
|
|
||||||
|
[Cached]
|
||||||
|
private NotificationOverlay notifications;
|
||||||
|
|
||||||
|
private ScheduledDelegate trackResetDelegate;
|
||||||
|
|
||||||
protected IntroTestScene()
|
protected IntroTestScene()
|
||||||
{
|
{
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
@ -38,6 +47,11 @@ namespace osu.Game.Tests.Visual.Menus
|
|||||||
RelativePositionAxes = Axes.Both,
|
RelativePositionAxes = Axes.Both,
|
||||||
Depth = float.MinValue,
|
Depth = float.MinValue,
|
||||||
Position = new Vector2(0.5f),
|
Position = new Vector2(0.5f),
|
||||||
|
},
|
||||||
|
notifications = new NotificationOverlay
|
||||||
|
{
|
||||||
|
Anchor = Anchor.TopRight,
|
||||||
|
Origin = Anchor.TopRight,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -63,6 +77,41 @@ namespace osu.Game.Tests.Visual.Menus
|
|||||||
AddUntilStep("wait for menu", () => intro.DidLoadMenu);
|
AddUntilStep("wait for menu", () => intro.DidLoadMenu);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public virtual void TestPlayIntroWithFailingAudioDevice()
|
||||||
|
{
|
||||||
|
AddStep("hide notifications", () => notifications.Hide());
|
||||||
|
AddStep("restart sequence", () =>
|
||||||
|
{
|
||||||
|
logo.FinishTransforms();
|
||||||
|
logo.IsTracking = false;
|
||||||
|
|
||||||
|
IntroStack?.Expire();
|
||||||
|
|
||||||
|
Add(IntroStack = new OsuScreenStack
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
});
|
||||||
|
|
||||||
|
IntroStack.Push(intro = CreateScreen());
|
||||||
|
});
|
||||||
|
|
||||||
|
AddStep("trigger failure", () =>
|
||||||
|
{
|
||||||
|
trackResetDelegate = Scheduler.AddDelayed(() =>
|
||||||
|
{
|
||||||
|
intro.Beatmap.Value.Track.Seek(0);
|
||||||
|
}, 0, true);
|
||||||
|
});
|
||||||
|
|
||||||
|
AddUntilStep("wait for menu", () => intro.DidLoadMenu);
|
||||||
|
|
||||||
|
if (IntroReliesOnTrack)
|
||||||
|
AddUntilStep("wait for notification", () => notifications.UnreadCount.Value == 1);
|
||||||
|
|
||||||
|
AddStep("uninstall delegate", () => trackResetDelegate?.Cancel());
|
||||||
|
}
|
||||||
|
|
||||||
protected abstract IntroScreen CreateScreen();
|
protected abstract IntroScreen CreateScreen();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ namespace osu.Game.Tests.Visual.Menus
|
|||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class TestSceneIntroCircles : IntroTestScene
|
public class TestSceneIntroCircles : IntroTestScene
|
||||||
{
|
{
|
||||||
|
protected override bool IntroReliesOnTrack => false;
|
||||||
protected override IntroScreen CreateScreen() => new IntroCircles();
|
protected override IntroScreen CreateScreen() => new IntroCircles();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ namespace osu.Game.Tests.Visual.Menus
|
|||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class TestSceneIntroTriangles : IntroTestScene
|
public class TestSceneIntroTriangles : IntroTestScene
|
||||||
{
|
{
|
||||||
|
protected override bool IntroReliesOnTrack => true;
|
||||||
protected override IntroScreen CreateScreen() => new IntroTriangles();
|
protected override IntroScreen CreateScreen() => new IntroTriangles();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ namespace osu.Game.Tests.Visual.Menus
|
|||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class TestSceneIntroWelcome : IntroTestScene
|
public class TestSceneIntroWelcome : IntroTestScene
|
||||||
{
|
{
|
||||||
|
protected override bool IntroReliesOnTrack => false;
|
||||||
protected override IntroScreen CreateScreen() => new IntroWelcome();
|
protected override IntroScreen CreateScreen() => new IntroWelcome();
|
||||||
|
|
||||||
public override void TestPlayIntro()
|
public override void TestPlayIntro()
|
||||||
|
@ -60,8 +60,8 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
{
|
{
|
||||||
beatmaps.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely();
|
beatmaps.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely();
|
||||||
importedSet = beatmaps.GetAllUsableBeatmapSets().First();
|
importedSet = beatmaps.GetAllUsableBeatmapSets().First();
|
||||||
InitialBeatmap = importedSet.Beatmaps.First(b => b.RulesetID == 0);
|
InitialBeatmap = importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0);
|
||||||
OtherBeatmap = importedSet.Beatmaps.Last(b => b.RulesetID == 0);
|
OtherBeatmap = importedSet.Beatmaps.Last(b => b.Ruleset.OnlineID == 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
AddStep("load multiplayer", () => LoadScreen(multiplayerComponents = new TestMultiplayerComponents()));
|
AddStep("load multiplayer", () => LoadScreen(multiplayerComponents = new TestMultiplayerComponents()));
|
||||||
|
@ -48,7 +48,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
private void load()
|
private void load()
|
||||||
{
|
{
|
||||||
importedSet = BeatmapImportHelper.LoadOszIntoOsu(game, virtualTrack: true).GetResultSafely();
|
importedSet = BeatmapImportHelper.LoadOszIntoOsu(game, virtualTrack: true).GetResultSafely();
|
||||||
importedBeatmap = importedSet.Beatmaps.First(b => b.RulesetID == 0);
|
importedBeatmap = importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0);
|
||||||
importedBeatmapId = importedBeatmap.OnlineID;
|
importedBeatmapId = importedBeatmap.OnlineID;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -347,19 +347,44 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
AddAssert($"{PLAYER_1_ID} score quit still set", () => getLeaderboardScore(PLAYER_1_ID).HasQuit.Value);
|
AddAssert($"{PLAYER_1_ID} score quit still set", () => getLeaderboardScore(PLAYER_1_ID).HasQuit.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadSpectateScreen(bool waitForPlayerLoad = true)
|
/// <summary>
|
||||||
|
/// Tests spectating with a gameplay start time set to a negative value.
|
||||||
|
/// Simulating beatmaps with high <see cref="BeatmapInfo.AudioLeadIn"/> or negative time storyboard elements.
|
||||||
|
/// </summary>
|
||||||
|
[Test]
|
||||||
|
public void TestNegativeGameplayStartTime()
|
||||||
{
|
{
|
||||||
AddStep("load screen", () =>
|
start(PLAYER_1_ID);
|
||||||
|
|
||||||
|
loadSpectateScreen(false, -500);
|
||||||
|
|
||||||
|
// to ensure negative gameplay start time does not affect spectator, send frames exactly after StartGameplay().
|
||||||
|
// (similar to real spectating sessions in which the first frames get sent between StartGameplay() and player load complete)
|
||||||
|
AddStep("send frames at gameplay start", () => getInstance(PLAYER_1_ID).OnGameplayStarted += () => SpectatorClient.SendFrames(PLAYER_1_ID, 100));
|
||||||
|
|
||||||
|
AddUntilStep("wait for player load", () => spectatorScreen.AllPlayersLoaded);
|
||||||
|
|
||||||
|
AddWaitStep("wait for progression", 3);
|
||||||
|
|
||||||
|
assertNotCatchingUp(PLAYER_1_ID);
|
||||||
|
assertRunning(PLAYER_1_ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadSpectateScreen(bool waitForPlayerLoad = true, double? gameplayStartTime = null)
|
||||||
|
{
|
||||||
|
AddStep(!gameplayStartTime.HasValue ? "load screen" : $"load screen (start = {gameplayStartTime}ms)", () =>
|
||||||
{
|
{
|
||||||
Beatmap.Value = beatmapManager.GetWorkingBeatmap(importedBeatmap);
|
Beatmap.Value = beatmapManager.GetWorkingBeatmap(importedBeatmap);
|
||||||
Ruleset.Value = importedBeatmap.Ruleset;
|
Ruleset.Value = importedBeatmap.Ruleset;
|
||||||
|
|
||||||
LoadScreen(spectatorScreen = new MultiSpectatorScreen(playingUsers.ToArray()));
|
LoadScreen(spectatorScreen = new TestMultiSpectatorScreen(playingUsers.ToArray(), gameplayStartTime));
|
||||||
});
|
});
|
||||||
|
|
||||||
AddUntilStep("wait for screen load", () => spectatorScreen.LoadState == LoadState.Loaded && (!waitForPlayerLoad || spectatorScreen.AllPlayersLoaded));
|
AddUntilStep("wait for screen load", () => spectatorScreen.LoadState == LoadState.Loaded && (!waitForPlayerLoad || spectatorScreen.AllPlayersLoaded));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void start(int userId, int? beatmapId = null) => start(new[] { userId }, beatmapId);
|
||||||
|
|
||||||
private void start(int[] userIds, int? beatmapId = null)
|
private void start(int[] userIds, int? beatmapId = null)
|
||||||
{
|
{
|
||||||
AddStep("start play", () =>
|
AddStep("start play", () =>
|
||||||
@ -419,6 +444,12 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
private void assertMuted(int userId, bool muted)
|
private void assertMuted(int userId, bool muted)
|
||||||
=> AddAssert($"{userId} {(muted ? "is" : "is not")} muted", () => getInstance(userId).Mute == muted);
|
=> AddAssert($"{userId} {(muted ? "is" : "is not")} muted", () => getInstance(userId).Mute == muted);
|
||||||
|
|
||||||
|
private void assertRunning(int userId)
|
||||||
|
=> AddAssert($"{userId} clock running", () => getInstance(userId).GameplayClock.IsRunning);
|
||||||
|
|
||||||
|
private void assertNotCatchingUp(int userId)
|
||||||
|
=> AddAssert($"{userId} in sync", () => !getInstance(userId).GameplayClock.IsCatchingUp);
|
||||||
|
|
||||||
private void waitForCatchup(int userId)
|
private void waitForCatchup(int userId)
|
||||||
=> AddUntilStep($"{userId} not catching up", () => !getInstance(userId).GameplayClock.IsCatchingUp);
|
=> AddUntilStep($"{userId} not catching up", () => !getInstance(userId).GameplayClock.IsCatchingUp);
|
||||||
|
|
||||||
@ -429,5 +460,19 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
private GameplayLeaderboardScore getLeaderboardScore(int userId) => spectatorScreen.ChildrenOfType<GameplayLeaderboardScore>().Single(s => s.User?.Id == userId);
|
private GameplayLeaderboardScore getLeaderboardScore(int userId) => spectatorScreen.ChildrenOfType<GameplayLeaderboardScore>().Single(s => s.User?.Id == userId);
|
||||||
|
|
||||||
private int[] getPlayerIds(int count) => Enumerable.Range(PLAYER_1_ID, count).ToArray();
|
private int[] getPlayerIds(int count) => Enumerable.Range(PLAYER_1_ID, count).ToArray();
|
||||||
|
|
||||||
|
private class TestMultiSpectatorScreen : MultiSpectatorScreen
|
||||||
|
{
|
||||||
|
private readonly double? gameplayStartTime;
|
||||||
|
|
||||||
|
public TestMultiSpectatorScreen(MultiplayerRoomUser[] users, double? gameplayStartTime = null)
|
||||||
|
: base(users)
|
||||||
|
{
|
||||||
|
this.gameplayStartTime = gameplayStartTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override MasterGameplayClockContainer CreateMasterGameplayClockContainer(WorkingBeatmap beatmap)
|
||||||
|
=> new MasterGameplayClockContainer(beatmap, gameplayStartTime ?? 0, gameplayStartTime.HasValue);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -98,7 +98,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
{
|
{
|
||||||
new PlaylistItem
|
new PlaylistItem
|
||||||
{
|
{
|
||||||
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.RulesetID == 0)).BeatmapInfo },
|
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo },
|
||||||
Ruleset = { Value = new OsuRuleset().RulesetInfo },
|
Ruleset = { Value = new OsuRuleset().RulesetInfo },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -234,7 +234,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
{
|
{
|
||||||
new PlaylistItem
|
new PlaylistItem
|
||||||
{
|
{
|
||||||
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.RulesetID == 0)).BeatmapInfo },
|
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo },
|
||||||
Ruleset = { Value = new OsuRuleset().RulesetInfo },
|
Ruleset = { Value = new OsuRuleset().RulesetInfo },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -256,7 +256,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
{
|
{
|
||||||
new PlaylistItem
|
new PlaylistItem
|
||||||
{
|
{
|
||||||
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.RulesetID == 0)).BeatmapInfo },
|
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo },
|
||||||
Ruleset = { Value = new OsuRuleset().RulesetInfo },
|
Ruleset = { Value = new OsuRuleset().RulesetInfo },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -286,7 +286,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
{
|
{
|
||||||
new PlaylistItem
|
new PlaylistItem
|
||||||
{
|
{
|
||||||
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.RulesetID == 0)).BeatmapInfo },
|
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo },
|
||||||
Ruleset = { Value = new OsuRuleset().RulesetInfo },
|
Ruleset = { Value = new OsuRuleset().RulesetInfo },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -317,7 +317,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
{
|
{
|
||||||
new PlaylistItem
|
new PlaylistItem
|
||||||
{
|
{
|
||||||
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.RulesetID == 0)).BeatmapInfo },
|
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo },
|
||||||
Ruleset = { Value = new OsuRuleset().RulesetInfo },
|
Ruleset = { Value = new OsuRuleset().RulesetInfo },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -339,7 +339,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
{
|
{
|
||||||
new PlaylistItem
|
new PlaylistItem
|
||||||
{
|
{
|
||||||
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.RulesetID == 0)).BeatmapInfo },
|
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo },
|
||||||
Ruleset = { Value = new OsuRuleset().RulesetInfo },
|
Ruleset = { Value = new OsuRuleset().RulesetInfo },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -372,7 +372,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
{
|
{
|
||||||
new PlaylistItem
|
new PlaylistItem
|
||||||
{
|
{
|
||||||
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.RulesetID == 0)).BeatmapInfo },
|
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo },
|
||||||
Ruleset = { Value = new OsuRuleset().RulesetInfo },
|
Ruleset = { Value = new OsuRuleset().RulesetInfo },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -392,7 +392,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
{
|
{
|
||||||
new PlaylistItem
|
new PlaylistItem
|
||||||
{
|
{
|
||||||
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.RulesetID == 0)).BeatmapInfo },
|
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo },
|
||||||
Ruleset = { Value = new OsuRuleset().RulesetInfo },
|
Ruleset = { Value = new OsuRuleset().RulesetInfo },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -414,7 +414,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
{
|
{
|
||||||
new PlaylistItem
|
new PlaylistItem
|
||||||
{
|
{
|
||||||
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.RulesetID == 0)).BeatmapInfo },
|
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo },
|
||||||
Ruleset = { Value = new OsuRuleset().RulesetInfo },
|
Ruleset = { Value = new OsuRuleset().RulesetInfo },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -453,7 +453,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
{
|
{
|
||||||
new PlaylistItem
|
new PlaylistItem
|
||||||
{
|
{
|
||||||
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.RulesetID == 0)).BeatmapInfo },
|
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo },
|
||||||
Ruleset = { Value = new OsuRuleset().RulesetInfo },
|
Ruleset = { Value = new OsuRuleset().RulesetInfo },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -492,7 +492,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
{
|
{
|
||||||
new PlaylistItem
|
new PlaylistItem
|
||||||
{
|
{
|
||||||
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.RulesetID == 0)).BeatmapInfo },
|
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo },
|
||||||
Ruleset = { Value = new OsuRuleset().RulesetInfo },
|
Ruleset = { Value = new OsuRuleset().RulesetInfo },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -531,7 +531,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
{
|
{
|
||||||
new PlaylistItem
|
new PlaylistItem
|
||||||
{
|
{
|
||||||
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.RulesetID == 0)).BeatmapInfo },
|
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo },
|
||||||
Ruleset = { Value = new OsuRuleset().RulesetInfo },
|
Ruleset = { Value = new OsuRuleset().RulesetInfo },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -565,7 +565,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
{
|
{
|
||||||
new PlaylistItem
|
new PlaylistItem
|
||||||
{
|
{
|
||||||
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.RulesetID == 0)).BeatmapInfo },
|
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo },
|
||||||
Ruleset = { Value = new OsuRuleset().RulesetInfo },
|
Ruleset = { Value = new OsuRuleset().RulesetInfo },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -605,7 +605,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
{
|
{
|
||||||
new PlaylistItem
|
new PlaylistItem
|
||||||
{
|
{
|
||||||
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.RulesetID == 0)).BeatmapInfo },
|
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo },
|
||||||
Ruleset = { Value = new OsuRuleset().RulesetInfo },
|
Ruleset = { Value = new OsuRuleset().RulesetInfo },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -625,7 +625,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
{
|
{
|
||||||
new PlaylistItem
|
new PlaylistItem
|
||||||
{
|
{
|
||||||
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.RulesetID == 0)).BeatmapInfo },
|
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo },
|
||||||
Ruleset = { Value = new OsuRuleset().RulesetInfo },
|
Ruleset = { Value = new OsuRuleset().RulesetInfo },
|
||||||
AllowedMods = { new OsuModHidden() }
|
AllowedMods = { new OsuModHidden() }
|
||||||
}
|
}
|
||||||
@ -665,7 +665,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
{
|
{
|
||||||
new PlaylistItem
|
new PlaylistItem
|
||||||
{
|
{
|
||||||
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.RulesetID == 0)).BeatmapInfo },
|
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo },
|
||||||
Ruleset = { Value = new OsuRuleset().RulesetInfo },
|
Ruleset = { Value = new OsuRuleset().RulesetInfo },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -696,7 +696,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
{
|
{
|
||||||
new PlaylistItem
|
new PlaylistItem
|
||||||
{
|
{
|
||||||
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.RulesetID == 0)).BeatmapInfo },
|
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo },
|
||||||
Ruleset = { Value = new OsuRuleset().RulesetInfo },
|
Ruleset = { Value = new OsuRuleset().RulesetInfo },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -714,7 +714,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
roomManager.ServerSideRooms[0].Playlist.Add(new PlaylistItem
|
roomManager.ServerSideRooms[0].Playlist.Add(new PlaylistItem
|
||||||
{
|
{
|
||||||
ID = 2,
|
ID = 2,
|
||||||
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.RulesetID == 0)).BeatmapInfo },
|
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo },
|
||||||
Ruleset = { Value = new OsuRuleset().RulesetInfo },
|
Ruleset = { Value = new OsuRuleset().RulesetInfo },
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -742,7 +742,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
{
|
{
|
||||||
new PlaylistItem
|
new PlaylistItem
|
||||||
{
|
{
|
||||||
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.RulesetID == 0)).BeatmapInfo },
|
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo },
|
||||||
Ruleset = { Value = new OsuRuleset().RulesetInfo },
|
Ruleset = { Value = new OsuRuleset().RulesetInfo },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -778,7 +778,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
{
|
{
|
||||||
new PlaylistItem
|
new PlaylistItem
|
||||||
{
|
{
|
||||||
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.RulesetID == 0)).BeatmapInfo },
|
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo },
|
||||||
Ruleset = { Value = new OsuRuleset().RulesetInfo },
|
Ruleset = { Value = new OsuRuleset().RulesetInfo },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -817,7 +817,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
{
|
{
|
||||||
new PlaylistItem
|
new PlaylistItem
|
||||||
{
|
{
|
||||||
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.RulesetID == 0)).BeatmapInfo },
|
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo },
|
||||||
Ruleset = { Value = new OsuRuleset().RulesetInfo },
|
Ruleset = { Value = new OsuRuleset().RulesetInfo },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -828,7 +828,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
AddStep("join other user", () => client.AddUser(new APIUser { Id = 1234 }));
|
AddStep("join other user", () => client.AddUser(new APIUser { Id = 1234 }));
|
||||||
AddStep("add item as other user", () => client.AddUserPlaylistItem(1234, new MultiplayerPlaylistItem(new PlaylistItem
|
AddStep("add item as other user", () => client.AddUserPlaylistItem(1234, new MultiplayerPlaylistItem(new PlaylistItem
|
||||||
{
|
{
|
||||||
BeatmapID = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.RulesetID == 0)).BeatmapInfo.OnlineID
|
BeatmapID = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo.OnlineID
|
||||||
})));
|
})));
|
||||||
|
|
||||||
AddUntilStep("item arrived in playlist", () => client.Room?.Playlist.Count == 2);
|
AddUntilStep("item arrived in playlist", () => client.Room?.Playlist.Count == 2);
|
||||||
@ -848,7 +848,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
{
|
{
|
||||||
new PlaylistItem
|
new PlaylistItem
|
||||||
{
|
{
|
||||||
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.RulesetID == 0)).BeatmapInfo },
|
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo },
|
||||||
Ruleset = { Value = new OsuRuleset().RulesetInfo },
|
Ruleset = { Value = new OsuRuleset().RulesetInfo },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -859,7 +859,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
AddStep("join other user", () => client.AddUser(new APIUser { Id = 1234 }));
|
AddStep("join other user", () => client.AddUser(new APIUser { Id = 1234 }));
|
||||||
AddStep("add item as other user", () => client.AddUserPlaylistItem(1234, new MultiplayerPlaylistItem(new PlaylistItem
|
AddStep("add item as other user", () => client.AddUserPlaylistItem(1234, new MultiplayerPlaylistItem(new PlaylistItem
|
||||||
{
|
{
|
||||||
BeatmapID = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.RulesetID == 0)).BeatmapInfo.OnlineID
|
BeatmapID = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo.OnlineID
|
||||||
})));
|
})));
|
||||||
|
|
||||||
AddUntilStep("item arrived in playlist", () => client.Room?.Playlist.Count == 2);
|
AddUntilStep("item arrived in playlist", () => client.Room?.Playlist.Count == 2);
|
||||||
|
@ -107,7 +107,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
BeatmapInfo selectedBeatmap = null;
|
BeatmapInfo selectedBeatmap = null;
|
||||||
|
|
||||||
AddStep("select beatmap",
|
AddStep("select beatmap",
|
||||||
() => songSelect.Carousel.SelectBeatmap(selectedBeatmap = beatmaps.Where(beatmap => beatmap.RulesetID == new OsuRuleset().LegacyID).ElementAt(1)));
|
() => songSelect.Carousel.SelectBeatmap(selectedBeatmap = beatmaps.Where(beatmap => beatmap.Ruleset.OnlineID == new OsuRuleset().LegacyID).ElementAt(1)));
|
||||||
AddUntilStep("wait for selection", () => Beatmap.Value.BeatmapInfo.Equals(selectedBeatmap));
|
AddUntilStep("wait for selection", () => Beatmap.Value.BeatmapInfo.Equals(selectedBeatmap));
|
||||||
|
|
||||||
AddStep("exit song select", () => songSelect.Exit());
|
AddStep("exit song select", () => songSelect.Exit());
|
||||||
@ -139,7 +139,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
|
|
||||||
AddStep("change ruleset", () => Ruleset.Value = new TaikoRuleset().RulesetInfo);
|
AddStep("change ruleset", () => Ruleset.Value = new TaikoRuleset().RulesetInfo);
|
||||||
AddStep("select beatmap",
|
AddStep("select beatmap",
|
||||||
() => songSelect.Carousel.SelectBeatmap(selectedBeatmap = beatmaps.First(beatmap => beatmap.RulesetID == new TaikoRuleset().LegacyID)));
|
() => songSelect.Carousel.SelectBeatmap(selectedBeatmap = beatmaps.First(beatmap => beatmap.Ruleset.OnlineID == new TaikoRuleset().LegacyID)));
|
||||||
AddUntilStep("wait for selection", () => Beatmap.Value.BeatmapInfo.Equals(selectedBeatmap));
|
AddUntilStep("wait for selection", () => Beatmap.Value.BeatmapInfo.Equals(selectedBeatmap));
|
||||||
AddStep("set mods", () => SelectedMods.Value = new[] { new TaikoModDoubleTime() });
|
AddStep("set mods", () => SelectedMods.Value = new[] { new TaikoModDoubleTime() });
|
||||||
|
|
||||||
|
@ -15,8 +15,12 @@ using osu.Game.Online.Multiplayer;
|
|||||||
using osu.Game.Online.Rooms;
|
using osu.Game.Online.Rooms;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Rulesets.Osu;
|
using osu.Game.Rulesets.Osu;
|
||||||
|
using osu.Game.Rulesets.Taiko;
|
||||||
|
using osu.Game.Rulesets.Taiko.Mods;
|
||||||
|
using osu.Game.Rulesets.UI;
|
||||||
using osu.Game.Screens.OnlinePlay.Multiplayer;
|
using osu.Game.Screens.OnlinePlay.Multiplayer;
|
||||||
using osu.Game.Screens.OnlinePlay.Multiplayer.Match;
|
using osu.Game.Screens.OnlinePlay.Multiplayer.Match;
|
||||||
|
using osu.Game.Screens.OnlinePlay.Multiplayer.Participants;
|
||||||
using osu.Game.Tests.Beatmaps;
|
using osu.Game.Tests.Beatmaps;
|
||||||
using osu.Game.Tests.Resources;
|
using osu.Game.Tests.Resources;
|
||||||
|
|
||||||
@ -77,6 +81,27 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
AddUntilStep("wait for join", () => RoomJoined);
|
AddUntilStep("wait for join", () => RoomJoined);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestTaikoOnlyMod()
|
||||||
|
{
|
||||||
|
AddStep("add playlist item", () =>
|
||||||
|
{
|
||||||
|
SelectedRoom.Value.Playlist.Add(new PlaylistItem
|
||||||
|
{
|
||||||
|
Beatmap = { Value = new TestBeatmap(new TaikoRuleset().RulesetInfo).BeatmapInfo },
|
||||||
|
Ruleset = { Value = new TaikoRuleset().RulesetInfo },
|
||||||
|
AllowedMods = { new TaikoModSwap() }
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
ClickButtonWhenEnabled<MultiplayerMatchSettingsOverlay.CreateOrUpdateButton>();
|
||||||
|
|
||||||
|
AddUntilStep("wait for join", () => RoomJoined);
|
||||||
|
|
||||||
|
AddStep("select swap mod", () => Client.ChangeUserMods(API.LocalUser.Value.OnlineID, new[] { new TaikoModSwap() }));
|
||||||
|
AddUntilStep("participant panel has mod", () => this.ChildrenOfType<ParticipantPanel>().Any(p => p.ChildrenOfType<ModIcon>().Any(m => m.Mod is TaikoModSwap)));
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestSettingValidity()
|
public void TestSettingValidity()
|
||||||
{
|
{
|
||||||
|
@ -57,7 +57,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
{
|
{
|
||||||
beatmaps.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely();
|
beatmaps.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely();
|
||||||
importedSet = beatmaps.GetAllUsableBeatmapSets().First();
|
importedSet = beatmaps.GetAllUsableBeatmapSets().First();
|
||||||
importedBeatmap = importedSet.Beatmaps.First(b => b.RulesetID == 0);
|
importedBeatmap = importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
AddStep("change to all players mode", () => Client.ChangeSettings(new MultiplayerRoomSettings { QueueMode = QueueMode.AllPlayers }));
|
AddStep("change to all players mode", () => Client.ChangeSettings(new MultiplayerRoomSettings { QueueMode = QueueMode.AllPlayers }));
|
||||||
|
@ -62,7 +62,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
{
|
{
|
||||||
beatmaps.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely();
|
beatmaps.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely();
|
||||||
importedSet = beatmaps.GetAllUsableBeatmapSets().First();
|
importedSet = beatmaps.GetAllUsableBeatmapSets().First();
|
||||||
importedBeatmap = importedSet.Beatmaps.First(b => b.RulesetID == 0);
|
importedBeatmap = importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
AddStep("change to all players mode", () => Client.ChangeSettings(new MultiplayerRoomSettings { QueueMode = QueueMode.AllPlayers }));
|
AddStep("change to all players mode", () => Client.ChangeSettings(new MultiplayerRoomSettings { QueueMode = QueueMode.AllPlayers }));
|
||||||
|
@ -73,7 +73,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
{
|
{
|
||||||
new PlaylistItem
|
new PlaylistItem
|
||||||
{
|
{
|
||||||
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.RulesetID == 0)).BeatmapInfo },
|
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo },
|
||||||
Ruleset = { Value = new OsuRuleset().RulesetInfo },
|
Ruleset = { Value = new OsuRuleset().RulesetInfo },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -94,7 +94,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
{
|
{
|
||||||
new PlaylistItem
|
new PlaylistItem
|
||||||
{
|
{
|
||||||
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.RulesetID == 0)).BeatmapInfo },
|
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo },
|
||||||
Ruleset = { Value = new OsuRuleset().RulesetInfo },
|
Ruleset = { Value = new OsuRuleset().RulesetInfo },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -132,7 +132,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
{
|
{
|
||||||
new PlaylistItem
|
new PlaylistItem
|
||||||
{
|
{
|
||||||
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.RulesetID == 0)).BeatmapInfo },
|
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo },
|
||||||
Ruleset = { Value = new OsuRuleset().RulesetInfo },
|
Ruleset = { Value = new OsuRuleset().RulesetInfo },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -158,7 +158,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
{
|
{
|
||||||
new PlaylistItem
|
new PlaylistItem
|
||||||
{
|
{
|
||||||
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.RulesetID == 0)).BeatmapInfo },
|
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo },
|
||||||
Ruleset = { Value = new OsuRuleset().RulesetInfo },
|
Ruleset = { Value = new OsuRuleset().RulesetInfo },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@ using osu.Game.Screens;
|
|||||||
using osu.Game.Screens.Menu;
|
using osu.Game.Screens.Menu;
|
||||||
using osu.Game.Screens.Play;
|
using osu.Game.Screens.Play;
|
||||||
using osu.Game.Screens.Ranking;
|
using osu.Game.Screens.Ranking;
|
||||||
|
using osu.Game.Screens.Select;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual.Navigation
|
namespace osu.Game.Tests.Visual.Navigation
|
||||||
{
|
{
|
||||||
@ -92,6 +93,9 @@ namespace osu.Game.Tests.Visual.Navigation
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestFromSongSelect([Values] ScorePresentType type)
|
public void TestFromSongSelect([Values] ScorePresentType type)
|
||||||
{
|
{
|
||||||
|
AddStep("enter song select", () => Game.ChildrenOfType<ButtonSystem>().Single().OnSolo.Invoke());
|
||||||
|
AddUntilStep("song select is current", () => Game.ScreenStack.CurrentScreen is PlaySongSelect songSelect && songSelect.BeatmapSetsLoaded);
|
||||||
|
|
||||||
var firstImport = importScore(1);
|
var firstImport = importScore(1);
|
||||||
presentAndConfirm(firstImport, type);
|
presentAndConfirm(firstImport, type);
|
||||||
|
|
||||||
@ -102,6 +106,9 @@ namespace osu.Game.Tests.Visual.Navigation
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestFromSongSelectDifferentRuleset([Values] ScorePresentType type)
|
public void TestFromSongSelectDifferentRuleset([Values] ScorePresentType type)
|
||||||
{
|
{
|
||||||
|
AddStep("enter song select", () => Game.ChildrenOfType<ButtonSystem>().Single().OnSolo.Invoke());
|
||||||
|
AddUntilStep("song select is current", () => Game.ScreenStack.CurrentScreen is PlaySongSelect songSelect && songSelect.BeatmapSetsLoaded);
|
||||||
|
|
||||||
var firstImport = importScore(1);
|
var firstImport = importScore(1);
|
||||||
presentAndConfirm(firstImport, type);
|
presentAndConfirm(firstImport, type);
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
// 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.
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
@ -10,16 +11,19 @@ using osu.Framework.Screens;
|
|||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
|
using osu.Game.Online.Leaderboards;
|
||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
using osu.Game.Overlays.Mods;
|
using osu.Game.Overlays.Mods;
|
||||||
using osu.Game.Overlays.Toolbar;
|
using osu.Game.Overlays.Toolbar;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.Osu.Mods;
|
using osu.Game.Rulesets.Osu.Mods;
|
||||||
|
using osu.Game.Scoring;
|
||||||
using osu.Game.Screens.Menu;
|
using osu.Game.Screens.Menu;
|
||||||
using osu.Game.Screens.OnlinePlay.Lounge;
|
using osu.Game.Screens.OnlinePlay.Lounge;
|
||||||
using osu.Game.Screens.Play;
|
using osu.Game.Screens.Play;
|
||||||
using osu.Game.Screens.Ranking;
|
using osu.Game.Screens.Ranking;
|
||||||
using osu.Game.Screens.Select;
|
using osu.Game.Screens.Select;
|
||||||
|
using osu.Game.Screens.Select.Leaderboards;
|
||||||
using osu.Game.Screens.Select.Options;
|
using osu.Game.Screens.Select.Options;
|
||||||
using osu.Game.Tests.Beatmaps.IO;
|
using osu.Game.Tests.Beatmaps.IO;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
@ -96,35 +100,87 @@ namespace osu.Game.Tests.Visual.Navigation
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestRetryFromResults()
|
public void TestRetryFromResults()
|
||||||
{
|
{
|
||||||
Player player = null;
|
var getOriginalPlayer = playToResults();
|
||||||
ResultsScreen results = null;
|
|
||||||
|
|
||||||
IWorkingBeatmap beatmap() => Game.Beatmap.Value;
|
AddStep("attempt to retry", () => ((ResultsScreen)Game.ScreenStack.CurrentScreen).ChildrenOfType<HotkeyRetryOverlay>().First().Action());
|
||||||
|
AddUntilStep("wait for player", () => Game.ScreenStack.CurrentScreen != getOriginalPlayer() && Game.ScreenStack.CurrentScreen is Player);
|
||||||
|
}
|
||||||
|
|
||||||
Screens.Select.SongSelect songSelect = null;
|
[Test]
|
||||||
PushAndConfirm(() => songSelect = new TestPlaySongSelect());
|
public void TestDeleteAllScoresAfterPlaying()
|
||||||
AddUntilStep("wait for song select", () => songSelect.BeatmapSetsLoaded);
|
|
||||||
|
|
||||||
AddStep("import beatmap", () => BeatmapImportHelper.LoadQuickOszIntoOsu(Game).WaitSafely());
|
|
||||||
|
|
||||||
AddUntilStep("wait for selected", () => !Game.Beatmap.IsDefault);
|
|
||||||
|
|
||||||
AddStep("set mods", () => Game.SelectedMods.Value = new Mod[] { new OsuModNoFail(), new OsuModDoubleTime { SpeedChange = { Value = 2 } } });
|
|
||||||
|
|
||||||
AddStep("press enter", () => InputManager.Key(Key.Enter));
|
|
||||||
|
|
||||||
AddUntilStep("wait for player", () =>
|
|
||||||
{
|
{
|
||||||
// dismiss any notifications that may appear (ie. muted notification).
|
playToResults();
|
||||||
clickMouseInCentre();
|
|
||||||
return (player = Game.ScreenStack.CurrentScreen as Player) != null;
|
ScoreInfo score = null;
|
||||||
|
LeaderboardScore scorePanel = null;
|
||||||
|
|
||||||
|
AddStep("get score", () => score = ((ResultsScreen)Game.ScreenStack.CurrentScreen).Score);
|
||||||
|
|
||||||
|
AddAssert("ensure score is databased", () => Game.Realm.Run(r => r.Find<ScoreInfo>(score.ID)?.DeletePending == false));
|
||||||
|
|
||||||
|
AddStep("press back button", () => Game.ChildrenOfType<BackButton>().First().Action());
|
||||||
|
|
||||||
|
AddStep("show local scores", () => Game.ChildrenOfType<BeatmapDetailAreaTabControl>().First().Current.Value = new BeatmapDetailAreaLeaderboardTabItem<BeatmapLeaderboardScope>(BeatmapLeaderboardScope.Local));
|
||||||
|
|
||||||
|
AddUntilStep("wait for score displayed", () => (scorePanel = Game.ChildrenOfType<LeaderboardScore>().FirstOrDefault(s => s.Score.Equals(score))) != null);
|
||||||
|
|
||||||
|
AddStep("open options", () => InputManager.Key(Key.F3));
|
||||||
|
|
||||||
|
AddStep("choose clear all scores", () => InputManager.Key(Key.Number4));
|
||||||
|
|
||||||
|
AddUntilStep("wait for dialog display", () => Game.Dependencies.Get<DialogOverlay>().IsLoaded);
|
||||||
|
AddUntilStep("wait for dialog", () => Game.Dependencies.Get<DialogOverlay>().CurrentDialog != null);
|
||||||
|
AddStep("confirm deletion", () => InputManager.Key(Key.Number1));
|
||||||
|
AddUntilStep("wait for dialog dismissed", () => Game.Dependencies.Get<DialogOverlay>().CurrentDialog == null);
|
||||||
|
|
||||||
|
AddAssert("ensure score is pending deletion", () => Game.Realm.Run(r => r.Find<ScoreInfo>(score.ID)?.DeletePending == true));
|
||||||
|
|
||||||
|
AddUntilStep("wait for score panel removal", () => scorePanel.Parent == null);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestDeleteScoreAfterPlaying()
|
||||||
|
{
|
||||||
|
playToResults();
|
||||||
|
|
||||||
|
ScoreInfo score = null;
|
||||||
|
LeaderboardScore scorePanel = null;
|
||||||
|
|
||||||
|
AddStep("get score", () => score = ((ResultsScreen)Game.ScreenStack.CurrentScreen).Score);
|
||||||
|
|
||||||
|
AddAssert("ensure score is databased", () => Game.Realm.Run(r => r.Find<ScoreInfo>(score.ID)?.DeletePending == false));
|
||||||
|
|
||||||
|
AddStep("press back button", () => Game.ChildrenOfType<BackButton>().First().Action());
|
||||||
|
|
||||||
|
AddStep("show local scores", () => Game.ChildrenOfType<BeatmapDetailAreaTabControl>().First().Current.Value = new BeatmapDetailAreaLeaderboardTabItem<BeatmapLeaderboardScope>(BeatmapLeaderboardScope.Local));
|
||||||
|
|
||||||
|
AddUntilStep("wait for score displayed", () => (scorePanel = Game.ChildrenOfType<LeaderboardScore>().FirstOrDefault(s => s.Score.Equals(score))) != null);
|
||||||
|
|
||||||
|
AddStep("right click panel", () =>
|
||||||
|
{
|
||||||
|
InputManager.MoveMouseTo(scorePanel);
|
||||||
|
InputManager.Click(MouseButton.Right);
|
||||||
});
|
});
|
||||||
|
|
||||||
AddUntilStep("wait for track playing", () => beatmap().Track.IsRunning);
|
AddStep("click delete", () =>
|
||||||
AddStep("seek to near end", () => player.ChildrenOfType<GameplayClockContainer>().First().Seek(beatmap().Beatmap.HitObjects[^1].StartTime - 1000));
|
{
|
||||||
AddUntilStep("wait for pass", () => (results = Game.ScreenStack.CurrentScreen as ResultsScreen) != null && results.IsLoaded);
|
var dropdownItem = Game
|
||||||
AddStep("attempt to retry", () => results.ChildrenOfType<HotkeyRetryOverlay>().First().Action());
|
.ChildrenOfType<PlayBeatmapDetailArea>().First()
|
||||||
AddUntilStep("wait for player", () => Game.ScreenStack.CurrentScreen != player && Game.ScreenStack.CurrentScreen is Player);
|
.ChildrenOfType<OsuContextMenu>().First()
|
||||||
|
.ChildrenOfType<DrawableOsuMenuItem>().First(i => i.Item.Text.ToString() == "Delete");
|
||||||
|
|
||||||
|
InputManager.MoveMouseTo(dropdownItem);
|
||||||
|
InputManager.Click(MouseButton.Left);
|
||||||
|
});
|
||||||
|
|
||||||
|
AddUntilStep("wait for dialog display", () => Game.Dependencies.Get<DialogOverlay>().IsLoaded);
|
||||||
|
AddUntilStep("wait for dialog", () => Game.Dependencies.Get<DialogOverlay>().CurrentDialog != null);
|
||||||
|
AddStep("confirm deletion", () => InputManager.Key(Key.Number1));
|
||||||
|
AddUntilStep("wait for dialog dismissed", () => Game.Dependencies.Get<DialogOverlay>().CurrentDialog == null);
|
||||||
|
|
||||||
|
AddAssert("ensure score is pending deletion", () => Game.Realm.Run(r => r.Find<ScoreInfo>(score.ID)?.DeletePending == true));
|
||||||
|
|
||||||
|
AddUntilStep("wait for score panel removal", () => scorePanel.Parent == null);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestCase(true)]
|
[TestCase(true)]
|
||||||
@ -432,6 +488,37 @@ namespace osu.Game.Tests.Visual.Navigation
|
|||||||
AddStep("test dispose doesn't crash", () => Game.Dispose());
|
AddStep("test dispose doesn't crash", () => Game.Dispose());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Func<Player> playToResults()
|
||||||
|
{
|
||||||
|
Player player = null;
|
||||||
|
|
||||||
|
IWorkingBeatmap beatmap() => Game.Beatmap.Value;
|
||||||
|
|
||||||
|
Screens.Select.SongSelect songSelect = null;
|
||||||
|
PushAndConfirm(() => songSelect = new TestPlaySongSelect());
|
||||||
|
AddUntilStep("wait for song select", () => songSelect.BeatmapSetsLoaded);
|
||||||
|
|
||||||
|
AddStep("import beatmap", () => BeatmapImportHelper.LoadQuickOszIntoOsu(Game).WaitSafely());
|
||||||
|
|
||||||
|
AddUntilStep("wait for selected", () => !Game.Beatmap.IsDefault);
|
||||||
|
|
||||||
|
AddStep("set mods", () => Game.SelectedMods.Value = new Mod[] { new OsuModNoFail(), new OsuModDoubleTime { SpeedChange = { Value = 2 } } });
|
||||||
|
|
||||||
|
AddStep("press enter", () => InputManager.Key(Key.Enter));
|
||||||
|
|
||||||
|
AddUntilStep("wait for player", () =>
|
||||||
|
{
|
||||||
|
// dismiss any notifications that may appear (ie. muted notification).
|
||||||
|
clickMouseInCentre();
|
||||||
|
return (player = Game.ScreenStack.CurrentScreen as Player) != null;
|
||||||
|
});
|
||||||
|
|
||||||
|
AddUntilStep("wait for track playing", () => beatmap().Track.IsRunning);
|
||||||
|
AddStep("seek to near end", () => player.ChildrenOfType<GameplayClockContainer>().First().Seek(beatmap().Beatmap.HitObjects[^1].StartTime - 1000));
|
||||||
|
AddUntilStep("wait for pass", () => (Game.ScreenStack.CurrentScreen as ResultsScreen)?.IsLoaded == true);
|
||||||
|
return () => player;
|
||||||
|
}
|
||||||
|
|
||||||
private void clickMouseInCentre()
|
private void clickMouseInCentre()
|
||||||
{
|
{
|
||||||
InputManager.MoveMouseTo(Game.ScreenSpaceDrawQuad.Centre);
|
InputManager.MoveMouseTo(Game.ScreenSpaceDrawQuad.Centre);
|
||||||
|
@ -9,6 +9,7 @@ using osu.Framework.Allocation;
|
|||||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Utils;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
@ -40,6 +41,36 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
this.rulesets = rulesets;
|
this.rulesets = rulesets;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestScrollPositionMaintainedOnAdd()
|
||||||
|
{
|
||||||
|
loadBeatmaps(count: 1, randomDifficulties: false);
|
||||||
|
|
||||||
|
for (int i = 0; i < 10; i++)
|
||||||
|
{
|
||||||
|
AddRepeatStep("Add some sets", () => carousel.UpdateBeatmapSet(TestResources.CreateTestBeatmapSetInfo()), 4);
|
||||||
|
|
||||||
|
checkSelectionIsCentered();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestScrollPositionMaintainedOnDelete()
|
||||||
|
{
|
||||||
|
loadBeatmaps(count: 50, randomDifficulties: false);
|
||||||
|
|
||||||
|
for (int i = 0; i < 10; i++)
|
||||||
|
{
|
||||||
|
AddRepeatStep("Remove some sets", () =>
|
||||||
|
carousel.RemoveBeatmapSet(carousel.Items.Select(item => item.Item)
|
||||||
|
.OfType<CarouselBeatmapSet>()
|
||||||
|
.OrderBy(item => item.GetHashCode())
|
||||||
|
.First(item => item.State.Value != CarouselItemState.Selected && item.Visible).BeatmapSet), 4);
|
||||||
|
|
||||||
|
checkSelectionIsCentered();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestManyPanels()
|
public void TestManyPanels()
|
||||||
{
|
{
|
||||||
@ -570,7 +601,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
{
|
{
|
||||||
BeatmapSetInfo testMixed = null;
|
BeatmapSetInfo testMixed = null;
|
||||||
|
|
||||||
createCarousel();
|
createCarousel(new List<BeatmapSetInfo>());
|
||||||
|
|
||||||
AddStep("add mixed ruleset beatmapset", () =>
|
AddStep("add mixed ruleset beatmapset", () =>
|
||||||
{
|
{
|
||||||
@ -586,7 +617,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
AddStep("filter to ruleset 0", () =>
|
AddStep("filter to ruleset 0", () =>
|
||||||
carousel.Filter(new FilterCriteria { Ruleset = rulesets.AvailableRulesets.ElementAt(0) }, false));
|
carousel.Filter(new FilterCriteria { Ruleset = rulesets.AvailableRulesets.ElementAt(0) }, false));
|
||||||
AddStep("select filtered map skipping filtered", () => carousel.SelectBeatmap(testMixed.Beatmaps[1], false));
|
AddStep("select filtered map skipping filtered", () => carousel.SelectBeatmap(testMixed.Beatmaps[1], false));
|
||||||
AddAssert("unfiltered beatmap not selected", () => carousel.SelectedBeatmapInfo.RulesetID == 0);
|
AddAssert("unfiltered beatmap not selected", () => carousel.SelectedBeatmapInfo.Ruleset.OnlineID == 0);
|
||||||
|
|
||||||
AddStep("remove mixed set", () =>
|
AddStep("remove mixed set", () =>
|
||||||
{
|
{
|
||||||
@ -734,10 +765,6 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
{
|
{
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
|
|
||||||
createCarousel(c =>
|
|
||||||
{
|
|
||||||
carouselAdjust?.Invoke(c);
|
|
||||||
|
|
||||||
if (beatmapSets == null)
|
if (beatmapSets == null)
|
||||||
{
|
{
|
||||||
beatmapSets = new List<BeatmapSetInfo>();
|
beatmapSets = new List<BeatmapSetInfo>();
|
||||||
@ -750,6 +777,10 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
createCarousel(beatmapSets, c =>
|
||||||
|
{
|
||||||
|
carouselAdjust?.Invoke(c);
|
||||||
|
|
||||||
carousel.Filter(initialCriteria?.Invoke() ?? new FilterCriteria());
|
carousel.Filter(initialCriteria?.Invoke() ?? new FilterCriteria());
|
||||||
carousel.BeatmapSetsChanged = () => changed = true;
|
carousel.BeatmapSetsChanged = () => changed = true;
|
||||||
carousel.BeatmapSets = beatmapSets;
|
carousel.BeatmapSets = beatmapSets;
|
||||||
@ -758,7 +789,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
AddUntilStep("Wait for load", () => changed);
|
AddUntilStep("Wait for load", () => changed);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createCarousel(Action<BeatmapCarousel> carouselAdjust = null, Container target = null)
|
private void createCarousel(List<BeatmapSetInfo> beatmapSets, Action<BeatmapCarousel> carouselAdjust = null, Container target = null)
|
||||||
{
|
{
|
||||||
AddStep("Create carousel", () =>
|
AddStep("Create carousel", () =>
|
||||||
{
|
{
|
||||||
@ -772,6 +803,8 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
|
|
||||||
carouselAdjust?.Invoke(carousel);
|
carouselAdjust?.Invoke(carousel);
|
||||||
|
|
||||||
|
carousel.BeatmapSets = beatmapSets;
|
||||||
|
|
||||||
(target ?? this).Child = carousel;
|
(target ?? this).Child = carousel;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -813,6 +846,18 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
carousel.Items.Count(s => (diff ? s.Item is CarouselBeatmap : s.Item is CarouselBeatmapSet) && s.Item.Visible) == count);
|
carousel.Items.Count(s => (diff ? s.Item is CarouselBeatmap : s.Item is CarouselBeatmapSet) && s.Item.Visible) == count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void checkSelectionIsCentered()
|
||||||
|
{
|
||||||
|
AddAssert("Selected panel is centered", () =>
|
||||||
|
{
|
||||||
|
return Precision.AlmostEquals(
|
||||||
|
carousel.ScreenSpaceDrawQuad.Centre,
|
||||||
|
carousel.Items
|
||||||
|
.First(i => i.Item.State.Value == CarouselItemState.Selected)
|
||||||
|
.ScreenSpaceDrawQuad.Centre, 100);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private void checkNoSelection() => AddAssert("Selection is null", () => currentSelection == null);
|
private void checkNoSelection() => AddAssert("Selection is null", () => currentSelection == null);
|
||||||
|
|
||||||
private void nextRandom() =>
|
private void nextRandom() =>
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
// 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 System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
@ -100,7 +101,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
public void TestGlobalScoresDisplay()
|
public void TestGlobalScoresDisplay()
|
||||||
{
|
{
|
||||||
AddStep(@"Set scope", () => leaderboard.Scope = BeatmapLeaderboardScope.Global);
|
AddStep(@"Set scope", () => leaderboard.Scope = BeatmapLeaderboardScope.Global);
|
||||||
AddStep(@"New Scores", () => leaderboard.Scores = generateSampleScores(null));
|
AddStep(@"New Scores", () => leaderboard.SetScores(generateSampleScores(new BeatmapInfo())));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@ -113,24 +114,18 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestPlaceholderStates()
|
public void TestPlaceholderStates()
|
||||||
{
|
{
|
||||||
AddStep(@"Empty Scores", () => leaderboard.SetRetrievalState(PlaceholderState.NoScores));
|
AddStep("ensure no scores displayed", () => leaderboard.SetScores(null));
|
||||||
AddStep(@"Network failure", () => leaderboard.SetRetrievalState(PlaceholderState.NetworkFailure));
|
|
||||||
AddStep(@"No supporter", () => leaderboard.SetRetrievalState(PlaceholderState.NotSupporter));
|
|
||||||
AddStep(@"Not logged in", () => leaderboard.SetRetrievalState(PlaceholderState.NotLoggedIn));
|
|
||||||
AddStep(@"Unavailable", () => leaderboard.SetRetrievalState(PlaceholderState.Unavailable));
|
|
||||||
AddStep(@"None selected", () => leaderboard.SetRetrievalState(PlaceholderState.NoneSelected));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
AddStep(@"Network failure", () => leaderboard.SetErrorState(LeaderboardState.NetworkFailure));
|
||||||
public void TestBeatmapStates()
|
AddStep(@"No supporter", () => leaderboard.SetErrorState(LeaderboardState.NotSupporter));
|
||||||
{
|
AddStep(@"Not logged in", () => leaderboard.SetErrorState(LeaderboardState.NotLoggedIn));
|
||||||
foreach (BeatmapOnlineStatus status in Enum.GetValues(typeof(BeatmapOnlineStatus)))
|
AddStep(@"Unavailable", () => leaderboard.SetErrorState(LeaderboardState.Unavailable));
|
||||||
AddStep($"{status} beatmap", () => showBeatmapWithStatus(status));
|
AddStep(@"None selected", () => leaderboard.SetErrorState(LeaderboardState.NoneSelected));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showPersonalBestWithNullPosition()
|
private void showPersonalBestWithNullPosition()
|
||||||
{
|
{
|
||||||
leaderboard.TopScore = new ScoreInfo
|
leaderboard.SetScores(leaderboard.Scores, new ScoreInfo
|
||||||
{
|
{
|
||||||
Rank = ScoreRank.XH,
|
Rank = ScoreRank.XH,
|
||||||
Accuracy = 1,
|
Accuracy = 1,
|
||||||
@ -148,12 +143,12 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
FlagName = @"ES",
|
FlagName = @"ES",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showPersonalBest()
|
private void showPersonalBest()
|
||||||
{
|
{
|
||||||
leaderboard.TopScore = new ScoreInfo
|
leaderboard.SetScores(leaderboard.Scores, new ScoreInfo
|
||||||
{
|
{
|
||||||
Position = 999,
|
Position = 999,
|
||||||
Rank = ScoreRank.XH,
|
Rank = ScoreRank.XH,
|
||||||
@ -172,7 +167,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
FlagName = @"ES",
|
FlagName = @"ES",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadMoreScores(Func<BeatmapInfo> beatmapInfo)
|
private void loadMoreScores(Func<BeatmapInfo> beatmapInfo)
|
||||||
@ -202,7 +197,24 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
Accuracy = 1,
|
Accuracy = 1,
|
||||||
MaxCombo = 244,
|
MaxCombo = 244,
|
||||||
TotalScore = 1707827,
|
TotalScore = 1707827,
|
||||||
//Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
Mods = new Mod[]
|
||||||
|
{
|
||||||
|
new OsuModHidden(),
|
||||||
|
new OsuModHardRock(),
|
||||||
|
new OsuModFlashlight
|
||||||
|
{
|
||||||
|
FollowDelay = { Value = 200 },
|
||||||
|
SizeMultiplier = { Value = 5 },
|
||||||
|
},
|
||||||
|
new OsuModDifficultyAdjust
|
||||||
|
{
|
||||||
|
CircleSize = { Value = 11 },
|
||||||
|
ApproachRate = { Value = 10 },
|
||||||
|
OverallDifficulty = { Value = 10 },
|
||||||
|
DrainRate = { Value = 10 },
|
||||||
|
ExtendedLimits = { Value = true }
|
||||||
|
}
|
||||||
|
},
|
||||||
Ruleset = new OsuRuleset().RulesetInfo,
|
Ruleset = new OsuRuleset().RulesetInfo,
|
||||||
BeatmapInfo = beatmapInfo,
|
BeatmapInfo = beatmapInfo,
|
||||||
User = new APIUser
|
User = new APIUser
|
||||||
@ -222,7 +234,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
Accuracy = 1,
|
Accuracy = 1,
|
||||||
MaxCombo = 244,
|
MaxCombo = 244,
|
||||||
TotalScore = 1707827,
|
TotalScore = 1707827,
|
||||||
//Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
||||||
BeatmapInfo = beatmapInfo,
|
BeatmapInfo = beatmapInfo,
|
||||||
Ruleset = new OsuRuleset().RulesetInfo,
|
Ruleset = new OsuRuleset().RulesetInfo,
|
||||||
User = new APIUser
|
User = new APIUser
|
||||||
@ -242,7 +254,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
Accuracy = 1,
|
Accuracy = 1,
|
||||||
MaxCombo = 244,
|
MaxCombo = 244,
|
||||||
TotalScore = 1707827,
|
TotalScore = 1707827,
|
||||||
//Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
||||||
BeatmapInfo = beatmapInfo,
|
BeatmapInfo = beatmapInfo,
|
||||||
Ruleset = new OsuRuleset().RulesetInfo,
|
Ruleset = new OsuRuleset().RulesetInfo,
|
||||||
|
|
||||||
@ -263,7 +275,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
Accuracy = 1,
|
Accuracy = 1,
|
||||||
MaxCombo = 244,
|
MaxCombo = 244,
|
||||||
TotalScore = 1707827,
|
TotalScore = 1707827,
|
||||||
//Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
||||||
BeatmapInfo = beatmapInfo,
|
BeatmapInfo = beatmapInfo,
|
||||||
Ruleset = new OsuRuleset().RulesetInfo,
|
Ruleset = new OsuRuleset().RulesetInfo,
|
||||||
|
|
||||||
@ -284,7 +296,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
Accuracy = 1,
|
Accuracy = 1,
|
||||||
MaxCombo = 244,
|
MaxCombo = 244,
|
||||||
TotalScore = 1707827,
|
TotalScore = 1707827,
|
||||||
//Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
||||||
BeatmapInfo = beatmapInfo,
|
BeatmapInfo = beatmapInfo,
|
||||||
Ruleset = new OsuRuleset().RulesetInfo,
|
Ruleset = new OsuRuleset().RulesetInfo,
|
||||||
|
|
||||||
@ -305,7 +317,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
Accuracy = 0.9826,
|
Accuracy = 0.9826,
|
||||||
MaxCombo = 244,
|
MaxCombo = 244,
|
||||||
TotalScore = 1707827,
|
TotalScore = 1707827,
|
||||||
//Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
||||||
BeatmapInfo = beatmapInfo,
|
BeatmapInfo = beatmapInfo,
|
||||||
Ruleset = new OsuRuleset().RulesetInfo,
|
Ruleset = new OsuRuleset().RulesetInfo,
|
||||||
|
|
||||||
@ -326,7 +338,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
Accuracy = 0.9654,
|
Accuracy = 0.9654,
|
||||||
MaxCombo = 244,
|
MaxCombo = 244,
|
||||||
TotalScore = 1707827,
|
TotalScore = 1707827,
|
||||||
//Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
||||||
BeatmapInfo = beatmapInfo,
|
BeatmapInfo = beatmapInfo,
|
||||||
Ruleset = new OsuRuleset().RulesetInfo,
|
Ruleset = new OsuRuleset().RulesetInfo,
|
||||||
|
|
||||||
@ -347,7 +359,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
Accuracy = 0.6025,
|
Accuracy = 0.6025,
|
||||||
MaxCombo = 244,
|
MaxCombo = 244,
|
||||||
TotalScore = 1707827,
|
TotalScore = 1707827,
|
||||||
//Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
||||||
BeatmapInfo = beatmapInfo,
|
BeatmapInfo = beatmapInfo,
|
||||||
Ruleset = new OsuRuleset().RulesetInfo,
|
Ruleset = new OsuRuleset().RulesetInfo,
|
||||||
|
|
||||||
@ -368,7 +380,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
Accuracy = 0.5140,
|
Accuracy = 0.5140,
|
||||||
MaxCombo = 244,
|
MaxCombo = 244,
|
||||||
TotalScore = 1707827,
|
TotalScore = 1707827,
|
||||||
//Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
||||||
BeatmapInfo = beatmapInfo,
|
BeatmapInfo = beatmapInfo,
|
||||||
Ruleset = new OsuRuleset().RulesetInfo,
|
Ruleset = new OsuRuleset().RulesetInfo,
|
||||||
|
|
||||||
@ -389,7 +401,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
Accuracy = 0.4222,
|
Accuracy = 0.4222,
|
||||||
MaxCombo = 244,
|
MaxCombo = 244,
|
||||||
TotalScore = 1707827,
|
TotalScore = 1707827,
|
||||||
//Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
||||||
BeatmapInfo = beatmapInfo,
|
BeatmapInfo = beatmapInfo,
|
||||||
Ruleset = new OsuRuleset().RulesetInfo,
|
Ruleset = new OsuRuleset().RulesetInfo,
|
||||||
|
|
||||||
@ -407,21 +419,10 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showBeatmapWithStatus(BeatmapOnlineStatus status)
|
|
||||||
{
|
|
||||||
leaderboard.BeatmapInfo = new BeatmapInfo
|
|
||||||
{
|
|
||||||
OnlineID = 1113057,
|
|
||||||
Status = status,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private class FailableLeaderboard : BeatmapLeaderboard
|
private class FailableLeaderboard : BeatmapLeaderboard
|
||||||
{
|
{
|
||||||
public void SetRetrievalState(PlaceholderState state)
|
public new void SetErrorState(LeaderboardState state) => base.SetErrorState(state);
|
||||||
{
|
public new void SetScores(IEnumerable<ScoreInfo> scores, ScoreInfo userScore = default) => base.SetScores(scores, userScore);
|
||||||
PlaceholderState = state;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@ using osu.Framework.Screens;
|
|||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
|
using osu.Game.Database;
|
||||||
using osu.Game.Extensions;
|
using osu.Game.Extensions;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
using osu.Game.Online.API.Requests.Responses;
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
@ -68,6 +69,8 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
{
|
{
|
||||||
Ruleset.Value = new OsuRuleset().RulesetInfo;
|
Ruleset.Value = new OsuRuleset().RulesetInfo;
|
||||||
Beatmap.SetDefault();
|
Beatmap.SetDefault();
|
||||||
|
|
||||||
|
songSelect = null;
|
||||||
});
|
});
|
||||||
|
|
||||||
AddStep("delete all beatmaps", () => manager?.Delete());
|
AddStep("delete all beatmaps", () => manager?.Delete());
|
||||||
@ -325,10 +328,10 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
changeRuleset(2);
|
changeRuleset(2);
|
||||||
addRulesetImportStep(2);
|
addRulesetImportStep(2);
|
||||||
addRulesetImportStep(1);
|
addRulesetImportStep(1);
|
||||||
AddUntilStep("has selection", () => songSelect.Carousel.SelectedBeatmapInfo.RulesetID == 2);
|
AddUntilStep("has selection", () => songSelect.Carousel.SelectedBeatmapInfo.Ruleset.OnlineID == 2);
|
||||||
|
|
||||||
changeRuleset(1);
|
changeRuleset(1);
|
||||||
AddUntilStep("has selection", () => songSelect.Carousel.SelectedBeatmapInfo.RulesetID == 1);
|
AddUntilStep("has selection", () => songSelect.Carousel.SelectedBeatmapInfo.Ruleset.OnlineID == 1);
|
||||||
|
|
||||||
changeRuleset(0);
|
changeRuleset(0);
|
||||||
AddUntilStep("no selection", () => songSelect.Carousel.SelectedBeatmapInfo == null);
|
AddUntilStep("no selection", () => songSelect.Carousel.SelectedBeatmapInfo == null);
|
||||||
@ -341,7 +344,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
changeRuleset(2);
|
changeRuleset(2);
|
||||||
|
|
||||||
addRulesetImportStep(2);
|
addRulesetImportStep(2);
|
||||||
AddUntilStep("has selection", () => songSelect.Carousel.SelectedBeatmapInfo.RulesetID == 2);
|
AddUntilStep("has selection", () => songSelect.Carousel.SelectedBeatmapInfo.Ruleset.OnlineID == 2);
|
||||||
|
|
||||||
addRulesetImportStep(0);
|
addRulesetImportStep(0);
|
||||||
addRulesetImportStep(0);
|
addRulesetImportStep(0);
|
||||||
@ -352,7 +355,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
AddStep("select beatmap/ruleset externally", () =>
|
AddStep("select beatmap/ruleset externally", () =>
|
||||||
{
|
{
|
||||||
target = manager.GetAllUsableBeatmapSets()
|
target = manager.GetAllUsableBeatmapSets()
|
||||||
.Last(b => b.Beatmaps.Any(bi => bi.RulesetID == 0)).Beatmaps.Last();
|
.Last(b => b.Beatmaps.Any(bi => bi.Ruleset.OnlineID == 0)).Beatmaps.Last();
|
||||||
|
|
||||||
Ruleset.Value = rulesets.AvailableRulesets.First(r => r.OnlineID == 0);
|
Ruleset.Value = rulesets.AvailableRulesets.First(r => r.OnlineID == 0);
|
||||||
Beatmap.Value = manager.GetWorkingBeatmap(target);
|
Beatmap.Value = manager.GetWorkingBeatmap(target);
|
||||||
@ -371,7 +374,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
changeRuleset(2);
|
changeRuleset(2);
|
||||||
|
|
||||||
addRulesetImportStep(2);
|
addRulesetImportStep(2);
|
||||||
AddUntilStep("has selection", () => songSelect.Carousel.SelectedBeatmapInfo.RulesetID == 2);
|
AddUntilStep("has selection", () => songSelect.Carousel.SelectedBeatmapInfo.Ruleset.OnlineID == 2);
|
||||||
|
|
||||||
addRulesetImportStep(0);
|
addRulesetImportStep(0);
|
||||||
addRulesetImportStep(0);
|
addRulesetImportStep(0);
|
||||||
@ -382,7 +385,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
AddStep("select beatmap/ruleset externally", () =>
|
AddStep("select beatmap/ruleset externally", () =>
|
||||||
{
|
{
|
||||||
target = manager.GetAllUsableBeatmapSets()
|
target = manager.GetAllUsableBeatmapSets()
|
||||||
.Last(b => b.Beatmaps.Any(bi => bi.RulesetID == 0)).Beatmaps.Last();
|
.Last(b => b.Beatmaps.Any(bi => bi.Ruleset.OnlineID == 0)).Beatmaps.Last();
|
||||||
|
|
||||||
Beatmap.Value = manager.GetWorkingBeatmap(target);
|
Beatmap.Value = manager.GetWorkingBeatmap(target);
|
||||||
Ruleset.Value = rulesets.AvailableRulesets.First(r => r.OnlineID == 0);
|
Ruleset.Value = rulesets.AvailableRulesets.First(r => r.OnlineID == 0);
|
||||||
@ -493,9 +496,9 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
AddStep("select beatmap externally", () =>
|
AddStep("select beatmap externally", () =>
|
||||||
{
|
{
|
||||||
target = manager.GetAllUsableBeatmapSets()
|
target = manager.GetAllUsableBeatmapSets()
|
||||||
.First(b => b.Beatmaps.Any(bi => bi.RulesetID == targetRuleset))
|
.First(b => b.Beatmaps.Any(bi => bi.Ruleset.OnlineID == targetRuleset))
|
||||||
.Beatmaps
|
.Beatmaps
|
||||||
.First(bi => bi.RulesetID == targetRuleset);
|
.First(bi => bi.Ruleset.OnlineID == targetRuleset);
|
||||||
|
|
||||||
Beatmap.Value = manager.GetWorkingBeatmap(target);
|
Beatmap.Value = manager.GetWorkingBeatmap(target);
|
||||||
});
|
});
|
||||||
@ -544,7 +547,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
{
|
{
|
||||||
target = manager
|
target = manager
|
||||||
.GetAllUsableBeatmapSets()
|
.GetAllUsableBeatmapSets()
|
||||||
.First(b => b.Beatmaps.Any(bi => bi.RulesetID == 1))
|
.First(b => b.Beatmaps.Any(bi => bi.Ruleset.OnlineID == 1))
|
||||||
.Beatmaps.First();
|
.Beatmaps.First();
|
||||||
|
|
||||||
Beatmap.Value = manager.GetWorkingBeatmap(target);
|
Beatmap.Value = manager.GetWorkingBeatmap(target);
|
||||||
@ -799,8 +802,8 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestChangeRulesetWhilePresentingScore()
|
public void TestChangeRulesetWhilePresentingScore()
|
||||||
{
|
{
|
||||||
BeatmapInfo getPresentBeatmap() => manager.GetAllUsableBeatmapSets().Where(s => !s.DeletePending).SelectMany(s => s.Beatmaps).First(b => b.RulesetID == 0);
|
BeatmapInfo getPresentBeatmap() => manager.GetAllUsableBeatmapSets().Where(s => !s.DeletePending).SelectMany(s => s.Beatmaps).First(b => b.Ruleset.OnlineID == 0);
|
||||||
BeatmapInfo getSwitchBeatmap() => manager.GetAllUsableBeatmapSets().Where(s => !s.DeletePending).SelectMany(s => s.Beatmaps).First(b => b.RulesetID == 1);
|
BeatmapInfo getSwitchBeatmap() => manager.GetAllUsableBeatmapSets().Where(s => !s.DeletePending).SelectMany(s => s.Beatmaps).First(b => b.Ruleset.OnlineID == 1);
|
||||||
|
|
||||||
changeRuleset(0);
|
changeRuleset(0);
|
||||||
|
|
||||||
@ -831,8 +834,8 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestChangeBeatmapWhilePresentingScore()
|
public void TestChangeBeatmapWhilePresentingScore()
|
||||||
{
|
{
|
||||||
BeatmapInfo getPresentBeatmap() => manager.GetAllUsableBeatmapSets().Where(s => !s.DeletePending).SelectMany(s => s.Beatmaps).First(b => b.RulesetID == 0);
|
BeatmapInfo getPresentBeatmap() => manager.GetAllUsableBeatmapSets().Where(s => !s.DeletePending).SelectMany(s => s.Beatmaps).First(b => b.Ruleset.OnlineID == 0);
|
||||||
BeatmapInfo getSwitchBeatmap() => manager.GetAllUsableBeatmapSets().Where(s => !s.DeletePending).SelectMany(s => s.Beatmaps).First(b => b.RulesetID == 1);
|
BeatmapInfo getSwitchBeatmap() => manager.GetAllUsableBeatmapSets().Where(s => !s.DeletePending).SelectMany(s => s.Beatmaps).First(b => b.Ruleset.OnlineID == 1);
|
||||||
|
|
||||||
changeRuleset(0);
|
changeRuleset(0);
|
||||||
|
|
||||||
@ -870,9 +873,16 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
return set.ChildrenOfType<FilterableDifficultyIcon>().ToList().FindIndex(i => i == icon);
|
return set.ChildrenOfType<FilterableDifficultyIcon>().ToList().FindIndex(i => i == icon);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addRulesetImportStep(int id) => AddStep($"import test map for ruleset {id}", () => importForRuleset(id));
|
private void addRulesetImportStep(int id)
|
||||||
|
{
|
||||||
|
Live<BeatmapSetInfo> imported = null;
|
||||||
|
AddStep($"import test map for ruleset {id}", () => imported = importForRuleset(id));
|
||||||
|
// This is specifically for cases where the add is happening post song select load.
|
||||||
|
// For cases where song select is null, the assertions are provided by the load checks.
|
||||||
|
AddUntilStep("wait for imported to arrive in carousel", () => songSelect == null || songSelect.Carousel.BeatmapSets.Any(s => s.ID == imported?.ID));
|
||||||
|
}
|
||||||
|
|
||||||
private void importForRuleset(int id) => manager.Import(TestResources.CreateTestBeatmapSetInfo(3, rulesets.AvailableRulesets.Where(r => r.OnlineID == id).ToArray()));
|
private Live<BeatmapSetInfo> importForRuleset(int id) => manager.Import(TestResources.CreateTestBeatmapSetInfo(3, rulesets.AvailableRulesets.Where(r => r.OnlineID == id).ToArray()));
|
||||||
|
|
||||||
private void checkMusicPlaying(bool playing) =>
|
private void checkMusicPlaying(bool playing) =>
|
||||||
AddUntilStep($"music {(playing ? "" : "not ")}playing", () => music.IsPlaying == playing);
|
AddUntilStep($"music {(playing ? "" : "not ")}playing", () => music.IsPlaying == playing);
|
||||||
|
@ -128,21 +128,16 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
scoreManager.Undelete(r.All<ScoreInfo>().Where(s => s.DeletePending).ToList());
|
scoreManager.Undelete(r.All<ScoreInfo>().Where(s => s.DeletePending).ToList());
|
||||||
});
|
});
|
||||||
|
|
||||||
leaderboard.Scores = null;
|
|
||||||
leaderboard.FinishTransforms(true); // After setting scores, we may be waiting for transforms to expire drawables
|
|
||||||
|
|
||||||
leaderboard.BeatmapInfo = beatmapInfo;
|
leaderboard.BeatmapInfo = beatmapInfo;
|
||||||
leaderboard.RefreshScores(); // Required in the case that the beatmap hasn't changed
|
leaderboard.RefetchScores(); // Required in the case that the beatmap hasn't changed
|
||||||
});
|
});
|
||||||
|
|
||||||
[SetUpSteps]
|
[SetUpSteps]
|
||||||
public void SetupSteps()
|
public void SetupSteps()
|
||||||
{
|
{
|
||||||
// Ensure the leaderboard has finished async-loading drawables
|
|
||||||
AddUntilStep("wait for drawables", () => leaderboard.ChildrenOfType<LeaderboardScore>().Any());
|
|
||||||
|
|
||||||
// Ensure the leaderboard items have finished showing up
|
// Ensure the leaderboard items have finished showing up
|
||||||
AddStep("finish transforms", () => leaderboard.FinishTransforms(true));
|
AddStep("finish transforms", () => leaderboard.FinishTransforms(true));
|
||||||
|
AddUntilStep("wait for drawables", () => leaderboard.ChildrenOfType<LeaderboardScore>().Any());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
@ -8,6 +8,7 @@ using osu.Framework.Graphics;
|
|||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Database;
|
||||||
using osu.Game.Graphics.Containers;
|
using osu.Game.Graphics.Containers;
|
||||||
using osu.Game.Overlays.Music;
|
using osu.Game.Overlays.Music;
|
||||||
using osu.Game.Tests.Resources;
|
using osu.Game.Tests.Resources;
|
||||||
@ -18,11 +19,11 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
{
|
{
|
||||||
public class TestScenePlaylistOverlay : OsuManualInputManagerTestScene
|
public class TestScenePlaylistOverlay : OsuManualInputManagerTestScene
|
||||||
{
|
{
|
||||||
private readonly BindableList<BeatmapSetInfo> beatmapSets = new BindableList<BeatmapSetInfo>();
|
private readonly BindableList<Live<BeatmapSetInfo>> beatmapSets = new BindableList<Live<BeatmapSetInfo>>();
|
||||||
|
|
||||||
private PlaylistOverlay playlistOverlay;
|
private PlaylistOverlay playlistOverlay;
|
||||||
|
|
||||||
private BeatmapSetInfo first;
|
private Live<BeatmapSetInfo> first;
|
||||||
|
|
||||||
[SetUp]
|
[SetUp]
|
||||||
public void Setup() => Schedule(() =>
|
public void Setup() => Schedule(() =>
|
||||||
@ -45,7 +46,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
|
|
||||||
for (int i = 0; i < 100; i++)
|
for (int i = 0; i < 100; i++)
|
||||||
{
|
{
|
||||||
beatmapSets.Add(TestResources.CreateTestBeatmapSetInfo());
|
beatmapSets.Add(TestResources.CreateTestBeatmapSetInfo().ToLiveUnmanaged());
|
||||||
}
|
}
|
||||||
|
|
||||||
first = beatmapSets.First();
|
first = beatmapSets.First();
|
||||||
@ -60,7 +61,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
|
|
||||||
AddStep("hold 1st item handle", () =>
|
AddStep("hold 1st item handle", () =>
|
||||||
{
|
{
|
||||||
var handle = this.ChildrenOfType<OsuRearrangeableListItem<BeatmapSetInfo>.PlaylistItemHandle>().First();
|
var handle = this.ChildrenOfType<OsuRearrangeableListItem<Live<BeatmapSetInfo>>.PlaylistItemHandle>().First();
|
||||||
InputManager.MoveMouseTo(handle.ScreenSpaceDrawQuad.Centre);
|
InputManager.MoveMouseTo(handle.ScreenSpaceDrawQuad.Centre);
|
||||||
InputManager.PressButton(MouseButton.Left);
|
InputManager.PressButton(MouseButton.Left);
|
||||||
});
|
});
|
||||||
@ -68,7 +69,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
AddStep("drag to 5th", () =>
|
AddStep("drag to 5th", () =>
|
||||||
{
|
{
|
||||||
var item = this.ChildrenOfType<PlaylistItem>().ElementAt(4);
|
var item = this.ChildrenOfType<PlaylistItem>().ElementAt(4);
|
||||||
InputManager.MoveMouseTo(item.ScreenSpaceDrawQuad.Centre);
|
InputManager.MoveMouseTo(item.ScreenSpaceDrawQuad.BottomLeft);
|
||||||
});
|
});
|
||||||
|
|
||||||
AddAssert("song 1 is 5th", () => beatmapSets[4].Equals(first));
|
AddAssert("song 1 is 5th", () => beatmapSets[4].Equals(first));
|
||||||
|
@ -47,7 +47,7 @@ namespace osu.Game.Tournament.Components
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var ruleset = rulesets.GetRuleset(ladderInfo.Ruleset.Value?.ID ?? 0);
|
var ruleset = rulesets.GetRuleset(ladderInfo.Ruleset.Value?.OnlineID ?? 0);
|
||||||
var modIcon = ruleset?.CreateInstance().CreateModFromAcronym(modAcronym);
|
var modIcon = ruleset?.CreateInstance().CreateModFromAcronym(modAcronym);
|
||||||
|
|
||||||
if (modIcon == null)
|
if (modIcon == null)
|
||||||
|
@ -61,18 +61,15 @@ namespace osu.Game.Tournament
|
|||||||
|
|
||||||
loadingSpinner.Show();
|
loadingSpinner.Show();
|
||||||
|
|
||||||
BracketLoadTask.ContinueWith(t =>
|
BracketLoadTask.ContinueWith(t => Schedule(() =>
|
||||||
{
|
{
|
||||||
if (t.IsFaulted)
|
if (t.IsFaulted)
|
||||||
{
|
|
||||||
Schedule(() =>
|
|
||||||
{
|
{
|
||||||
loadingSpinner.Hide();
|
loadingSpinner.Hide();
|
||||||
loadingSpinner.Expire();
|
loadingSpinner.Expire();
|
||||||
|
|
||||||
Logger.Error(t.Exception, "Couldn't load bracket with error");
|
Logger.Error(t.Exception, "Couldn't load bracket with error");
|
||||||
Add(new WarningBox($"Your {BRACKET_FILENAME} file could not be parsed. Please check runtime.log for more details."));
|
Add(new WarningBox($"Your {BRACKET_FILENAME} file could not be parsed. Please check runtime.log for more details."));
|
||||||
});
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -143,7 +140,7 @@ namespace osu.Game.Tournament
|
|||||||
windowMode.Value = WindowMode.Windowed;
|
windowMode.Value = WindowMode.Windowed;
|
||||||
}), true);
|
}), true);
|
||||||
});
|
});
|
||||||
});
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -99,11 +99,11 @@ namespace osu.Game.Beatmaps
|
|||||||
|
|
||||||
public bool LetterboxInBreaks { get; set; }
|
public bool LetterboxInBreaks { get; set; }
|
||||||
|
|
||||||
public bool WidescreenStoryboard { get; set; }
|
public bool WidescreenStoryboard { get; set; } = true;
|
||||||
|
|
||||||
public bool EpilepsyWarning { get; set; }
|
public bool EpilepsyWarning { get; set; }
|
||||||
|
|
||||||
public bool SamplesMatchPlaybackRate { get; set; }
|
public bool SamplesMatchPlaybackRate { get; set; } = true;
|
||||||
|
|
||||||
public double DistanceSpacing { get; set; }
|
public double DistanceSpacing { get; set; }
|
||||||
|
|
||||||
@ -155,7 +155,6 @@ namespace osu.Game.Beatmaps
|
|||||||
[Ignored]
|
[Ignored]
|
||||||
public int RulesetID
|
public int RulesetID
|
||||||
{
|
{
|
||||||
get => Ruleset.OnlineID;
|
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrEmpty(Ruleset.InstantiationInfo))
|
if (!string.IsNullOrEmpty(Ruleset.InstantiationInfo))
|
||||||
|
@ -90,14 +90,7 @@ namespace osu.Game.Beatmaps
|
|||||||
{
|
{
|
||||||
Beatmaps =
|
Beatmaps =
|
||||||
{
|
{
|
||||||
new BeatmapInfo
|
new BeatmapInfo(ruleset, new BeatmapDifficulty(), metadata)
|
||||||
{
|
|
||||||
Difficulty = new BeatmapDifficulty(),
|
|
||||||
Ruleset = ruleset,
|
|
||||||
Metadata = metadata,
|
|
||||||
WidescreenStoryboard = true,
|
|
||||||
SamplesMatchPlaybackRate = true,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -39,14 +39,14 @@ namespace osu.Game.Beatmaps
|
|||||||
/// The time in milliseconds to begin playing the track for preview purposes.
|
/// The time in milliseconds to begin playing the track for preview purposes.
|
||||||
/// If -1, the track should begin playing at 40% of its length.
|
/// If -1, the track should begin playing at 40% of its length.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int PreviewTime { get; set; }
|
public int PreviewTime { get; set; } = -1;
|
||||||
|
|
||||||
public string AudioFile { get; set; } = string.Empty;
|
public string AudioFile { get; set; } = string.Empty;
|
||||||
public string BackgroundFile { get; set; } = string.Empty;
|
public string BackgroundFile { get; set; } = string.Empty;
|
||||||
|
|
||||||
public BeatmapMetadata(RealmUser? user = null)
|
public BeatmapMetadata(RealmUser? user = null)
|
||||||
{
|
{
|
||||||
Author = new RealmUser();
|
Author = user ?? new RealmUser();
|
||||||
}
|
}
|
||||||
|
|
||||||
[UsedImplicitly] // Realm
|
[UsedImplicitly] // Realm
|
||||||
|
@ -30,6 +30,7 @@ namespace osu.Game.Beatmaps.Drawables
|
|||||||
{
|
{
|
||||||
background = new Box
|
background = new Box
|
||||||
{
|
{
|
||||||
|
Alpha = 0.9f,
|
||||||
RelativeSizeAxes = Axes.Both
|
RelativeSizeAxes = Axes.Both
|
||||||
},
|
},
|
||||||
new FillFlowContainer
|
new FillFlowContainer
|
||||||
|
@ -30,7 +30,7 @@ namespace osu.Game.Beatmaps
|
|||||||
{
|
{
|
||||||
this.beatmap = beatmap;
|
this.beatmap = beatmap;
|
||||||
|
|
||||||
beatmap.BeatmapInfo.Ruleset = rulesetProvider(beatmap.BeatmapInfo.RulesetID).RulesetInfo;
|
beatmap.BeatmapInfo.Ruleset = rulesetProvider(beatmap.BeatmapInfo.Ruleset.OnlineID).RulesetInfo;
|
||||||
|
|
||||||
if (beatmapId.HasValue)
|
if (beatmapId.HasValue)
|
||||||
beatmap.BeatmapInfo.OnlineID = beatmapId.Value;
|
beatmap.BeatmapInfo.OnlineID = beatmapId.Value;
|
||||||
|
@ -56,6 +56,8 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
this.beatmap = beatmap;
|
this.beatmap = beatmap;
|
||||||
this.beatmap.BeatmapInfo.BeatmapVersion = FormatVersion;
|
this.beatmap.BeatmapInfo.BeatmapVersion = FormatVersion;
|
||||||
|
|
||||||
|
applyLegacyDefaults(this.beatmap.BeatmapInfo);
|
||||||
|
|
||||||
base.ParseStreamInto(stream, beatmap);
|
base.ParseStreamInto(stream, beatmap);
|
||||||
|
|
||||||
flushPendingPoints();
|
flushPendingPoints();
|
||||||
@ -70,6 +72,19 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
hitObject.ApplyDefaults(this.beatmap.ControlPointInfo, this.beatmap.Difficulty);
|
hitObject.ApplyDefaults(this.beatmap.ControlPointInfo, this.beatmap.Difficulty);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Some `BeatmapInfo` members have default values that differ from the default values used by stable.
|
||||||
|
/// In addition, legacy beatmaps will sometimes not contain some configuration keys, in which case
|
||||||
|
/// the legacy default values should be used.
|
||||||
|
/// This method's intention is to restore those legacy defaults.
|
||||||
|
/// See also: https://osu.ppy.sh/wiki/en/Client/File_formats/Osu_%28file_format%29
|
||||||
|
/// </summary>
|
||||||
|
private void applyLegacyDefaults(BeatmapInfo beatmapInfo)
|
||||||
|
{
|
||||||
|
beatmapInfo.WidescreenStoryboard = false;
|
||||||
|
beatmapInfo.SamplesMatchPlaybackRate = false;
|
||||||
|
}
|
||||||
|
|
||||||
protected override bool ShouldSkipLine(string line) => base.ShouldSkipLine(line) || line.StartsWith(' ') || line.StartsWith('_');
|
protected override bool ShouldSkipLine(string line) => base.ShouldSkipLine(line) || line.StartsWith(' ') || line.StartsWith('_');
|
||||||
|
|
||||||
protected override void ParseLine(Beatmap beatmap, Section section, string line)
|
protected override void ParseLine(Beatmap beatmap, Section section, string line)
|
||||||
@ -141,9 +156,11 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case @"Mode":
|
case @"Mode":
|
||||||
beatmap.BeatmapInfo.RulesetID = Parsing.ParseInt(pair.Value);
|
int rulesetID = Parsing.ParseInt(pair.Value);
|
||||||
|
|
||||||
switch (beatmap.BeatmapInfo.RulesetID)
|
beatmap.BeatmapInfo.RulesetID = rulesetID;
|
||||||
|
|
||||||
|
switch (rulesetID)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
parser = new Rulesets.Objects.Legacy.Osu.ConvertHitObjectParser(getOffsetTime(), FormatVersion);
|
parser = new Rulesets.Objects.Legacy.Osu.ConvertHitObjectParser(getOffsetTime(), FormatVersion);
|
||||||
@ -294,10 +311,13 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
|
|
||||||
case @"OverallDifficulty":
|
case @"OverallDifficulty":
|
||||||
difficulty.OverallDifficulty = Parsing.ParseFloat(pair.Value);
|
difficulty.OverallDifficulty = Parsing.ParseFloat(pair.Value);
|
||||||
|
if (!hasApproachRate)
|
||||||
|
difficulty.ApproachRate = difficulty.OverallDifficulty;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case @"ApproachRate":
|
case @"ApproachRate":
|
||||||
difficulty.ApproachRate = Parsing.ParseFloat(pair.Value);
|
difficulty.ApproachRate = Parsing.ParseFloat(pair.Value);
|
||||||
|
hasApproachRate = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case @"SliderMultiplier":
|
case @"SliderMultiplier":
|
||||||
@ -397,7 +417,7 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
OmitFirstBarLine = omitFirstBarSignature,
|
OmitFirstBarLine = omitFirstBarSignature,
|
||||||
};
|
};
|
||||||
|
|
||||||
bool isOsuRuleset = beatmap.BeatmapInfo.RulesetID == 0;
|
bool isOsuRuleset = beatmap.BeatmapInfo.Ruleset.OnlineID == 0;
|
||||||
// scrolling rulesets use effect points rather than difficulty points for scroll speed adjustments.
|
// scrolling rulesets use effect points rather than difficulty points for scroll speed adjustments.
|
||||||
if (!isOsuRuleset)
|
if (!isOsuRuleset)
|
||||||
effectPoint.ScrollSpeed = speedMultiplier;
|
effectPoint.ScrollSpeed = speedMultiplier;
|
||||||
@ -415,6 +435,7 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
private readonly List<ControlPoint> pendingControlPoints = new List<ControlPoint>();
|
private readonly List<ControlPoint> pendingControlPoints = new List<ControlPoint>();
|
||||||
private readonly HashSet<Type> pendingControlPointTypes = new HashSet<Type>();
|
private readonly HashSet<Type> pendingControlPointTypes = new HashSet<Type>();
|
||||||
private double pendingControlPointsTime;
|
private double pendingControlPointsTime;
|
||||||
|
private bool hasApproachRate;
|
||||||
|
|
||||||
private void addControlPoint(double time, ControlPoint point, bool timingChange)
|
private void addControlPoint(double time, ControlPoint point, bool timingChange)
|
||||||
{
|
{
|
||||||
|
@ -35,6 +35,8 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
[CanBeNull]
|
[CanBeNull]
|
||||||
private readonly ISkin skin;
|
private readonly ISkin skin;
|
||||||
|
|
||||||
|
private readonly int onlineRulesetID;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new <see cref="LegacyBeatmapEncoder"/>.
|
/// Creates a new <see cref="LegacyBeatmapEncoder"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -45,7 +47,9 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
this.beatmap = beatmap;
|
this.beatmap = beatmap;
|
||||||
this.skin = skin;
|
this.skin = skin;
|
||||||
|
|
||||||
if (beatmap.BeatmapInfo.RulesetID < 0 || beatmap.BeatmapInfo.RulesetID > 3)
|
onlineRulesetID = beatmap.BeatmapInfo.Ruleset.OnlineID;
|
||||||
|
|
||||||
|
if (onlineRulesetID < 0 || onlineRulesetID > 3)
|
||||||
throw new ArgumentException("Only beatmaps in the osu, taiko, catch, or mania rulesets can be encoded to the legacy beatmap format.", nameof(beatmap));
|
throw new ArgumentException("Only beatmaps in the osu, taiko, catch, or mania rulesets can be encoded to the legacy beatmap format.", nameof(beatmap));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,7 +92,7 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
writer.WriteLine(FormattableString.Invariant($"Countdown: {(int)beatmap.BeatmapInfo.Countdown}"));
|
writer.WriteLine(FormattableString.Invariant($"Countdown: {(int)beatmap.BeatmapInfo.Countdown}"));
|
||||||
writer.WriteLine(FormattableString.Invariant($"SampleSet: {toLegacySampleBank((beatmap.HitObjects.FirstOrDefault()?.SampleControlPoint ?? SampleControlPoint.DEFAULT).SampleBank)}"));
|
writer.WriteLine(FormattableString.Invariant($"SampleSet: {toLegacySampleBank((beatmap.HitObjects.FirstOrDefault()?.SampleControlPoint ?? SampleControlPoint.DEFAULT).SampleBank)}"));
|
||||||
writer.WriteLine(FormattableString.Invariant($"StackLeniency: {beatmap.BeatmapInfo.StackLeniency}"));
|
writer.WriteLine(FormattableString.Invariant($"StackLeniency: {beatmap.BeatmapInfo.StackLeniency}"));
|
||||||
writer.WriteLine(FormattableString.Invariant($"Mode: {beatmap.BeatmapInfo.RulesetID}"));
|
writer.WriteLine(FormattableString.Invariant($"Mode: {onlineRulesetID}"));
|
||||||
writer.WriteLine(FormattableString.Invariant($"LetterboxInBreaks: {(beatmap.BeatmapInfo.LetterboxInBreaks ? '1' : '0')}"));
|
writer.WriteLine(FormattableString.Invariant($"LetterboxInBreaks: {(beatmap.BeatmapInfo.LetterboxInBreaks ? '1' : '0')}"));
|
||||||
// if (beatmap.BeatmapInfo.UseSkinSprites)
|
// if (beatmap.BeatmapInfo.UseSkinSprites)
|
||||||
// writer.WriteLine(@"UseSkinSprites: 1");
|
// writer.WriteLine(@"UseSkinSprites: 1");
|
||||||
@ -102,7 +106,7 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
writer.WriteLine(@"EpilepsyWarning: 1");
|
writer.WriteLine(@"EpilepsyWarning: 1");
|
||||||
if (beatmap.BeatmapInfo.CountdownOffset > 0)
|
if (beatmap.BeatmapInfo.CountdownOffset > 0)
|
||||||
writer.WriteLine(FormattableString.Invariant($@"CountdownOffset: {beatmap.BeatmapInfo.CountdownOffset}"));
|
writer.WriteLine(FormattableString.Invariant($@"CountdownOffset: {beatmap.BeatmapInfo.CountdownOffset}"));
|
||||||
if (beatmap.BeatmapInfo.RulesetID == 3)
|
if (onlineRulesetID == 3)
|
||||||
writer.WriteLine(FormattableString.Invariant($"SpecialStyle: {(beatmap.BeatmapInfo.SpecialStyle ? '1' : '0')}"));
|
writer.WriteLine(FormattableString.Invariant($"SpecialStyle: {(beatmap.BeatmapInfo.SpecialStyle ? '1' : '0')}"));
|
||||||
writer.WriteLine(FormattableString.Invariant($"WidescreenStoryboard: {(beatmap.BeatmapInfo.WidescreenStoryboard ? '1' : '0')}"));
|
writer.WriteLine(FormattableString.Invariant($"WidescreenStoryboard: {(beatmap.BeatmapInfo.WidescreenStoryboard ? '1' : '0')}"));
|
||||||
if (beatmap.BeatmapInfo.SamplesMatchPlaybackRate)
|
if (beatmap.BeatmapInfo.SamplesMatchPlaybackRate)
|
||||||
@ -147,7 +151,7 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
writer.WriteLine(FormattableString.Invariant($"ApproachRate: {beatmap.Difficulty.ApproachRate}"));
|
writer.WriteLine(FormattableString.Invariant($"ApproachRate: {beatmap.Difficulty.ApproachRate}"));
|
||||||
|
|
||||||
// Taiko adjusts the slider multiplier (see: LEGACY_TAIKO_VELOCITY_MULTIPLIER)
|
// Taiko adjusts the slider multiplier (see: LEGACY_TAIKO_VELOCITY_MULTIPLIER)
|
||||||
writer.WriteLine(beatmap.BeatmapInfo.RulesetID == 1
|
writer.WriteLine(onlineRulesetID == 1
|
||||||
? FormattableString.Invariant($"SliderMultiplier: {beatmap.Difficulty.SliderMultiplier / LEGACY_TAIKO_VELOCITY_MULTIPLIER}")
|
? FormattableString.Invariant($"SliderMultiplier: {beatmap.Difficulty.SliderMultiplier / LEGACY_TAIKO_VELOCITY_MULTIPLIER}")
|
||||||
: FormattableString.Invariant($"SliderMultiplier: {beatmap.Difficulty.SliderMultiplier}"));
|
: FormattableString.Invariant($"SliderMultiplier: {beatmap.Difficulty.SliderMultiplier}"));
|
||||||
|
|
||||||
@ -179,7 +183,7 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
SampleControlPoint lastRelevantSamplePoint = null;
|
SampleControlPoint lastRelevantSamplePoint = null;
|
||||||
DifficultyControlPoint lastRelevantDifficultyPoint = null;
|
DifficultyControlPoint lastRelevantDifficultyPoint = null;
|
||||||
|
|
||||||
bool isOsuRuleset = beatmap.BeatmapInfo.RulesetID == 0;
|
bool isOsuRuleset = onlineRulesetID == 0;
|
||||||
|
|
||||||
// iterate over hitobjects and pull out all required sample and difficulty changes
|
// iterate over hitobjects and pull out all required sample and difficulty changes
|
||||||
extractDifficultyControlPoints(beatmap.HitObjects);
|
extractDifficultyControlPoints(beatmap.HitObjects);
|
||||||
@ -318,7 +322,7 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
{
|
{
|
||||||
Vector2 position = new Vector2(256, 192);
|
Vector2 position = new Vector2(256, 192);
|
||||||
|
|
||||||
switch (beatmap.BeatmapInfo.RulesetID)
|
switch (onlineRulesetID)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
case 2:
|
case 2:
|
||||||
@ -372,7 +376,7 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case IHasDuration _:
|
case IHasDuration _:
|
||||||
if (beatmap.BeatmapInfo.RulesetID == 3)
|
if (onlineRulesetID == 3)
|
||||||
type |= LegacyHitObjectType.Hold;
|
type |= LegacyHitObjectType.Hold;
|
||||||
else
|
else
|
||||||
type |= LegacyHitObjectType.Spinner;
|
type |= LegacyHitObjectType.Spinner;
|
||||||
|
@ -25,7 +25,7 @@ namespace osu.Game.Collections
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The beatmaps contained by the collection.
|
/// The beatmaps contained by the collection.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly BindableList<IBeatmapInfo> Beatmaps = new BindableList<IBeatmapInfo>();
|
public readonly BindableList<BeatmapInfo> Beatmaps = new BindableList<BeatmapInfo>();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The date when this collection was last modified.
|
/// The date when this collection was last modified.
|
||||||
|
@ -38,7 +38,7 @@ namespace osu.Game.Collections
|
|||||||
}
|
}
|
||||||
|
|
||||||
private readonly IBindableList<BeatmapCollection> collections = new BindableList<BeatmapCollection>();
|
private readonly IBindableList<BeatmapCollection> collections = new BindableList<BeatmapCollection>();
|
||||||
private readonly IBindableList<IBeatmapInfo> beatmaps = new BindableList<IBeatmapInfo>();
|
private readonly IBindableList<BeatmapInfo> beatmaps = new BindableList<BeatmapInfo>();
|
||||||
private readonly BindableList<CollectionFilterMenuItem> filters = new BindableList<CollectionFilterMenuItem>();
|
private readonly BindableList<CollectionFilterMenuItem> filters = new BindableList<CollectionFilterMenuItem>();
|
||||||
|
|
||||||
[Resolved(CanBeNull = true)]
|
[Resolved(CanBeNull = true)]
|
||||||
@ -196,7 +196,7 @@ namespace osu.Game.Collections
|
|||||||
private IBindable<WorkingBeatmap> beatmap { get; set; }
|
private IBindable<WorkingBeatmap> beatmap { get; set; }
|
||||||
|
|
||||||
[CanBeNull]
|
[CanBeNull]
|
||||||
private readonly BindableList<IBeatmapInfo> collectionBeatmaps;
|
private readonly BindableList<BeatmapInfo> collectionBeatmaps;
|
||||||
|
|
||||||
[NotNull]
|
[NotNull]
|
||||||
private readonly Bindable<string> collectionName;
|
private readonly Bindable<string> collectionName;
|
||||||
|
@ -50,9 +50,14 @@ namespace osu.Game.Collections
|
|||||||
this.storage = storage;
|
this.storage = storage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Resolved(canBeNull: true)]
|
||||||
|
private DatabaseContextFactory efContextFactory { get; set; } = null!;
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
{
|
{
|
||||||
|
efContextFactory?.WaitForMigrationCompletion();
|
||||||
|
|
||||||
Collections.CollectionChanged += collectionsChanged;
|
Collections.CollectionChanged += collectionsChanged;
|
||||||
|
|
||||||
if (storage.Exists(database_backup_name))
|
if (storage.Exists(database_backup_name))
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user