Merge branch 'master' into show-loved-pp
2
.github/ISSUE_TEMPLATE/01-bug-issues.md
vendored
@ -9,6 +9,8 @@ about: Issues regarding encountered bugs.
|
||||
**osu!lazer version:**
|
||||
|
||||
**Logs:**
|
||||
<!--
|
||||
*please attach logs here, which are located at:*
|
||||
- `%AppData%/osu/logs` *(on Windows),*
|
||||
- `~/.local/share/osu/logs` *(on Linux & macOS).*
|
||||
-->
|
||||
|
2
.github/ISSUE_TEMPLATE/02-crash-issues.md
vendored
@ -9,8 +9,10 @@ about: Issues regarding crashes or permanent freezes.
|
||||
**osu!lazer version:**
|
||||
|
||||
**Logs:**
|
||||
<!--
|
||||
*please attach logs here, which are located at:*
|
||||
- `%AppData%/osu/logs` *(on Windows),*
|
||||
- `~/.local/share/osu/logs` *(on Linux & macOS).*
|
||||
-->
|
||||
|
||||
**Computer Specifications:**
|
||||
|
42
.vscode/launch.json
vendored
@ -11,11 +11,6 @@
|
||||
],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build osu! (Debug)",
|
||||
"linux": {
|
||||
"env": {
|
||||
"LD_LIBRARY_PATH": "${workspaceRoot}/osu.Desktop/bin/Debug/netcoreapp3.1:${env:LD_LIBRARY_PATH}"
|
||||
}
|
||||
},
|
||||
"console": "internalConsole"
|
||||
},
|
||||
{
|
||||
@ -28,11 +23,6 @@
|
||||
],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build osu! (Release)",
|
||||
"linux": {
|
||||
"env": {
|
||||
"LD_LIBRARY_PATH": "${workspaceRoot}/osu.Desktop/bin/Release/netcoreapp3.1:${env:LD_LIBRARY_PATH}"
|
||||
}
|
||||
},
|
||||
"console": "internalConsole"
|
||||
},
|
||||
{
|
||||
@ -45,11 +35,6 @@
|
||||
],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build tests (Debug)",
|
||||
"linux": {
|
||||
"env": {
|
||||
"LD_LIBRARY_PATH": "${workspaceRoot}/osu.Game.Tests/bin/Debug/netcoreapp3.1:${env:LD_LIBRARY_PATH}"
|
||||
}
|
||||
},
|
||||
"console": "internalConsole"
|
||||
},
|
||||
{
|
||||
@ -62,11 +47,6 @@
|
||||
],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build tests (Release)",
|
||||
"linux": {
|
||||
"env": {
|
||||
"LD_LIBRARY_PATH": "${workspaceRoot}/osu.Game.Tests/bin/Release/netcoreapp3.1:${env:LD_LIBRARY_PATH}"
|
||||
}
|
||||
},
|
||||
"console": "internalConsole"
|
||||
},
|
||||
{
|
||||
@ -80,11 +60,6 @@
|
||||
],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build osu! (Debug)",
|
||||
"linux": {
|
||||
"env": {
|
||||
"LD_LIBRARY_PATH": "${workspaceRoot}/osu.Desktop/bin/Debug/netcoreapp3.1:${env:LD_LIBRARY_PATH}"
|
||||
}
|
||||
},
|
||||
"console": "internalConsole"
|
||||
},
|
||||
{
|
||||
@ -98,11 +73,6 @@
|
||||
],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build osu! (Release)",
|
||||
"linux": {
|
||||
"env": {
|
||||
"LD_LIBRARY_PATH": "${workspaceRoot}/osu.Desktop/bin/Release/netcoreapp3.1:${env:LD_LIBRARY_PATH}"
|
||||
}
|
||||
},
|
||||
"console": "internalConsole"
|
||||
},
|
||||
{
|
||||
@ -116,11 +86,6 @@
|
||||
],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build tournament tests (Debug)",
|
||||
"linux": {
|
||||
"env": {
|
||||
"LD_LIBRARY_PATH": "${workspaceRoot}/osu.Game.Tournament.Tests/bin/Debug/netcoreapp3.1:${env:LD_LIBRARY_PATH}"
|
||||
}
|
||||
},
|
||||
"console": "internalConsole"
|
||||
},
|
||||
{
|
||||
@ -134,11 +99,6 @@
|
||||
],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build tournament tests (Release)",
|
||||
"linux": {
|
||||
"env": {
|
||||
"LD_LIBRARY_PATH": "${workspaceRoot}/osu.Game.Tournament.Tests/bin/Debug/netcoreapp3.1:${env:LD_LIBRARY_PATH}"
|
||||
}
|
||||
},
|
||||
"console": "internalConsole"
|
||||
},
|
||||
{
|
||||
@ -169,4 +129,4 @@
|
||||
"externalConsole": false
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ If you are looking to install or test osu! without setting up a development envi
|
||||
|
||||
**Latest build:**
|
||||
|
||||
| [Windows (x64)](https://github.com/ppy/osu/releases/latest/download/install.exe) | [macOS 10.12+](https://github.com/ppy/osu/releases/latest/download/osu.app.zip) | [Linux (x64)](https://github.com/ppy/osu/releases/latest/download/osu.x86_64.AppImage) | [iOS(iOS 10+)](https://osu.ppy.sh/home/testflight) | [Android (5+)](https://github.com/ppy/osu/releases/latest/download/sh.ppy.osulazer.apk)
|
||||
| [Windows (x64)](https://github.com/ppy/osu/releases/latest/download/install.exe) | [macOS 10.12+](https://github.com/ppy/osu/releases/latest/download/osu.app.zip) | [Linux (x64)](https://github.com/ppy/osu/releases/latest/download/osu.AppImage) | [iOS(iOS 10+)](https://osu.ppy.sh/home/testflight) | [Android (5+)](https://github.com/ppy/osu/releases/latest/download/sh.ppy.osulazer.apk)
|
||||
| ------------- | ------------- | ------------- | ------------- | ------------- |
|
||||
|
||||
- When running on Windows 7 or 8.1, **[additional prerequisites](https://docs.microsoft.com/en-us/dotnet/core/install/dependencies?tabs=netcore31&pivots=os-windows)** may be required to correctly run .NET Core applications if your operating system is not up-to-date with the latest service packs.
|
||||
|
@ -25,7 +25,6 @@
|
||||
<DebugType>portable</DebugType>
|
||||
<Optimize>False</Optimize>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<EnableLLVM>false</EnableLLVM>
|
||||
<AndroidManagedSymbols>false</AndroidManagedSymbols>
|
||||
<AndroidUseSharedRuntime>true</AndroidUseSharedRuntime>
|
||||
<EmbedAssembliesIntoApk>false</EmbedAssembliesIntoApk>
|
||||
@ -34,7 +33,6 @@
|
||||
<DebugSymbols>false</DebugSymbols>
|
||||
<DebugType>None</DebugType>
|
||||
<Optimize>True</Optimize>
|
||||
<EnableLLVM>true</EnableLLVM>
|
||||
<AndroidManagedSymbols>false</AndroidManagedSymbols>
|
||||
<AndroidUseSharedRuntime>False</AndroidUseSharedRuntime>
|
||||
<EmbedAssembliesIntoApk>true</EmbedAssembliesIntoApk>
|
||||
@ -53,7 +51,7 @@
|
||||
<Reference Include="Java.Interop" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2020.221.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2020.221.0" />
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2020.304.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2020.310.0" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
@ -30,11 +30,6 @@ namespace osu.Android
|
||||
}
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
Add(new SimpleUpdateManager());
|
||||
}
|
||||
protected override UpdateManager CreateUpdateManager() => new SimpleUpdateManager();
|
||||
}
|
||||
}
|
@ -13,6 +13,7 @@
|
||||
<AssemblyName>osu.Android</AssemblyName>
|
||||
<AndroidManifest>Properties\AndroidManifest.xml</AndroidManifest>
|
||||
<AndroidSupportedAbis>armeabi-v7a;x86;arm64-v8a</AndroidSupportedAbis>
|
||||
<EnableLLVM>false</EnableLLVM> <!-- This currently causes random lockups during gameplay. https://github.com/mono/mono/issues/18973 -->
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<MandroidI18n>cjk;mideast;other;rare;west</MandroidI18n>
|
||||
@ -52,4 +53,4 @@
|
||||
<AndroidResource Include="Resources\drawable\lazer.png" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
|
||||
</Project>
|
||||
</Project>
|
||||
|
@ -47,20 +47,25 @@ namespace osu.Desktop
|
||||
return null;
|
||||
}
|
||||
|
||||
protected override UpdateManager CreateUpdateManager()
|
||||
{
|
||||
switch (RuntimeInfo.OS)
|
||||
{
|
||||
case RuntimeInfo.Platform.Windows:
|
||||
return new SquirrelUpdateManager();
|
||||
|
||||
default:
|
||||
return new SimpleUpdateManager();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
if (!noVersionOverlay)
|
||||
{
|
||||
LoadComponentAsync(versionManager = new VersionManager { Depth = int.MinValue }, Add);
|
||||
|
||||
if (RuntimeInfo.OS == RuntimeInfo.Platform.Windows)
|
||||
Add(new SquirrelUpdateManager());
|
||||
else
|
||||
Add(new SimpleUpdateManager());
|
||||
}
|
||||
|
||||
LoadComponentAsync(new DiscordRichPresence(), Add);
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,54 @@
|
||||
// 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.Catch.Mods;
|
||||
using osu.Game.Rulesets.Catch.Objects;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Tests.Visual;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Tests.Mods
|
||||
{
|
||||
public class TestSceneCatchModPerfect : ModPerfectTestScene
|
||||
{
|
||||
public TestSceneCatchModPerfect()
|
||||
: base(new CatchRuleset(), new CatchModPerfect())
|
||||
{
|
||||
}
|
||||
|
||||
[TestCase(false)]
|
||||
[TestCase(true)]
|
||||
public void TestBananaShower(bool shouldMiss) => CreateHitObjectTest(new HitObjectTestData(new BananaShower { StartTime = 1000, EndTime = 3000 }, false), shouldMiss);
|
||||
|
||||
[TestCase(false)]
|
||||
[TestCase(true)]
|
||||
public void TestFruit(bool shouldMiss) => CreateHitObjectTest(new HitObjectTestData(new Fruit { StartTime = 1000 }), shouldMiss);
|
||||
|
||||
[TestCase(false)]
|
||||
[TestCase(true)]
|
||||
public void TestJuiceStream(bool shouldMiss)
|
||||
{
|
||||
var stream = new JuiceStream
|
||||
{
|
||||
StartTime = 1000,
|
||||
Path = new SliderPath(PathType.Linear, new[]
|
||||
{
|
||||
Vector2.Zero,
|
||||
new Vector2(100, 0),
|
||||
})
|
||||
};
|
||||
|
||||
CreateHitObjectTest(new HitObjectTestData(stream), shouldMiss);
|
||||
}
|
||||
|
||||
// We only care about testing misses, hits are tested via JuiceStream
|
||||
[TestCase(true)]
|
||||
public void TestDroplet(bool shouldMiss) => CreateHitObjectTest(new HitObjectTestData(new Droplet { StartTime = 1000 }), shouldMiss);
|
||||
|
||||
// We only care about testing misses, hits are tested via JuiceStream
|
||||
[TestCase(true)]
|
||||
public void TestTinyDroplet(bool shouldMiss) => CreateHitObjectTest(new HitObjectTestData(new TinyDroplet { StartTime = 1000 }), shouldMiss);
|
||||
}
|
||||
}
|
After Width: | Height: | Size: 56 KiB |
After Width: | Height: | Size: 56 KiB |
After Width: | Height: | Size: 56 KiB |
After Width: | Height: | Size: 56 KiB |
After Width: | Height: | Size: 55 KiB |
After Width: | Height: | Size: 56 KiB |
Before Width: | Height: | Size: 130 KiB |
@ -7,7 +7,6 @@ using osu.Game.Rulesets.Catch.Objects;
|
||||
using osu.Game.Rulesets.Catch.UI;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Screens.Play;
|
||||
using osu.Game.Tests.Visual;
|
||||
using osuTK;
|
||||
|
||||
@ -51,7 +50,7 @@ namespace osu.Game.Rulesets.Catch.Tests
|
||||
return beatmap;
|
||||
}
|
||||
|
||||
protected override Player CreatePlayer(Ruleset ruleset)
|
||||
protected override TestPlayer CreatePlayer(Ruleset ruleset)
|
||||
{
|
||||
SelectedMods.Value = SelectedMods.Value.Concat(new[] { ruleset.GetAutoplayMod() }).ToArray();
|
||||
return base.CreatePlayer(ruleset);
|
||||
|
@ -29,6 +29,12 @@ namespace osu.Game.Rulesets.Catch.Tests
|
||||
{
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestBananaShower()
|
||||
{
|
||||
AddUntilStep("player is done", () => !Player.ValidForResume);
|
||||
}
|
||||
|
||||
protected override IBeatmap CreateBeatmap(RulesetInfo ruleset)
|
||||
{
|
||||
var beatmap = new Beatmap
|
||||
@ -40,7 +46,7 @@ namespace osu.Game.Rulesets.Catch.Tests
|
||||
}
|
||||
};
|
||||
|
||||
beatmap.HitObjects.Add(new BananaShower { StartTime = 200, Duration = 5000, NewCombo = true });
|
||||
beatmap.HitObjects.Add(new BananaShower { StartTime = 200, Duration = 3000, NewCombo = true });
|
||||
|
||||
return beatmap;
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ namespace osu.Game.Rulesets.Catch.Tests
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(CatcherArea),
|
||||
typeof(CatcherSprite)
|
||||
};
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
|
@ -42,6 +42,9 @@ namespace osu.Game.Rulesets.Catch.Tests
|
||||
AddStep("show droplet", () => SetContents(createDrawableDroplet));
|
||||
|
||||
AddStep("show tiny droplet", () => SetContents(createDrawableTinyDroplet));
|
||||
|
||||
foreach (FruitVisualRepresentation rep in Enum.GetValues(typeof(FruitVisualRepresentation)))
|
||||
AddStep($"show hyperdash {rep}", () => SetContents(() => createDrawable(rep, true)));
|
||||
}
|
||||
|
||||
private Drawable createDrawableTinyDroplet()
|
||||
@ -82,9 +85,13 @@ namespace osu.Game.Rulesets.Catch.Tests
|
||||
};
|
||||
}
|
||||
|
||||
private Drawable createDrawable(FruitVisualRepresentation rep)
|
||||
private Drawable createDrawable(FruitVisualRepresentation rep, bool hyperdash = false)
|
||||
{
|
||||
Fruit fruit = new TestCatchFruit(rep) { Scale = 1.5f };
|
||||
Fruit fruit = new TestCatchFruit(rep)
|
||||
{
|
||||
Scale = 1.5f,
|
||||
HyperDashTarget = hyperdash ? new Banana() : null
|
||||
};
|
||||
|
||||
return new DrawableFruit(fruit)
|
||||
{
|
||||
|
@ -1,9 +1,13 @@
|
||||
// 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 NUnit.Framework;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Catch.Objects;
|
||||
using osu.Game.Rulesets.Catch.UI;
|
||||
using osu.Game.Tests.Visual;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Tests
|
||||
@ -22,8 +26,17 @@ namespace osu.Game.Rulesets.Catch.Tests
|
||||
public void TestHyperDash()
|
||||
{
|
||||
AddAssert("First note is hyperdash", () => Beatmap.Value.Beatmap.HitObjects[0] is Fruit f && f.HyperDash);
|
||||
AddUntilStep("wait for left hyperdash", () => getCatcher().Scale.X < 0 && getCatcher().HyperDashing);
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
AddUntilStep("wait for right hyperdash", () => getCatcher().Scale.X > 0 && getCatcher().HyperDashing);
|
||||
AddUntilStep("wait for left hyperdash", () => getCatcher().Scale.X < 0 && getCatcher().HyperDashing);
|
||||
}
|
||||
}
|
||||
|
||||
private CatcherArea.Catcher getCatcher() => Player.ChildrenOfType<CatcherArea>().First().MovableCatcher;
|
||||
|
||||
protected override IBeatmap CreateBeatmap(RulesetInfo ruleset)
|
||||
{
|
||||
var beatmap = new Beatmap
|
||||
@ -35,17 +48,40 @@ namespace osu.Game.Rulesets.Catch.Tests
|
||||
}
|
||||
};
|
||||
|
||||
// Should produce a hyper-dash
|
||||
beatmap.HitObjects.Add(new Fruit { StartTime = 816, X = 308 / 512f, NewCombo = true });
|
||||
beatmap.HitObjects.Add(new Fruit { StartTime = 1008, X = 56 / 512f, });
|
||||
// Should produce a hyper-dash (edge case test)
|
||||
beatmap.HitObjects.Add(new Fruit { StartTime = 1816, X = 308 / 512f, NewCombo = true });
|
||||
beatmap.HitObjects.Add(new JuiceStream { StartTime = 2008, X = 56 / 512f, });
|
||||
|
||||
for (int i = 0; i < 512; i++)
|
||||
{
|
||||
if (i % 5 < 3)
|
||||
beatmap.HitObjects.Add(new Fruit { X = i % 10 < 5 ? 0.02f : 0.98f, StartTime = 2000 + i * 100, NewCombo = i % 8 == 0 });
|
||||
}
|
||||
double startTime = 3000;
|
||||
|
||||
const float left_x = 0.02f;
|
||||
const float right_x = 0.98f;
|
||||
|
||||
createObjects(() => new Fruit(), left_x);
|
||||
createObjects(() => new JuiceStream(), right_x);
|
||||
createObjects(() => new JuiceStream(), left_x);
|
||||
createObjects(() => new Fruit(), right_x);
|
||||
createObjects(() => new Fruit(), left_x);
|
||||
createObjects(() => new Fruit(), right_x);
|
||||
createObjects(() => new JuiceStream(), left_x);
|
||||
|
||||
return beatmap;
|
||||
|
||||
void createObjects(Func<CatchHitObject> createObject, float x)
|
||||
{
|
||||
const float spacing = 140;
|
||||
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
var hitObject = createObject();
|
||||
hitObject.X = x;
|
||||
hitObject.StartTime = startTime + i * spacing;
|
||||
|
||||
beatmap.HitObjects.Add(hitObject);
|
||||
}
|
||||
|
||||
startTime += 700;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
56
osu.Game.Rulesets.Catch.Tests/TestSceneJuiceStream.cs
Normal file
@ -0,0 +1,56 @@
|
||||
// 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.Rulesets.Catch.Objects;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Tests.Visual;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Tests
|
||||
{
|
||||
public class TestSceneJuiceStream : PlayerTestScene
|
||||
{
|
||||
public TestSceneJuiceStream()
|
||||
: base(new CatchRuleset())
|
||||
{
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestJuiceStreamEndingCombo()
|
||||
{
|
||||
AddUntilStep("player is done", () => !Player.ValidForResume);
|
||||
}
|
||||
|
||||
protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) => new Beatmap
|
||||
{
|
||||
BeatmapInfo = new BeatmapInfo
|
||||
{
|
||||
BaseDifficulty = new BeatmapDifficulty { CircleSize = 5, SliderMultiplier = 2 },
|
||||
Ruleset = ruleset
|
||||
},
|
||||
HitObjects = new List<HitObject>
|
||||
{
|
||||
new JuiceStream
|
||||
{
|
||||
X = 0.5f,
|
||||
Path = new SliderPath(PathType.Linear, new[]
|
||||
{
|
||||
Vector2.Zero,
|
||||
new Vector2(0, 100)
|
||||
}),
|
||||
StartTime = 200
|
||||
},
|
||||
new Banana
|
||||
{
|
||||
X = 0.5f,
|
||||
StartTime = 1000,
|
||||
NewCombo = true
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -10,6 +10,7 @@ namespace osu.Game.Rulesets.Catch
|
||||
FruitGrapes,
|
||||
FruitOrange,
|
||||
FruitPear,
|
||||
Droplet
|
||||
Droplet,
|
||||
CatcherIdle
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,17 @@
|
||||
// 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 osu.Game.Rulesets.Catch.Judgements;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Mods
|
||||
{
|
||||
public class CatchModPerfect : ModPerfect
|
||||
{
|
||||
protected override bool FailCondition(HealthProcessor healthProcessor, JudgementResult result)
|
||||
=> !(result.Judgement is CatchBananaJudgement)
|
||||
&& base.FailCondition(healthProcessor, result);
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
// 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 osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Objects
|
||||
@ -11,6 +12,8 @@ namespace osu.Game.Rulesets.Catch.Objects
|
||||
|
||||
public override bool LastInCombo => true;
|
||||
|
||||
public override Judgement CreateJudgement() => new IgnoreJudgement();
|
||||
|
||||
protected override void CreateNestedHitObjects()
|
||||
{
|
||||
base.CreateNestedHitObjects();
|
||||
|
@ -7,9 +7,7 @@ using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Rulesets.Catch.Objects.Drawables.Pieces;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Objects.Drawables
|
||||
@ -64,15 +62,24 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables
|
||||
|
||||
if (hitObject.HyperDash)
|
||||
{
|
||||
AddInternal(new Pulp
|
||||
AddInternal(new Circle
|
||||
{
|
||||
RelativePositionAxes = Axes.Both,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
AccentColour = { Value = Color4.Red },
|
||||
Blending = BlendingParameters.Additive,
|
||||
Alpha = 0.5f,
|
||||
Scale = new Vector2(1.333f)
|
||||
BorderColour = Color4.Red,
|
||||
BorderThickness = 12f * RADIUS_ADJUST,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
AlwaysPresent = true,
|
||||
Alpha = 0.3f,
|
||||
Blending = BlendingParameters.Additive,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4.Red,
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ using osu.Game.Audio;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Rulesets.Catch.UI;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
|
||||
@ -19,6 +20,8 @@ namespace osu.Game.Rulesets.Catch.Objects
|
||||
/// </summary>
|
||||
private const float base_scoring_distance = 100;
|
||||
|
||||
public override Judgement CreateJudgement() => new IgnoreJudgement();
|
||||
|
||||
public int RepeatCount { get; set; }
|
||||
|
||||
public double Velocity;
|
||||
|
@ -44,6 +44,10 @@ namespace osu.Game.Rulesets.Catch.Skinning
|
||||
return new LegacyFruitPiece("fruit-drop") { Scale = new Vector2(0.8f) };
|
||||
|
||||
break;
|
||||
|
||||
case CatchSkinComponents.CatcherIdle:
|
||||
return this.GetAnimation("fruit-catcher-idle", true, true, true) ??
|
||||
this.GetAnimation("fruit-ryuuta", true, true, true);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
@ -9,6 +9,7 @@ using osu.Framework.Graphics.Sprites;
|
||||
using osu.Game.Rulesets.Catch.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Skinning;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Skinning
|
||||
@ -49,6 +50,23 @@ namespace osu.Game.Rulesets.Catch.Skinning
|
||||
Origin = Anchor.Centre,
|
||||
},
|
||||
};
|
||||
|
||||
if (drawableCatchObject.HitObject.HyperDash)
|
||||
{
|
||||
var hyperDash = new Sprite
|
||||
{
|
||||
Texture = skin.GetTexture(lookupName),
|
||||
Colour = Color4.Red,
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Blending = BlendingParameters.Additive,
|
||||
Depth = 1,
|
||||
Alpha = 0.7f,
|
||||
Scale = new Vector2(1.2f)
|
||||
};
|
||||
|
||||
AddInternal(hyperDash);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
|
@ -50,6 +50,9 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
|
||||
public void OnResult(DrawableCatchHitObject fruit, JudgementResult result)
|
||||
{
|
||||
if (result.Judgement is IgnoreJudgement)
|
||||
return;
|
||||
|
||||
void runAfterLoaded(Action action)
|
||||
{
|
||||
if (lastPlateableFruit == null)
|
||||
@ -89,7 +92,7 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
|
||||
if (fruit.HitObject.LastInCombo)
|
||||
{
|
||||
if (((CatchJudgement)result.Judgement).ShouldExplodeFor(result))
|
||||
if (result.Judgement is CatchJudgement catchJudgement && catchJudgement.ShouldExplodeFor(result))
|
||||
runAfterLoaded(() => MovableCatcher.Explode());
|
||||
else
|
||||
MovableCatcher.Drop();
|
||||
@ -152,7 +155,10 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.BottomCentre,
|
||||
},
|
||||
createCatcherSprite(),
|
||||
createCatcherSprite().With(c =>
|
||||
{
|
||||
c.Anchor = Anchor.TopCentre;
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
@ -202,12 +208,11 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
var additive = createCatcherSprite();
|
||||
|
||||
additive.Anchor = Anchor;
|
||||
additive.OriginPosition += new Vector2(DrawWidth / 2, 0); // also temporary to align sprite correctly.
|
||||
additive.Position = Position;
|
||||
additive.Scale = Scale;
|
||||
additive.Colour = HyperDashing ? Color4.Red : Color4.White;
|
||||
additive.RelativePositionAxes = RelativePositionAxes;
|
||||
additive.Blending = BlendingParameters.Additive;
|
||||
additive.RelativePositionAxes = RelativePositionAxes;
|
||||
additive.Position = Position;
|
||||
|
||||
AdditiveTarget.Add(additive);
|
||||
|
||||
@ -267,6 +272,10 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
catchObjectPosition >= catcherPosition - halfCatchWidth &&
|
||||
catchObjectPosition <= catcherPosition + halfCatchWidth;
|
||||
|
||||
// only update hyperdash state if we are catching a fruit.
|
||||
// exceptions are Droplets and JuiceStreams.
|
||||
if (!(fruit is Fruit)) return validCatch;
|
||||
|
||||
if (validCatch && fruit.HyperDash)
|
||||
{
|
||||
var target = fruit.HyperDashTarget;
|
||||
|
@ -3,31 +3,35 @@
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Game.Skinning;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.UI
|
||||
{
|
||||
public class CatcherSprite : CompositeDrawable
|
||||
public class CatcherSprite : SkinnableDrawable
|
||||
{
|
||||
protected override bool ApplySizeRestrictionsToDefault => true;
|
||||
|
||||
public CatcherSprite()
|
||||
: base(new CatchSkinComponent(CatchSkinComponents.CatcherIdle), _ =>
|
||||
new DefaultCatcherSprite(), confineMode: ConfineMode.ScaleDownToFit)
|
||||
{
|
||||
RelativeSizeAxes = Axes.None;
|
||||
Size = new Vector2(CatcherArea.CATCHER_SIZE);
|
||||
|
||||
// Sets the origin roughly to the centre of the catcher's plate to allow for correct scaling.
|
||||
OriginPosition = new Vector2(-0.02f, 0.06f) * CatcherArea.CATCHER_SIZE;
|
||||
OriginPosition = new Vector2(0.5f, 0.06f) * CatcherArea.CATCHER_SIZE;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
private class DefaultCatcherSprite : Sprite
|
||||
{
|
||||
InternalChild = new SkinnableSprite("Gameplay/catch/fruit-catcher-idle", confineMode: ConfineMode.ScaleDownToFit)
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(TextureStore textures)
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
};
|
||||
Texture = textures.Get("Gameplay/catch/fruit-catcher-idle");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,26 @@
|
||||
// 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.Mania.Mods;
|
||||
using osu.Game.Rulesets.Mania.Objects;
|
||||
using osu.Game.Tests.Visual;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Tests.Mods
|
||||
{
|
||||
public class TestSceneManiaModPerfect : ModPerfectTestScene
|
||||
{
|
||||
public TestSceneManiaModPerfect()
|
||||
: base(new ManiaRuleset(), new ManiaModPerfect())
|
||||
{
|
||||
}
|
||||
|
||||
[TestCase(false)]
|
||||
[TestCase(true)]
|
||||
public void TestNote(bool shouldMiss) => CreateHitObjectTest(new HitObjectTestData(new Note { StartTime = 1000 }), shouldMiss);
|
||||
|
||||
[TestCase(false)]
|
||||
[TestCase(true)]
|
||||
public void TestHoldNote(bool shouldMiss) => CreateHitObjectTest(new HitObjectTestData(new HoldNote { StartTime = 1000, EndTime = 3000 }), shouldMiss);
|
||||
}
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
// 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 osu.Game.Rulesets.Scoring;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Judgements
|
||||
{
|
||||
public class HoldNoteJudgement : ManiaJudgement
|
||||
{
|
||||
public override bool AffectsCombo => false;
|
||||
|
||||
protected override int NumericResultFor(HitResult result) => 0;
|
||||
}
|
||||
}
|
@ -3,8 +3,8 @@
|
||||
|
||||
using System;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Caching;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Layout;
|
||||
using osu.Game.Rulesets.Mania.Objects;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osuTK;
|
||||
@ -22,21 +22,13 @@ namespace osu.Game.Rulesets.Mania.Mods
|
||||
|
||||
private class ManiaFlashlight : Flashlight
|
||||
{
|
||||
private readonly Cached flashlightProperties = new Cached();
|
||||
private readonly LayoutValue flashlightProperties = new LayoutValue(Invalidation.DrawSize);
|
||||
|
||||
public ManiaFlashlight()
|
||||
{
|
||||
FlashlightSize = new Vector2(0, default_flashlight_size);
|
||||
}
|
||||
|
||||
public override bool Invalidate(Invalidation invalidation = Invalidation.All, Drawable source = null, bool shallPropagate = true)
|
||||
{
|
||||
if ((invalidation & Invalidation.DrawSize) > 0)
|
||||
{
|
||||
flashlightProperties.Invalidate();
|
||||
}
|
||||
|
||||
return base.Invalidate(invalidation, source, shallPropagate);
|
||||
AddLayout(flashlightProperties);
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
|
@ -1,6 +1,7 @@
|
||||
// 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 osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Objects
|
||||
@ -8,5 +9,7 @@ namespace osu.Game.Rulesets.Mania.Objects
|
||||
public class BarLine : ManiaHitObject, IBarLine
|
||||
{
|
||||
public bool Major { get; set; }
|
||||
|
||||
public override Judgement CreateJudgement() => new IgnoreJudgement();
|
||||
}
|
||||
}
|
||||
|
@ -71,8 +71,6 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
{
|
||||
}
|
||||
|
||||
protected override void UpdateStateTransforms(ArmedState state)
|
||||
{
|
||||
}
|
||||
protected override void UpdateStateTransforms(ArmedState state) => this.FadeOut(150);
|
||||
}
|
||||
}
|
||||
|
@ -2,13 +2,13 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using osu.Framework.Caching;
|
||||
using osuTK.Graphics;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Effects;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Layout;
|
||||
using osu.Game.Graphics;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
|
||||
@ -65,6 +65,8 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
AddLayout(subtractionCache);
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
@ -100,15 +102,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
|
||||
}
|
||||
}
|
||||
|
||||
private readonly Cached subtractionCache = new Cached();
|
||||
|
||||
public override bool Invalidate(Invalidation invalidation = Invalidation.All, Drawable source = null, bool shallPropagate = true)
|
||||
{
|
||||
if ((invalidation & Invalidation.DrawSize) > 0)
|
||||
subtractionCache.Invalidate();
|
||||
|
||||
return base.Invalidate(invalidation, source, shallPropagate);
|
||||
}
|
||||
private readonly LayoutValue subtractionCache = new LayoutValue(Invalidation.DrawSize);
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
|
@ -4,7 +4,6 @@
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Mania.Judgements;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
|
||||
@ -103,7 +102,7 @@ namespace osu.Game.Rulesets.Mania.Objects
|
||||
}
|
||||
}
|
||||
|
||||
public override Judgement CreateJudgement() => new HoldNoteJudgement();
|
||||
public override Judgement CreateJudgement() => new IgnoreJudgement();
|
||||
|
||||
protected override HitWindows CreateHitWindows() => HitWindows.Empty;
|
||||
}
|
||||
|
@ -115,9 +115,8 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.Centre,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Y = HIT_TARGET_POSITION + 150,
|
||||
BypassAutoSizeAxes = Axes.Both
|
||||
},
|
||||
topLevelContainer = new Container { RelativeSizeAxes = Axes.Both }
|
||||
}
|
||||
|
@ -0,0 +1,86 @@
|
||||
// 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.Framework.Graphics.Containers;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Rulesets.Osu.Mods;
|
||||
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||
using osu.Game.Tests.Visual;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Tests.Mods
|
||||
{
|
||||
public class TestSceneOsuModDifficultyAdjust : ModTestScene
|
||||
{
|
||||
public TestSceneOsuModDifficultyAdjust()
|
||||
: base(new OsuRuleset())
|
||||
{
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestNoAdjustment() => CreateModTest(new ModTestData
|
||||
{
|
||||
Mod = new OsuModDifficultyAdjust(),
|
||||
Autoplay = true,
|
||||
PassCondition = checkSomeHit
|
||||
});
|
||||
|
||||
[Test]
|
||||
public void TestCircleSize1() => CreateModTest(new ModTestData
|
||||
{
|
||||
Mod = new OsuModDifficultyAdjust { CircleSize = { Value = 1 } },
|
||||
Autoplay = true,
|
||||
PassCondition = () => checkSomeHit() && checkObjectsScale(0.78f)
|
||||
});
|
||||
|
||||
[Test]
|
||||
public void TestCircleSize10() => CreateModTest(new ModTestData
|
||||
{
|
||||
Mod = new OsuModDifficultyAdjust { CircleSize = { Value = 10 } },
|
||||
Autoplay = true,
|
||||
PassCondition = () => checkSomeHit() && checkObjectsScale(0.15f)
|
||||
});
|
||||
|
||||
[Test]
|
||||
public void TestApproachRate1() => CreateModTest(new ModTestData
|
||||
{
|
||||
Mod = new OsuModDifficultyAdjust { ApproachRate = { Value = 1 } },
|
||||
Autoplay = true,
|
||||
PassCondition = () => checkSomeHit() && checkObjectsPreempt(1680)
|
||||
});
|
||||
|
||||
[Test]
|
||||
public void TestApproachRate10() => CreateModTest(new ModTestData
|
||||
{
|
||||
Mod = new OsuModDifficultyAdjust { ApproachRate = { Value = 10 } },
|
||||
Autoplay = true,
|
||||
PassCondition = () => checkSomeHit() && checkObjectsPreempt(450)
|
||||
});
|
||||
|
||||
private bool checkObjectsPreempt(double target)
|
||||
{
|
||||
var objects = Player.ChildrenOfType<DrawableHitCircle>();
|
||||
if (!objects.Any())
|
||||
return false;
|
||||
|
||||
return objects.All(o => o.HitObject.TimePreempt == target);
|
||||
}
|
||||
|
||||
private bool checkObjectsScale(float target)
|
||||
{
|
||||
var objects = Player.ChildrenOfType<DrawableHitCircle>();
|
||||
if (!objects.Any())
|
||||
return false;
|
||||
|
||||
return objects.All(o => Precision.AlmostEquals(o.ChildrenOfType<ShakeContainer>().First().Children.OfType<Container>().Single().Scale.X, target));
|
||||
}
|
||||
|
||||
private bool checkSomeHit()
|
||||
{
|
||||
return Player.ScoreProcessor.JudgedHits >= 2;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
// 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.Framework.Utils;
|
||||
using osu.Game.Rulesets.Osu.Mods;
|
||||
using osu.Game.Tests.Visual;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Tests.Mods
|
||||
{
|
||||
public class TestSceneOsuModDoubleTime : ModTestScene
|
||||
{
|
||||
public TestSceneOsuModDoubleTime()
|
||||
: base(new OsuRuleset())
|
||||
{
|
||||
}
|
||||
|
||||
[TestCase(0.5)]
|
||||
[TestCase(1.01)]
|
||||
[TestCase(1.5)]
|
||||
[TestCase(2)]
|
||||
[TestCase(5)]
|
||||
public void TestSpeedChangeCustomisation(double rate)
|
||||
{
|
||||
var mod = new OsuModDoubleTime { SpeedChange = { Value = rate } };
|
||||
|
||||
CreateModTest(new ModTestData
|
||||
{
|
||||
Mod = mod,
|
||||
PassCondition = () => Player.ScoreProcessor.JudgedHits >= 2 &&
|
||||
Precision.AlmostEquals(Player.GameplayClockContainer.GameplayClock.Rate, mod.SpeedChange.Value)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
52
osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModPerfect.cs
Normal file
@ -0,0 +1,52 @@
|
||||
// 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.Objects;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Rulesets.Osu.Mods;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
using osu.Game.Tests.Visual;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Tests.Mods
|
||||
{
|
||||
public class TestSceneOsuModPerfect : ModPerfectTestScene
|
||||
{
|
||||
public TestSceneOsuModPerfect()
|
||||
: base(new OsuRuleset(), new OsuModPerfect())
|
||||
{
|
||||
}
|
||||
|
||||
[TestCase(false)]
|
||||
[TestCase(true)]
|
||||
public void TestHitCircle(bool shouldMiss) => CreateHitObjectTest(new HitObjectTestData(new HitCircle { StartTime = 1000 }), shouldMiss);
|
||||
|
||||
[TestCase(false)]
|
||||
[TestCase(true)]
|
||||
public void TestSlider(bool shouldMiss)
|
||||
{
|
||||
var slider = new Slider
|
||||
{
|
||||
StartTime = 1000,
|
||||
Path = new SliderPath(PathType.Linear, new[] { Vector2.Zero, new Vector2(100, 0), })
|
||||
};
|
||||
|
||||
CreateHitObjectTest(new HitObjectTestData(slider), shouldMiss);
|
||||
}
|
||||
|
||||
[TestCase(false)]
|
||||
[TestCase(true)]
|
||||
public void TestSpinner(bool shouldMiss)
|
||||
{
|
||||
var spinner = new Spinner
|
||||
{
|
||||
StartTime = 1000,
|
||||
EndTime = 3000,
|
||||
Position = new Vector2(256, 192)
|
||||
};
|
||||
|
||||
CreateHitObjectTest(new HitObjectTestData(spinner), shouldMiss);
|
||||
}
|
||||
}
|
||||
}
|
@ -2,9 +2,12 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
@ -114,6 +117,22 @@ namespace osu.Game.Rulesets.Osu.Tests
|
||||
assertGroups();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestStackedObjects()
|
||||
{
|
||||
addObjectsStep(() => new OsuHitObject[]
|
||||
{
|
||||
new HitCircle { Position = new Vector2(300, 100) },
|
||||
new HitCircle
|
||||
{
|
||||
Position = new Vector2(300, 300),
|
||||
StackHeight = 20
|
||||
},
|
||||
});
|
||||
|
||||
assertDirections();
|
||||
}
|
||||
|
||||
private void addMultipleObjectsStep() => addObjectsStep(() => new OsuHitObject[]
|
||||
{
|
||||
new HitCircle { Position = new Vector2(100, 100) },
|
||||
@ -207,6 +226,33 @@ namespace osu.Game.Rulesets.Osu.Tests
|
||||
});
|
||||
}
|
||||
|
||||
private void assertDirections()
|
||||
{
|
||||
AddAssert("group directions are correct", () =>
|
||||
{
|
||||
for (int i = 0; i < hitObjectContainer.Count; i++)
|
||||
{
|
||||
DrawableOsuHitObject expectedStart = getObject(i);
|
||||
DrawableOsuHitObject expectedEnd = i < hitObjectContainer.Count - 1 ? getObject(i + 1) : null;
|
||||
|
||||
if (expectedEnd == null)
|
||||
continue;
|
||||
|
||||
var points = getGroup(i).ChildrenOfType<FollowPoint>().ToArray();
|
||||
if (points.Length == 0)
|
||||
continue;
|
||||
|
||||
float expectedDirection = MathF.Atan2(expectedStart.Position.Y - expectedEnd.Position.Y, expectedStart.Position.X - expectedEnd.Position.X);
|
||||
float realDirection = MathF.Atan2(expectedStart.Position.Y - points[^1].Position.Y, expectedStart.Position.X - points[^1].Position.X);
|
||||
|
||||
if (!Precision.AlmostEquals(expectedDirection, realDirection))
|
||||
throw new AssertionException($"Expected group {i} in direction {expectedDirection}, but was {realDirection}.");
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private DrawableOsuHitObject getObject(int index) => hitObjectContainer[index];
|
||||
|
||||
private FollowPointConnection getGroup(int index) => followPointRenderer.Connections[index];
|
||||
|
108
osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleArea.cs
Normal file
@ -0,0 +1,108 @@
|
||||
// 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 NUnit.Framework;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Skinning;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Tests
|
||||
{
|
||||
public class TestSceneHitCircleArea : ManualInputManagerTestScene
|
||||
{
|
||||
private HitCircle hitCircle;
|
||||
private DrawableHitCircle drawableHitCircle;
|
||||
private DrawableHitCircle.HitReceptor hitAreaReceptor => drawableHitCircle.HitArea;
|
||||
|
||||
[SetUp]
|
||||
public new void SetUp()
|
||||
{
|
||||
base.SetUp();
|
||||
|
||||
Schedule(() =>
|
||||
{
|
||||
hitCircle = new HitCircle
|
||||
{
|
||||
Position = new Vector2(100, 100),
|
||||
StartTime = Time.Current + 500
|
||||
};
|
||||
|
||||
hitCircle.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
|
||||
|
||||
Child = new SkinProvidingContainer(new DefaultSkin())
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Child = drawableHitCircle = new DrawableHitCircle(hitCircle)
|
||||
{
|
||||
Size = new Vector2(100)
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestCircleHitCentre()
|
||||
{
|
||||
AddStep("move mouse to centre", () => InputManager.MoveMouseTo(hitAreaReceptor.ScreenSpaceDrawQuad.Centre));
|
||||
scheduleHit();
|
||||
|
||||
AddAssert("hit registered", () => hitAreaReceptor.HitAction == OsuAction.LeftButton);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestCircleHitLeftEdge()
|
||||
{
|
||||
AddStep("move mouse to left edge", () =>
|
||||
{
|
||||
var drawQuad = hitAreaReceptor.ScreenSpaceDrawQuad;
|
||||
var mousePosition = new Vector2(drawQuad.TopLeft.X, drawQuad.Centre.Y);
|
||||
|
||||
InputManager.MoveMouseTo(mousePosition);
|
||||
});
|
||||
scheduleHit();
|
||||
|
||||
AddAssert("hit registered", () => hitAreaReceptor.HitAction == OsuAction.LeftButton);
|
||||
}
|
||||
|
||||
[TestCase(0.95f, OsuAction.LeftButton)]
|
||||
[TestCase(1.05f, null)]
|
||||
public void TestHitsCloseToEdge(float relativeDistanceFromCentre, OsuAction? expectedAction)
|
||||
{
|
||||
AddStep("move mouse to top left circle edge", () =>
|
||||
{
|
||||
var drawQuad = hitAreaReceptor.ScreenSpaceDrawQuad;
|
||||
// sqrt(2) / 2 = sin(45deg) = cos(45deg)
|
||||
// draw width halved to get radius
|
||||
float correction = relativeDistanceFromCentre * (float)Math.Sqrt(2) / 2 * (drawQuad.Width / 2);
|
||||
var mousePosition = new Vector2(drawQuad.Centre.X - correction, drawQuad.Centre.Y - correction);
|
||||
|
||||
InputManager.MoveMouseTo(mousePosition);
|
||||
});
|
||||
scheduleHit();
|
||||
|
||||
AddAssert($"hit {(expectedAction == null ? "not " : string.Empty)}registered", () => hitAreaReceptor.HitAction == expectedAction);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestCircleMissBoundingBoxCorner()
|
||||
{
|
||||
AddStep("move mouse to top left corner of bounding box", () => InputManager.MoveMouseTo(hitAreaReceptor.ScreenSpaceDrawQuad.TopLeft));
|
||||
scheduleHit();
|
||||
|
||||
AddAssert("hit not registered", () => hitAreaReceptor.HitAction == null);
|
||||
}
|
||||
|
||||
private void scheduleHit() => AddStep("schedule action", () =>
|
||||
{
|
||||
var delay = hitCircle.StartTime - hitCircle.HitWindows.WindowFor(HitResult.Great) - Time.Current;
|
||||
Scheduler.AddDelayed(() => hitAreaReceptor.OnPressed(OsuAction.LeftButton), delay);
|
||||
});
|
||||
}
|
||||
}
|
101
osu.Game.Rulesets.Osu.Tests/TestSceneMissHitWindowJudgements.cs
Normal file
@ -0,0 +1,101 @@
|
||||
// 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.Beatmaps;
|
||||
using osu.Game.Replays;
|
||||
using osu.Game.Rulesets.Osu.Beatmaps;
|
||||
using osu.Game.Rulesets.Osu.Mods;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
using osu.Game.Rulesets.Osu.Replays;
|
||||
using osu.Game.Rulesets.Osu.Scoring;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Scoring;
|
||||
using osu.Game.Tests.Visual;
|
||||
using osu.Game.Users;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Tests
|
||||
{
|
||||
public class TestSceneMissHitWindowJudgements : ModTestScene
|
||||
{
|
||||
public TestSceneMissHitWindowJudgements()
|
||||
: base(new OsuRuleset())
|
||||
{
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestMissViaEarlyHit()
|
||||
{
|
||||
var beatmap = new Beatmap
|
||||
{
|
||||
HitObjects = { new HitCircle { Position = new Vector2(256, 192) } }
|
||||
};
|
||||
|
||||
var hitWindows = new OsuHitWindows();
|
||||
hitWindows.SetDifficulty(beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty);
|
||||
|
||||
CreateModTest(new ModTestData
|
||||
{
|
||||
Autoplay = false,
|
||||
Mod = new TestAutoMod(),
|
||||
Beatmap = new Beatmap
|
||||
{
|
||||
HitObjects = { new HitCircle { Position = new Vector2(256, 192) } }
|
||||
},
|
||||
PassCondition = () => Player.Results.Count > 0 && Player.Results[0].TimeOffset < -hitWindows.WindowFor(HitResult.Meh) && Player.Results[0].Type == HitResult.Miss
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestMissViaNotHitting()
|
||||
{
|
||||
var beatmap = new Beatmap
|
||||
{
|
||||
HitObjects = { new HitCircle { Position = new Vector2(256, 192) } }
|
||||
};
|
||||
|
||||
var hitWindows = new OsuHitWindows();
|
||||
hitWindows.SetDifficulty(beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty);
|
||||
|
||||
CreateModTest(new ModTestData
|
||||
{
|
||||
Autoplay = false,
|
||||
Beatmap = beatmap,
|
||||
PassCondition = () => Player.Results.Count > 0 && Player.Results[0].TimeOffset >= hitWindows.WindowFor(HitResult.Meh) && Player.Results[0].Type == HitResult.Miss
|
||||
});
|
||||
}
|
||||
|
||||
private class TestAutoMod : OsuModAutoplay
|
||||
{
|
||||
public override Score CreateReplayScore(IBeatmap beatmap) => new Score
|
||||
{
|
||||
ScoreInfo = new ScoreInfo { User = new User { Username = "Autoplay" } },
|
||||
Replay = new MissingAutoGenerator(beatmap).Generate()
|
||||
};
|
||||
}
|
||||
|
||||
private class MissingAutoGenerator : OsuAutoGeneratorBase
|
||||
{
|
||||
public new OsuBeatmap Beatmap => (OsuBeatmap)base.Beatmap;
|
||||
|
||||
public MissingAutoGenerator(IBeatmap beatmap)
|
||||
: base(beatmap)
|
||||
{
|
||||
}
|
||||
|
||||
public override Replay Generate()
|
||||
{
|
||||
AddFrameToReplay(new OsuReplayFrame(-100000, new Vector2(256, 500)));
|
||||
AddFrameToReplay(new OsuReplayFrame(Beatmap.HitObjects[0].StartTime - 1500, new Vector2(256, 500)));
|
||||
AddFrameToReplay(new OsuReplayFrame(Beatmap.HitObjects[0].StartTime - 1500, new Vector2(256, 500)));
|
||||
|
||||
AddFrameToReplay(new OsuReplayFrame(Beatmap.HitObjects[0].StartTime - 450, Beatmap.HitObjects[0].StackedPosition));
|
||||
AddFrameToReplay(new OsuReplayFrame(Beatmap.HitObjects[0].StartTime - 350, Beatmap.HitObjects[0].StackedPosition, OsuAction.LeftButton));
|
||||
AddFrameToReplay(new OsuReplayFrame(Beatmap.HitObjects[0].StartTime - 325, Beatmap.HitObjects[0].StackedPosition));
|
||||
|
||||
return Replay;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -3,13 +3,13 @@
|
||||
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Osu.Mods;
|
||||
using osu.Game.Screens.Play;
|
||||
using osu.Game.Tests.Visual;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Tests
|
||||
{
|
||||
public class TestSceneOsuFlashlight : TestSceneOsuPlayer
|
||||
{
|
||||
protected override Player CreatePlayer(Ruleset ruleset)
|
||||
protected override TestPlayer CreatePlayer(Ruleset ruleset)
|
||||
{
|
||||
SelectedMods.Value = new Mod[] { new OsuModAutoplay(), new OsuModFlashlight(), };
|
||||
|
||||
|
@ -18,7 +18,6 @@ using osu.Game.Configuration;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||
using osu.Game.Screens.Play;
|
||||
using osu.Game.Skinning;
|
||||
using osu.Game.Storyboards;
|
||||
using osu.Game.Tests.Visual;
|
||||
@ -56,7 +55,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
||||
private void checkNextHitObject(string skin) =>
|
||||
AddUntilStep($"check skin from {skin}", () =>
|
||||
{
|
||||
var firstObject = ((TestPlayer)Player).DrawableRuleset.Playfield.HitObjectContainer.AliveObjects.OfType<DrawableHitCircle>().FirstOrDefault();
|
||||
var firstObject = Player.DrawableRuleset.Playfield.HitObjectContainer.AliveObjects.OfType<DrawableHitCircle>().FirstOrDefault();
|
||||
|
||||
if (firstObject == null)
|
||||
return false;
|
||||
@ -75,7 +74,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
||||
[Resolved]
|
||||
private AudioManager audio { get; set; }
|
||||
|
||||
protected override Player CreatePlayer(Ruleset ruleset) => new SkinProvidingPlayer(testUserSkin);
|
||||
protected override TestPlayer CreatePlayer(Ruleset ruleset) => new SkinProvidingPlayer(testUserSkin);
|
||||
|
||||
protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap, Storyboard storyboard = null) => new CustomSkinWorkingBeatmap(beatmap, storyboard, Clock, audio, testBeatmapSkin);
|
||||
|
||||
|
@ -11,7 +11,6 @@ using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||
using osu.Game.Tests.Visual;
|
||||
using osuTK;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@ -44,7 +43,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
||||
base.SetUpSteps();
|
||||
|
||||
AddUntilStep("wait for track to start running", () => track.IsRunning);
|
||||
AddStep("retrieve spinner", () => drawableSpinner = (DrawableSpinner)((TestPlayer)Player).DrawableRuleset.Playfield.AllHitObjects.First());
|
||||
AddStep("retrieve spinner", () => drawableSpinner = (DrawableSpinner)Player.DrawableRuleset.Playfield.AllHitObjects.First());
|
||||
}
|
||||
|
||||
[Test]
|
||||
@ -89,7 +88,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
||||
{
|
||||
AddStep($"seek to {time}", () => track.Seek(time));
|
||||
|
||||
AddUntilStep("wait for seek to finish", () => Precision.AlmostEquals(time, ((TestPlayer)Player).DrawableRuleset.FrameStableClock.CurrentTime, 100));
|
||||
AddUntilStep("wait for seek to finish", () => Precision.AlmostEquals(time, Player.DrawableRuleset.FrameStableClock.CurrentTime, 100));
|
||||
}
|
||||
|
||||
protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) => new Beatmap
|
||||
|
@ -1,14 +0,0 @@
|
||||
// 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 osu.Game.Rulesets.Scoring;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Judgements
|
||||
{
|
||||
public class OsuSliderTailJudgement : OsuJudgement
|
||||
{
|
||||
public override bool AffectsCombo => false;
|
||||
|
||||
protected override int NumericResultFor(HitResult result) => 0;
|
||||
}
|
||||
}
|
@ -20,6 +20,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
|
||||
private const int spacing = 32;
|
||||
private const double preempt = 800;
|
||||
|
||||
public override bool RemoveWhenNotAlive => false;
|
||||
|
||||
/// <summary>
|
||||
/// The start time of <see cref="Start"/>.
|
||||
/// </summary>
|
||||
@ -79,27 +81,31 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
|
||||
drawableObject.HitObject.DefaultsApplied += scheduleRefresh;
|
||||
}
|
||||
|
||||
private void scheduleRefresh() => Scheduler.AddOnce(refresh);
|
||||
private void scheduleRefresh()
|
||||
{
|
||||
Scheduler.AddOnce(refresh);
|
||||
}
|
||||
|
||||
private void refresh()
|
||||
{
|
||||
ClearInternal();
|
||||
|
||||
if (End == null)
|
||||
return;
|
||||
|
||||
OsuHitObject osuStart = Start.HitObject;
|
||||
OsuHitObject osuEnd = End.HitObject;
|
||||
|
||||
if (osuEnd.NewCombo)
|
||||
return;
|
||||
|
||||
if (osuStart is Spinner || osuEnd is Spinner)
|
||||
return;
|
||||
|
||||
Vector2 startPosition = osuStart.EndPosition;
|
||||
Vector2 endPosition = osuEnd.Position;
|
||||
double startTime = osuStart.GetEndTime();
|
||||
|
||||
LifetimeStart = startTime;
|
||||
|
||||
OsuHitObject osuEnd = End?.HitObject;
|
||||
|
||||
if (osuEnd == null || osuEnd.NewCombo || osuStart is Spinner || osuEnd is Spinner)
|
||||
{
|
||||
// ensure we always set a lifetime for full LifetimeManagementContainer benefits
|
||||
LifetimeEnd = LifetimeStart;
|
||||
return;
|
||||
}
|
||||
|
||||
Vector2 startPosition = osuStart.StackedEndPosition;
|
||||
Vector2 endPosition = osuEnd.StackedPosition;
|
||||
double endTime = osuEnd.StartTime;
|
||||
|
||||
Vector2 distanceVector = endPosition - startPosition;
|
||||
@ -107,6 +113,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
|
||||
float rotation = (float)(Math.Atan2(distanceVector.Y, distanceVector.X) * (180 / Math.PI));
|
||||
double duration = endTime - startTime;
|
||||
|
||||
double? firstTransformStartTime = null;
|
||||
double finalTransformEndTime = startTime;
|
||||
|
||||
for (int d = (int)(spacing * 1.5); d < distance - spacing; d += spacing)
|
||||
{
|
||||
float fraction = (float)d / distance;
|
||||
@ -125,16 +134,23 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
|
||||
Scale = new Vector2(1.5f * osuEnd.Scale),
|
||||
});
|
||||
|
||||
if (firstTransformStartTime == null)
|
||||
firstTransformStartTime = fadeInTime;
|
||||
|
||||
using (fp.BeginAbsoluteSequence(fadeInTime))
|
||||
{
|
||||
fp.FadeIn(osuEnd.TimeFadeIn);
|
||||
fp.ScaleTo(osuEnd.Scale, osuEnd.TimeFadeIn, Easing.Out);
|
||||
fp.MoveTo(pointEndPosition, osuEnd.TimeFadeIn, Easing.Out);
|
||||
fp.Delay(fadeOutTime - fadeInTime).FadeOut(osuEnd.TimeFadeIn);
|
||||
}
|
||||
|
||||
fp.Expire(true);
|
||||
finalTransformEndTime = fadeOutTime + osuEnd.TimeFadeIn;
|
||||
}
|
||||
}
|
||||
|
||||
// todo: use Expire() on FollowPoints and take lifetime from them when https://github.com/ppy/osu-framework/issues/3300 is fixed.
|
||||
LifetimeStart = firstTransformStartTime ?? startTime;
|
||||
LifetimeEnd = finalTransformEndTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
|
||||
/// <summary>
|
||||
/// Visualises connections between <see cref="DrawableOsuHitObject"/>s.
|
||||
/// </summary>
|
||||
public class FollowPointRenderer : CompositeDrawable
|
||||
public class FollowPointRenderer : LifetimeManagementContainer
|
||||
{
|
||||
/// <summary>
|
||||
/// All the <see cref="FollowPointConnection"/>s contained by this <see cref="FollowPointRenderer"/>.
|
||||
@ -45,8 +45,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
|
||||
/// <returns>The index of <paramref name="connection"/> in <see cref="connections"/>.</returns>
|
||||
private void addConnection(FollowPointConnection connection)
|
||||
{
|
||||
AddInternal(connection);
|
||||
|
||||
// Groups are sorted by their start time when added such that the index can be used to post-process other surrounding connections
|
||||
int index = connections.AddInPlace(connection, Comparer<FollowPointConnection>.Create((g1, g2) => g1.StartTime.Value.CompareTo(g2.StartTime.Value)));
|
||||
|
||||
@ -74,6 +72,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
|
||||
FollowPointConnection previousConnection = connections[index - 1];
|
||||
previousConnection.End = connection.Start;
|
||||
}
|
||||
|
||||
AddInternal(connection);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -170,7 +170,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
|
||||
public Drawable ProxiedLayer => ApproachCircle;
|
||||
|
||||
public class HitReceptor : Drawable, IKeyBindingHandler<OsuAction>
|
||||
public class HitReceptor : CompositeDrawable, IKeyBindingHandler<OsuAction>
|
||||
{
|
||||
// IsHovered is used
|
||||
public override bool HandlePositionalInput => true;
|
||||
@ -185,6 +185,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
|
||||
Anchor = Anchor.Centre;
|
||||
Origin = Anchor.Centre;
|
||||
|
||||
CornerRadius = OsuHitObject.OBJECT_RADIUS;
|
||||
CornerExponent = 2;
|
||||
}
|
||||
|
||||
public bool OnPressed(OsuAction action)
|
||||
|
@ -4,7 +4,6 @@
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Osu.Judgements;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Objects
|
||||
@ -23,7 +22,7 @@ namespace osu.Game.Rulesets.Osu.Objects
|
||||
pathVersion.BindValueChanged(_ => Position = slider.EndPosition);
|
||||
}
|
||||
|
||||
public override Judgement CreateJudgement() => new OsuSliderTailJudgement();
|
||||
public override Judgement CreateJudgement() => new IgnoreJudgement();
|
||||
|
||||
protected override HitWindows CreateHitWindows() => HitWindows.Empty;
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ namespace osu.Game.Rulesets.Osu.Scoring
|
||||
new DifficultyRange(HitResult.Great, 80, 50, 20),
|
||||
new DifficultyRange(HitResult.Good, 140, 100, 60),
|
||||
new DifficultyRange(HitResult.Meh, 200, 150, 100),
|
||||
new DifficultyRange(HitResult.Miss, 200, 200, 200),
|
||||
new DifficultyRange(HitResult.Miss, 400, 400, 400),
|
||||
};
|
||||
|
||||
public override bool IsHitResultAllowed(HitResult result)
|
||||
|
@ -5,7 +5,6 @@ using System;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Caching;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Batches;
|
||||
using osu.Framework.Graphics.OpenGL.Vertices;
|
||||
@ -14,6 +13,7 @@ using osu.Framework.Graphics.Shaders;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Framework.Input;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Framework.Layout;
|
||||
using osu.Framework.Timing;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
@ -43,6 +43,8 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
|
||||
// -1 signals that the part is unusable, and should not be drawn
|
||||
parts[i].InvalidationID = -1;
|
||||
}
|
||||
|
||||
AddLayout(partSizeCache);
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
@ -72,20 +74,12 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
|
||||
}
|
||||
}
|
||||
|
||||
private readonly Cached<Vector2> partSizeCache = new Cached<Vector2>();
|
||||
private readonly LayoutValue<Vector2> partSizeCache = new LayoutValue<Vector2>(Invalidation.DrawInfo | Invalidation.RequiredParentSizeToFit | Invalidation.Presence);
|
||||
|
||||
private Vector2 partSize => partSizeCache.IsValid
|
||||
? partSizeCache.Value
|
||||
: (partSizeCache.Value = new Vector2(Texture.DisplayWidth, Texture.DisplayHeight) * DrawInfo.Matrix.ExtractScale().Xy);
|
||||
|
||||
public override bool Invalidate(Invalidation invalidation = Invalidation.All, Drawable source = null, bool shallPropagate = true)
|
||||
{
|
||||
if ((invalidation & (Invalidation.DrawInfo | Invalidation.RequiredParentSizeToFit | Invalidation.Presence)) > 0)
|
||||
partSizeCache.Invalidate();
|
||||
|
||||
return base.Invalidate(invalidation, source, shallPropagate);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The amount of time to fade the cursor trail pieces.
|
||||
/// </summary>
|
||||
@ -97,7 +91,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
|
||||
{
|
||||
base.Update();
|
||||
|
||||
Invalidate(Invalidation.DrawNode, shallPropagate: false);
|
||||
Invalidate(Invalidation.DrawNode);
|
||||
|
||||
const int fade_clock_reset_threshold = 1000000;
|
||||
|
||||
|
@ -0,0 +1,47 @@
|
||||
// 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.Scoring;
|
||||
using osu.Game.Rulesets.Taiko.Mods;
|
||||
using osu.Game.Rulesets.Taiko.Objects;
|
||||
using osu.Game.Rulesets.Taiko.Scoring;
|
||||
using osu.Game.Tests.Visual;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.Tests.Mods
|
||||
{
|
||||
public class TestSceneTaikoModPerfect : ModPerfectTestScene
|
||||
{
|
||||
public TestSceneTaikoModPerfect()
|
||||
: base(new TestTaikoRuleset(), new TaikoModPerfect())
|
||||
{
|
||||
}
|
||||
|
||||
[TestCase(false)]
|
||||
[TestCase(true)]
|
||||
public void TestHit(bool shouldMiss) => CreateHitObjectTest(new HitObjectTestData(new CentreHit { StartTime = 1000 }), shouldMiss);
|
||||
|
||||
[TestCase(false)]
|
||||
[TestCase(true)]
|
||||
public void TestDrumRoll(bool shouldMiss) => CreateHitObjectTest(new HitObjectTestData(new DrumRoll { StartTime = 1000, EndTime = 3000 }), shouldMiss);
|
||||
|
||||
[TestCase(false)]
|
||||
[TestCase(true)]
|
||||
public void TestSwell(bool shouldMiss) => CreateHitObjectTest(new HitObjectTestData(new Swell { StartTime = 1000, EndTime = 3000 }), shouldMiss);
|
||||
|
||||
private class TestTaikoRuleset : TaikoRuleset
|
||||
{
|
||||
public override HealthProcessor CreateHealthProcessor(double drainStartTime) => new TestTaikoHealthProcessor();
|
||||
|
||||
private class TestTaikoHealthProcessor : TaikoHealthProcessor
|
||||
{
|
||||
protected override void Reset(bool storeResults)
|
||||
{
|
||||
base.Reset(storeResults);
|
||||
|
||||
Health.Value = 1; // Don't care about the health condition (only the mod condition)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,24 +1,16 @@
|
||||
// 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 System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Rulesets.Taiko.Judgements;
|
||||
using osu.Game.Rulesets.Taiko.Objects;
|
||||
using osu.Game.Screens.Play;
|
||||
using osu.Game.Tests.Visual;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.Tests
|
||||
{
|
||||
public class TestSceneSwellJudgements : PlayerTestScene
|
||||
{
|
||||
protected new TestPlayer Player => (TestPlayer)base.Player;
|
||||
|
||||
public TestSceneSwellJudgements()
|
||||
: base(new TaikoRuleset())
|
||||
{
|
||||
@ -28,7 +20,7 @@ namespace osu.Game.Rulesets.Taiko.Tests
|
||||
public void TestZeroTickTimeOffsets()
|
||||
{
|
||||
AddUntilStep("gameplay finished", () => Player.ScoreProcessor.HasCompleted);
|
||||
AddAssert("all tick offsets are 0", () => Player.Results.Where(r => r.Judgement is TaikoSwellTickJudgement).All(r => r.TimeOffset == 0));
|
||||
AddAssert("all tick offsets are 0", () => Player.Results.Where(r => r.HitObject is SwellTick).All(r => r.TimeOffset == 0));
|
||||
}
|
||||
|
||||
protected override bool Autoplay => true;
|
||||
@ -50,25 +42,5 @@ namespace osu.Game.Rulesets.Taiko.Tests
|
||||
|
||||
return beatmap;
|
||||
}
|
||||
|
||||
protected override Player CreatePlayer(Ruleset ruleset) => new TestPlayer();
|
||||
|
||||
protected class TestPlayer : Player
|
||||
{
|
||||
public readonly List<JudgementResult> Results = new List<JudgementResult>();
|
||||
|
||||
public new ScoreProcessor ScoreProcessor => base.ScoreProcessor;
|
||||
|
||||
public TestPlayer()
|
||||
: base(false, false)
|
||||
{
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
ScoreProcessor.NewJudgement += r => Results.Add(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,11 +4,9 @@
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Rulesets.Taiko.Beatmaps;
|
||||
using osu.Game.Rulesets.Taiko.Mods;
|
||||
using osu.Game.Rulesets.Taiko.Objects;
|
||||
using osu.Game.Screens.Play;
|
||||
using osu.Game.Tests.Visual;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.Tests
|
||||
@ -22,10 +20,10 @@ namespace osu.Game.Rulesets.Taiko.Tests
|
||||
|
||||
protected override bool AllowFail => true;
|
||||
|
||||
protected override Player CreatePlayer(Ruleset ruleset)
|
||||
protected override TestPlayer CreatePlayer(Ruleset ruleset)
|
||||
{
|
||||
SelectedMods.Value = SelectedMods.Value.Concat(new[] { new TaikoModSuddenDeath() }).ToArray();
|
||||
return new ScoreAccessiblePlayer();
|
||||
return base.CreatePlayer(ruleset);
|
||||
}
|
||||
|
||||
protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) =>
|
||||
@ -49,20 +47,10 @@ namespace osu.Game.Rulesets.Taiko.Tests
|
||||
AddStep("Setup judgements", () =>
|
||||
{
|
||||
judged = false;
|
||||
((ScoreAccessiblePlayer)Player).ScoreProcessor.NewJudgement += b => judged = true;
|
||||
Player.ScoreProcessor.NewJudgement += b => judged = true;
|
||||
});
|
||||
AddUntilStep("swell judged", () => judged);
|
||||
AddAssert("not failed", () => !Player.HasFailed);
|
||||
}
|
||||
|
||||
private class ScoreAccessiblePlayer : TestPlayer
|
||||
{
|
||||
public ScoreAccessiblePlayer()
|
||||
: base(false, false)
|
||||
{
|
||||
}
|
||||
|
||||
public new ScoreProcessor ScoreProcessor => base.ScoreProcessor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,8 +2,8 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Caching;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Layout;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Taiko.Objects;
|
||||
using osu.Game.Rulesets.Taiko.UI;
|
||||
@ -30,13 +30,15 @@ namespace osu.Game.Rulesets.Taiko.Mods
|
||||
|
||||
private class TaikoFlashlight : Flashlight
|
||||
{
|
||||
private readonly Cached flashlightProperties = new Cached();
|
||||
private readonly LayoutValue flashlightProperties = new LayoutValue(Invalidation.DrawSize);
|
||||
private readonly TaikoPlayfield taikoPlayfield;
|
||||
|
||||
public TaikoFlashlight(TaikoPlayfield taikoPlayfield)
|
||||
{
|
||||
this.taikoPlayfield = taikoPlayfield;
|
||||
FlashlightSize = new Vector2(0, getSizeFor(0));
|
||||
|
||||
AddLayout(flashlightProperties);
|
||||
}
|
||||
|
||||
private float getSizeFor(int combo)
|
||||
@ -56,16 +58,6 @@ namespace osu.Game.Rulesets.Taiko.Mods
|
||||
|
||||
protected override string FragmentShader => "CircularFlashlight";
|
||||
|
||||
public override bool Invalidate(Invalidation invalidation = Invalidation.All, Drawable source = null, bool shallPropagate = true)
|
||||
{
|
||||
if ((invalidation & Invalidation.DrawSize) > 0)
|
||||
{
|
||||
flashlightProperties.Invalidate();
|
||||
}
|
||||
|
||||
return base.Invalidate(invalidation, source, shallPropagate);
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
@ -1,6 +1,7 @@
|
||||
// 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 osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.Objects
|
||||
@ -8,5 +9,7 @@ namespace osu.Game.Rulesets.Taiko.Objects
|
||||
public class BarLine : TaikoHitObject, IBarLine
|
||||
{
|
||||
public bool Major { get; set; }
|
||||
|
||||
public override Judgement CreateJudgement() => new IgnoreJudgement();
|
||||
}
|
||||
}
|
||||
|
@ -54,5 +54,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
||||
Alpha = 0.75f
|
||||
});
|
||||
}
|
||||
|
||||
protected override void UpdateStateTransforms(ArmedState state) => this.FadeOut(150);
|
||||
}
|
||||
}
|
||||
|
@ -3,13 +3,12 @@
|
||||
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Rulesets.Taiko.Judgements;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.Objects
|
||||
{
|
||||
public class SwellTick : TaikoHitObject
|
||||
{
|
||||
public override Judgement CreateJudgement() => new TaikoSwellTickJudgement();
|
||||
public override Judgement CreateJudgement() => new IgnoreJudgement();
|
||||
|
||||
protected override HitWindows CreateHitWindows() => HitWindows.Empty;
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
// 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.Judgements;
|
||||
@ -39,7 +40,7 @@ namespace osu.Game.Rulesets.Taiko.Scoring
|
||||
{
|
||||
base.ApplyBeatmap(beatmap);
|
||||
|
||||
hpMultiplier = 1 / (object_count_factor * beatmap.HitObjects.OfType<Hit>().Count() * BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.DrainRate, 0.5, 0.75, 0.98));
|
||||
hpMultiplier = 1 / (object_count_factor * Math.Max(1, beatmap.HitObjects.OfType<Hit>().Count()) * BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.DrainRate, 0.5, 0.75, 0.98));
|
||||
hpMissMultiplier = BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.DrainRate, 0.0018, 0.0075, 0.0120);
|
||||
}
|
||||
|
||||
|
@ -99,7 +99,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
||||
var storyboard = decoder.Decode(stream);
|
||||
|
||||
StoryboardLayer background = storyboard.Layers.Single(l => l.Depth == 3);
|
||||
Assert.AreEqual(123456, ((StoryboardSprite)background.Elements.Single()).InitialPosition.X);
|
||||
Assert.AreEqual(3456, ((StoryboardSprite)background.Elements.Single()).InitialPosition.X);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -154,6 +154,7 @@ namespace osu.Game.Tests.Gameplay
|
||||
private class JudgeableHitObject : HitObject
|
||||
{
|
||||
public override Judgement CreateJudgement() => new Judgement();
|
||||
protected override HitWindows CreateHitWindows() => new HitWindows();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -11,8 +11,8 @@ using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Audio;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Objects.Legacy;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Skinning;
|
||||
using osu.Game.Tests.Visual;
|
||||
@ -78,7 +78,7 @@ namespace osu.Game.Tests.Gameplay
|
||||
}
|
||||
}
|
||||
|
||||
private class TestHitObjectWithCombo : HitObject, IHasComboInformation
|
||||
private class TestHitObjectWithCombo : ConvertHitObject, IHasComboInformation
|
||||
{
|
||||
public bool NewCombo { get; } = false;
|
||||
public int ComboOffset { get; } = 0;
|
||||
|
@ -1,5 +1,5 @@
|
||||
[Variables]
|
||||
$var=1234
|
||||
$var=34
|
||||
|
||||
[Events]
|
||||
Sprite,Background,TopCentre,"img.jpg",$var56,240
|
||||
|
@ -49,7 +49,7 @@ namespace osu.Game.Tests.Visual.Background
|
||||
|
||||
private DummySongSelect songSelect;
|
||||
private TestPlayerLoader playerLoader;
|
||||
private TestPlayer player;
|
||||
private LoadBlockingTestPlayer player;
|
||||
private BeatmapManager manager;
|
||||
private RulesetStore rulesets;
|
||||
|
||||
@ -81,7 +81,7 @@ namespace osu.Game.Tests.Visual.Background
|
||||
public void PlayerLoaderSettingsHoverTest()
|
||||
{
|
||||
setupUserSettings();
|
||||
AddStep("Start player loader", () => songSelect.Push(playerLoader = new TestPlayerLoader(player = new TestPlayer { BlockLoad = true })));
|
||||
AddStep("Start player loader", () => songSelect.Push(playerLoader = new TestPlayerLoader(player = new LoadBlockingTestPlayer { BlockLoad = true })));
|
||||
AddUntilStep("Wait for Player Loader to load", () => playerLoader?.IsLoaded ?? false);
|
||||
AddAssert("Background retained from song select", () => songSelect.IsBackgroundCurrent());
|
||||
AddStep("Trigger background preview", () =>
|
||||
@ -268,7 +268,7 @@ namespace osu.Game.Tests.Visual.Background
|
||||
{
|
||||
setupUserSettings();
|
||||
|
||||
AddStep("Start player loader", () => songSelect.Push(playerLoader = new TestPlayerLoader(player = new TestPlayer(allowPause))));
|
||||
AddStep("Start player loader", () => songSelect.Push(playerLoader = new TestPlayerLoader(player = new LoadBlockingTestPlayer(allowPause))));
|
||||
|
||||
AddUntilStep("Wait for Player Loader to load", () => playerLoader.IsLoaded);
|
||||
AddStep("Move mouse to center of screen", () => InputManager.MoveMouseTo(playerLoader.ScreenPos));
|
||||
@ -347,7 +347,7 @@ namespace osu.Game.Tests.Visual.Background
|
||||
public bool IsBlurCorrect() => ((FadeAccessibleBackground)Background).CurrentBlur == new Vector2(BACKGROUND_BLUR);
|
||||
}
|
||||
|
||||
private class TestPlayer : Visual.TestPlayer
|
||||
private class LoadBlockingTestPlayer : TestPlayer
|
||||
{
|
||||
protected override BackgroundScreen CreateBackground() => new FadeAccessibleBackground(Beatmap.Value);
|
||||
|
||||
@ -360,7 +360,7 @@ namespace osu.Game.Tests.Visual.Background
|
||||
public readonly Bindable<bool> ReplacesBackground = new Bindable<bool>();
|
||||
public readonly Bindable<bool> IsPaused = new Bindable<bool>();
|
||||
|
||||
public TestPlayer(bool allowPause = true)
|
||||
public LoadBlockingTestPlayer(bool allowPause = true)
|
||||
: base(allowPause)
|
||||
{
|
||||
}
|
||||
|
@ -3,53 +3,32 @@
|
||||
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Screens.Play;
|
||||
using osu.Game.Storyboards;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Gameplay
|
||||
{
|
||||
[Description("Player instantiated with an autoplay mod.")]
|
||||
public class TestSceneAutoplay : TestSceneAllRulesetPlayers
|
||||
{
|
||||
private ClockBackedTestWorkingBeatmap.TrackVirtualManual track;
|
||||
protected new TestPlayer Player => (TestPlayer)base.Player;
|
||||
|
||||
protected override Player CreatePlayer(Ruleset ruleset)
|
||||
{
|
||||
SelectedMods.Value = SelectedMods.Value.Concat(new[] { ruleset.GetAutoplayMod() }).ToArray();
|
||||
return new ScoreAccessiblePlayer();
|
||||
return new TestPlayer(false, false);
|
||||
}
|
||||
|
||||
protected override void AddCheckSteps()
|
||||
{
|
||||
AddUntilStep("score above zero", () => ((ScoreAccessiblePlayer)Player).ScoreProcessor.TotalScore.Value > 0);
|
||||
AddUntilStep("key counter counted keys", () => ((ScoreAccessiblePlayer)Player).HUDOverlay.KeyCounter.Children.Any(kc => kc.CountPresses > 2));
|
||||
AddStep("rewind", () => track.Seek(-10000));
|
||||
AddUntilStep("key counter reset", () => ((ScoreAccessiblePlayer)Player).HUDOverlay.KeyCounter.Children.All(kc => kc.CountPresses == 0));
|
||||
}
|
||||
|
||||
protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap, Storyboard storyboard = null)
|
||||
{
|
||||
var working = base.CreateWorkingBeatmap(beatmap, storyboard);
|
||||
|
||||
track = (ClockBackedTestWorkingBeatmap.TrackVirtualManual)working.Track;
|
||||
|
||||
return working;
|
||||
}
|
||||
|
||||
private class ScoreAccessiblePlayer : TestPlayer
|
||||
{
|
||||
public new ScoreProcessor ScoreProcessor => base.ScoreProcessor;
|
||||
public new HUDOverlay HUDOverlay => base.HUDOverlay;
|
||||
|
||||
public new GameplayClockContainer GameplayClockContainer => base.GameplayClockContainer;
|
||||
|
||||
public ScoreAccessiblePlayer()
|
||||
: base(false, false)
|
||||
{
|
||||
}
|
||||
AddUntilStep("score above zero", () => Player.ScoreProcessor.TotalScore.Value > 0);
|
||||
AddUntilStep("key counter counted keys", () => Player.HUDOverlay.KeyCounter.Children.Any(kc => kc.CountPresses > 2));
|
||||
AddStep("seek to break time", () => Player.GameplayClockContainer.Seek(Player.BreakOverlay.Breaks.First().StartTime));
|
||||
AddUntilStep("wait for seek to complete", () =>
|
||||
Player.HUDOverlay.Progress.ReferenceClock.CurrentTime >= Player.BreakOverlay.Breaks.First().StartTime);
|
||||
AddAssert("test keys not counting", () => !Player.HUDOverlay.KeyCounter.IsCounting);
|
||||
AddStep("rewind", () => Player.GameplayClockContainer.Seek(-80000));
|
||||
AddUntilStep("key counter reset", () => Player.HUDOverlay.KeyCounter.Children.All(kc => kc.CountPresses == 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ using osu.Game.Rulesets.Difficulty;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Objects.Legacy;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Rulesets.UI;
|
||||
@ -289,7 +290,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
|
||||
#region HitObject
|
||||
|
||||
private class TestHitObject : HitObject, IHasEndTime
|
||||
private class TestHitObject : ConvertHitObject, IHasEndTime
|
||||
{
|
||||
public double EndTime { get; set; }
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
// 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 System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
@ -11,12 +10,8 @@ using osu.Framework.Utils;
|
||||
using osu.Framework.Timing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using osu.Game.Screens.Play;
|
||||
using osu.Game.Storyboards;
|
||||
using osuTK;
|
||||
|
||||
@ -24,8 +19,6 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
{
|
||||
public class TestSceneGameplayRewinding : PlayerTestScene
|
||||
{
|
||||
private RulesetExposingPlayer player => (RulesetExposingPlayer)Player;
|
||||
|
||||
[Resolved]
|
||||
private AudioManager audioManager { get; set; }
|
||||
|
||||
@ -48,13 +41,13 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
{
|
||||
AddUntilStep("wait for track to start running", () => track.IsRunning);
|
||||
addSeekStep(3000);
|
||||
AddAssert("all judged", () => player.DrawableRuleset.Playfield.AllHitObjects.All(h => h.Judged));
|
||||
AddUntilStep("key counter counted keys", () => player.HUDOverlay.KeyCounter.Children.All(kc => kc.CountPresses >= 7));
|
||||
AddStep("clear results", () => player.AppliedResults.Clear());
|
||||
AddAssert("all judged", () => Player.DrawableRuleset.Playfield.AllHitObjects.All(h => h.Judged));
|
||||
AddUntilStep("key counter counted keys", () => Player.HUDOverlay.KeyCounter.Children.All(kc => kc.CountPresses >= 7));
|
||||
AddStep("clear results", () => Player.Results.Clear());
|
||||
addSeekStep(0);
|
||||
AddAssert("none judged", () => player.DrawableRuleset.Playfield.AllHitObjects.All(h => !h.Judged));
|
||||
AddUntilStep("key counters reset", () => player.HUDOverlay.KeyCounter.Children.All(kc => kc.CountPresses == 0));
|
||||
AddAssert("no results triggered", () => player.AppliedResults.Count == 0);
|
||||
AddAssert("none judged", () => Player.DrawableRuleset.Playfield.AllHitObjects.All(h => !h.Judged));
|
||||
AddUntilStep("key counters reset", () => Player.HUDOverlay.KeyCounter.Children.All(kc => kc.CountPresses == 0));
|
||||
AddAssert("no results triggered", () => Player.Results.Count == 0);
|
||||
}
|
||||
|
||||
private void addSeekStep(double time)
|
||||
@ -62,13 +55,13 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
AddStep($"seek to {time}", () => track.Seek(time));
|
||||
|
||||
// Allow a few frames of lenience
|
||||
AddUntilStep("wait for seek to finish", () => Precision.AlmostEquals(time, player.DrawableRuleset.FrameStableClock.CurrentTime, 100));
|
||||
AddUntilStep("wait for seek to finish", () => Precision.AlmostEquals(time, Player.DrawableRuleset.FrameStableClock.CurrentTime, 100));
|
||||
}
|
||||
|
||||
protected override Player CreatePlayer(Ruleset ruleset)
|
||||
protected override TestPlayer CreatePlayer(Ruleset ruleset)
|
||||
{
|
||||
SelectedMods.Value = SelectedMods.Value.Concat(new[] { ruleset.GetAutoplayMod() }).ToArray();
|
||||
return new RulesetExposingPlayer();
|
||||
return base.CreatePlayer(ruleset);
|
||||
}
|
||||
|
||||
protected override IBeatmap CreateBeatmap(RulesetInfo ruleset)
|
||||
@ -89,29 +82,5 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
|
||||
return beatmap;
|
||||
}
|
||||
|
||||
private class RulesetExposingPlayer : Player
|
||||
{
|
||||
public readonly List<JudgementResult> AppliedResults = new List<JudgementResult>();
|
||||
|
||||
public new ScoreProcessor ScoreProcessor => base.ScoreProcessor;
|
||||
|
||||
public new HUDOverlay HUDOverlay => base.HUDOverlay;
|
||||
|
||||
public new GameplayClockContainer GameplayClockContainer => base.GameplayClockContainer;
|
||||
|
||||
public new DrawableRuleset DrawableRuleset => base.DrawableRuleset;
|
||||
|
||||
public RulesetExposingPlayer()
|
||||
: base(false, false)
|
||||
{
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
ScoreProcessor.NewJudgement += r => AppliedResults.Add(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,16 +2,17 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using NUnit.Framework;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Threading;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Rulesets.Catch.Scoring;
|
||||
using osu.Game.Rulesets.Mania.Scoring;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Osu.Scoring;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Rulesets.Taiko.Scoring;
|
||||
@ -43,6 +44,22 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
AddRepeatStep("New max negative", () => newJudgement(-hitWindows.WindowFor(HitResult.Meh)), 20);
|
||||
AddRepeatStep("New max positive", () => newJudgement(hitWindows.WindowFor(HitResult.Meh)), 20);
|
||||
AddStep("New fixed judgement (50ms)", () => newJudgement(50));
|
||||
|
||||
AddStep("Judgement barrage", () =>
|
||||
{
|
||||
int runCount = 0;
|
||||
|
||||
ScheduledDelegate del = null;
|
||||
|
||||
del = Scheduler.AddDelayed(() =>
|
||||
{
|
||||
newJudgement(runCount++ / 10f);
|
||||
|
||||
if (runCount == 500)
|
||||
// ReSharper disable once AccessToModifiedClosure
|
||||
del?.Cancel();
|
||||
}, 10, true);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -47,21 +47,22 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
|
||||
Key testKey = ((KeyCounterKeyboard)kc.Children.First()).Key;
|
||||
|
||||
AddStep($"Press {testKey} key", () =>
|
||||
void addPressKeyStep()
|
||||
{
|
||||
InputManager.PressKey(testKey);
|
||||
InputManager.ReleaseKey(testKey);
|
||||
});
|
||||
AddStep($"Press {testKey} key", () =>
|
||||
{
|
||||
InputManager.PressKey(testKey);
|
||||
InputManager.ReleaseKey(testKey);
|
||||
});
|
||||
}
|
||||
|
||||
addPressKeyStep();
|
||||
AddAssert($"Check {testKey} counter after keypress", () => testCounter.CountPresses == 1);
|
||||
|
||||
AddStep($"Press {testKey} key", () =>
|
||||
{
|
||||
InputManager.PressKey(testKey);
|
||||
InputManager.ReleaseKey(testKey);
|
||||
});
|
||||
|
||||
addPressKeyStep();
|
||||
AddAssert($"Check {testKey} counter after keypress", () => testCounter.CountPresses == 2);
|
||||
AddStep("Disable counting", () => testCounter.IsCounting = false);
|
||||
addPressKeyStep();
|
||||
AddAssert($"Check {testKey} count has not changed", () => testCounter.CountPresses == 2);
|
||||
|
||||
Add(kc);
|
||||
}
|
||||
|
@ -11,7 +11,6 @@ using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.Cursor;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Screens.Play;
|
||||
using osuTK;
|
||||
using osuTK.Input;
|
||||
@ -282,14 +281,10 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
|
||||
protected override bool AllowFail => true;
|
||||
|
||||
protected override Player CreatePlayer(Ruleset ruleset) => new PausePlayer();
|
||||
protected override TestPlayer CreatePlayer(Ruleset ruleset) => new PausePlayer();
|
||||
|
||||
protected class PausePlayer : TestPlayer
|
||||
{
|
||||
public new HealthProcessor HealthProcessor => base.HealthProcessor;
|
||||
|
||||
public new HUDOverlay HUDOverlay => base.HUDOverlay;
|
||||
|
||||
public bool FailOverlayVisible => FailOverlay.State.Value == Visibility.Visible;
|
||||
|
||||
public bool PauseOverlayVisible => PauseOverlay.State.Value == Visibility.Visible;
|
||||
|
@ -9,15 +9,12 @@ using osu.Framework.Testing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Screens.Play;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Gameplay
|
||||
{
|
||||
[HeadlessTest] // we alter unsafe properties on the game host to test inactive window state.
|
||||
public class TestScenePauseWhenInactive : PlayerTestScene
|
||||
{
|
||||
protected new TestPlayer Player => (TestPlayer)base.Player;
|
||||
|
||||
protected override IBeatmap CreateBeatmap(RulesetInfo ruleset)
|
||||
{
|
||||
var beatmap = (Beatmap)base.CreateBeatmap(ruleset);
|
||||
@ -46,6 +43,6 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
AddAssert("time of pause is after gameplay start time", () => Player.GameplayClockContainer.GameplayClock.CurrentTime >= Player.DrawableRuleset.GameplayStartTime);
|
||||
}
|
||||
|
||||
protected override Player CreatePlayer(Ruleset ruleset) => new TestPlayer(true, true, true);
|
||||
protected override TestPlayer CreatePlayer(Ruleset ruleset) => new TestPlayer(true, true, true);
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,6 @@ using System.Threading.Tasks;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Utils;
|
||||
@ -307,17 +306,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
public ScoreRank AdjustRank(ScoreRank rank, double accuracy) => rank;
|
||||
}
|
||||
|
||||
private class TestPlayer : Visual.TestPlayer
|
||||
{
|
||||
public new Bindable<IReadOnlyList<Mod>> Mods => base.Mods;
|
||||
|
||||
public TestPlayer(bool allowPause = true, bool showResults = true)
|
||||
: base(allowPause, showResults)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
protected class SlowLoadPlayer : Visual.TestPlayer
|
||||
protected class SlowLoadPlayer : TestPlayer
|
||||
{
|
||||
public readonly ManualResetEventSlim AllowLoad = new ManualResetEventSlim(false);
|
||||
|
||||
|
@ -3,9 +3,6 @@
|
||||
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Screens.Play.HUD;
|
||||
using osuTK;
|
||||
@ -45,32 +42,12 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
};
|
||||
Add(accuracyCounter);
|
||||
|
||||
StarCounter stars = new StarCounter
|
||||
{
|
||||
Origin = Anchor.BottomLeft,
|
||||
Anchor = Anchor.BottomLeft,
|
||||
Position = new Vector2(20, -160),
|
||||
CountStars = 5,
|
||||
};
|
||||
Add(stars);
|
||||
|
||||
SpriteText starsLabel = new OsuSpriteText
|
||||
{
|
||||
Origin = Anchor.BottomLeft,
|
||||
Anchor = Anchor.BottomLeft,
|
||||
Position = new Vector2(20, -190),
|
||||
Text = stars.CountStars.ToString("0.00"),
|
||||
};
|
||||
Add(starsLabel);
|
||||
|
||||
AddStep(@"Reset all", delegate
|
||||
{
|
||||
score.Current.Value = 0;
|
||||
comboCounter.Current.Value = 0;
|
||||
numerator = denominator = 0;
|
||||
accuracyCounter.SetFraction(0, 0);
|
||||
stars.CountStars = 0;
|
||||
starsLabel.Text = stars.CountStars.ToString("0.00");
|
||||
});
|
||||
|
||||
AddStep(@"Hit! :D", delegate
|
||||
@ -88,20 +65,6 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
denominator++;
|
||||
accuracyCounter.SetFraction(numerator, denominator);
|
||||
});
|
||||
|
||||
AddStep(@"Alter stars", delegate
|
||||
{
|
||||
stars.CountStars = RNG.NextSingle() * (stars.StarCount + 1);
|
||||
starsLabel.Text = stars.CountStars.ToString("0.00");
|
||||
});
|
||||
|
||||
AddStep(@"Stop counters", delegate
|
||||
{
|
||||
score.StopRolling();
|
||||
comboCounter.StopRolling();
|
||||
accuracyCounter.StopRolling();
|
||||
stars.StopAnimation();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
57
osu.Game.Tests/Visual/Gameplay/TestSceneStarCounter.cs
Normal file
@ -0,0 +1,57 @@
|
||||
// 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.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Gameplay
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestSceneStarCounter : OsuTestScene
|
||||
{
|
||||
public TestSceneStarCounter()
|
||||
{
|
||||
StarCounter stars = new StarCounter
|
||||
{
|
||||
Origin = Anchor.Centre,
|
||||
Anchor = Anchor.Centre,
|
||||
Current = 5,
|
||||
};
|
||||
|
||||
Add(stars);
|
||||
|
||||
SpriteText starsLabel = new OsuSpriteText
|
||||
{
|
||||
Origin = Anchor.Centre,
|
||||
Anchor = Anchor.Centre,
|
||||
Scale = new Vector2(2),
|
||||
Y = 50,
|
||||
Text = stars.Current.ToString("0.00"),
|
||||
};
|
||||
|
||||
Add(starsLabel);
|
||||
|
||||
AddRepeatStep(@"random value", delegate
|
||||
{
|
||||
stars.Current = RNG.NextSingle() * (stars.StarCount + 1);
|
||||
starsLabel.Text = stars.Current.ToString("0.00");
|
||||
}, 10);
|
||||
|
||||
AddStep(@"Stop animation", delegate
|
||||
{
|
||||
stars.StopAnimation();
|
||||
});
|
||||
|
||||
AddStep(@"Reset", delegate
|
||||
{
|
||||
stars.Current = 0;
|
||||
starsLabel.Text = stars.Current.ToString("0.00");
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -62,14 +62,7 @@ namespace osu.Game.Tests.Visual.Navigation
|
||||
var frameworkConfig = host.Dependencies.Get<FrameworkConfigManager>();
|
||||
frameworkConfig.GetBindable<double>(FrameworkSetting.CursorSensitivity).Disabled = false;
|
||||
|
||||
Game = new TestOsuGame(LocalStorage, API);
|
||||
Game.SetHost(host);
|
||||
|
||||
// todo: this can be removed once we can run audio tracks without a device present
|
||||
// see https://github.com/ppy/osu/issues/1302
|
||||
Game.LocalConfig.Set(OsuSetting.IntroSequence, IntroSequence.Circles);
|
||||
|
||||
Add(Game);
|
||||
CreateGame();
|
||||
});
|
||||
|
||||
AddUntilStep("Wait for load", () => Game.IsLoaded);
|
||||
@ -78,6 +71,18 @@ namespace osu.Game.Tests.Visual.Navigation
|
||||
ConfirmAtMainMenu();
|
||||
}
|
||||
|
||||
protected void CreateGame()
|
||||
{
|
||||
Game = new TestOsuGame(LocalStorage, API);
|
||||
Game.SetHost(host);
|
||||
|
||||
// todo: this can be removed once we can run audio tracks without a device present
|
||||
// see https://github.com/ppy/osu/issues/1302
|
||||
Game.LocalConfig.Set(OsuSetting.IntroSequence, IntroSequence.Circles);
|
||||
|
||||
Add(Game);
|
||||
}
|
||||
|
||||
protected void PushAndConfirm(Func<Screen> newScreen)
|
||||
{
|
||||
Screen screen = null;
|
||||
@ -97,12 +102,17 @@ namespace osu.Game.Tests.Visual.Navigation
|
||||
|
||||
public new SettingsPanel Settings => base.Settings;
|
||||
|
||||
public new MusicController MusicController => base.MusicController;
|
||||
|
||||
public new OsuConfigManager LocalConfig => base.LocalConfig;
|
||||
|
||||
public new Bindable<WorkingBeatmap> Beatmap => base.Beatmap;
|
||||
|
||||
public new Bindable<RulesetInfo> Ruleset => base.Ruleset;
|
||||
|
||||
// if we don't do this, when running under nUnit the version that gets populated is that of nUnit.
|
||||
public override string Version => "test game";
|
||||
|
||||
protected override Loader CreateLoader() => new TestLoader();
|
||||
|
||||
public new void PerformFromScreen(Action<IScreen> action, IEnumerable<Type> validScreens = null) => base.PerformFromScreen(action, validScreens);
|
||||
|
@ -114,6 +114,22 @@ namespace osu.Game.Tests.Visual.Navigation
|
||||
AddAssert("Options overlay was closed", () => Game.Settings.State.Value == Visibility.Hidden);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestWaitForNextTrackInMenu()
|
||||
{
|
||||
bool trackCompleted = false;
|
||||
|
||||
AddUntilStep("Wait for music controller", () => Game.MusicController.IsLoaded);
|
||||
AddStep("Seek close to end", () =>
|
||||
{
|
||||
Game.MusicController.SeekTo(Game.Beatmap.Value.Track.Length - 1000);
|
||||
Game.Beatmap.Value.Track.Completed += () => trackCompleted = true;
|
||||
});
|
||||
|
||||
AddUntilStep("Track was completed", () => trackCompleted);
|
||||
AddUntilStep("Track was restarted", () => Game.Beatmap.Value.Track.IsRunning);
|
||||
}
|
||||
|
||||
private void pushEscape() =>
|
||||
AddStep("Press escape", () => pressAndRelease(Key.Escape));
|
||||
|
||||
|
41
osu.Game.Tests/Visual/Navigation/TestSettingsMigration.cs
Normal file
@ -0,0 +1,41 @@
|
||||
// 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.Framework.Utils;
|
||||
using osu.Game.Configuration;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Navigation
|
||||
{
|
||||
public class TestSettingsMigration : OsuGameTestScene
|
||||
{
|
||||
public override void RecycleLocalStorage()
|
||||
{
|
||||
base.RecycleLocalStorage();
|
||||
|
||||
using (var config = new OsuConfigManager(LocalStorage))
|
||||
{
|
||||
config.Set(OsuSetting.Version, "2020.101.0");
|
||||
config.Set(OsuSetting.DisplayStarsMaximum, 10.0);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDisplayStarsMigration()
|
||||
{
|
||||
AddAssert("config has migrated value", () => Precision.AlmostEquals(Game.LocalConfig.Get<double>(OsuSetting.DisplayStarsMaximum), 10.1));
|
||||
|
||||
AddStep("set value again", () => Game.LocalConfig.Set<double>(OsuSetting.DisplayStarsMaximum, 10));
|
||||
|
||||
AddStep("force save config", () => Game.LocalConfig.Save());
|
||||
|
||||
AddStep("remove game", () => Remove(Game));
|
||||
|
||||
AddStep("create game again", CreateGame);
|
||||
|
||||
AddUntilStep("Wait for load", () => Game.IsLoaded);
|
||||
|
||||
AddAssert("config did not migrate value", () => Precision.AlmostEquals(Game.LocalConfig.Get<double>(OsuSetting.DisplayStarsMaximum), 10));
|
||||
}
|
||||
}
|
||||
}
|
@ -13,6 +13,8 @@ using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics;
|
||||
using osuTK;
|
||||
using JetBrains.Annotations;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Online
|
||||
{
|
||||
@ -30,6 +32,8 @@ namespace osu.Game.Tests.Visual.Online
|
||||
private readonly BindableBool showDeleted = new BindableBool();
|
||||
private readonly Container content;
|
||||
|
||||
private TestCommentsPage commentsPage;
|
||||
|
||||
public TestSceneCommentsPage()
|
||||
{
|
||||
Add(new FillFlowContainer
|
||||
@ -57,15 +61,29 @@ namespace osu.Game.Tests.Visual.Online
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
AddStep("load comments", () => createPage(getCommentBundle()));
|
||||
AddStep("load empty comments", () => createPage(getEmptyCommentBundle()));
|
||||
[Test]
|
||||
public void TestAppendDuplicatedComment()
|
||||
{
|
||||
AddStep("Create page", () => createPage(getCommentBundle()));
|
||||
AddAssert("Dictionary length is 10", () => commentsPage?.DictionaryLength == 10);
|
||||
AddStep("Append existing comment", () => commentsPage?.AppendComments(getCommentSubBundle()));
|
||||
AddAssert("Dictionary length is 10", () => commentsPage?.DictionaryLength == 10);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestEmptyBundle()
|
||||
{
|
||||
AddStep("Create page", () => createPage(getEmptyCommentBundle()));
|
||||
AddAssert("Dictionary length is 0", () => commentsPage?.DictionaryLength == 0);
|
||||
}
|
||||
|
||||
private void createPage(CommentBundle commentBundle)
|
||||
{
|
||||
commentsPage = null;
|
||||
content.Clear();
|
||||
content.Add(new CommentsPage(commentBundle)
|
||||
content.Add(commentsPage = new TestCommentsPage(commentBundle)
|
||||
{
|
||||
ShowDeleted = { BindTarget = showDeleted }
|
||||
});
|
||||
@ -182,5 +200,33 @@ namespace osu.Game.Tests.Visual.Online
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
private CommentBundle getCommentSubBundle() => new CommentBundle
|
||||
{
|
||||
Comments = new List<Comment>
|
||||
{
|
||||
new Comment
|
||||
{
|
||||
Id = 1,
|
||||
Message = "Simple test comment",
|
||||
LegacyName = "TestUser1",
|
||||
CreatedAt = DateTimeOffset.Now,
|
||||
VotesCount = 5
|
||||
},
|
||||
},
|
||||
IncludedComments = new List<Comment>(),
|
||||
};
|
||||
|
||||
private class TestCommentsPage : CommentsPage
|
||||
{
|
||||
public TestCommentsPage(CommentBundle commentBundle)
|
||||
: base(commentBundle)
|
||||
{
|
||||
}
|
||||
|
||||
public new void AppendComments([NotNull] CommentBundle bundle) => base.AppendComments(bundle);
|
||||
|
||||
public int DictionaryLength => CommentDictionary.Count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,9 +2,11 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Users;
|
||||
using osuTK;
|
||||
|
||||
@ -13,13 +15,19 @@ namespace osu.Game.Tests.Visual.Online
|
||||
[TestFixture]
|
||||
public class TestSceneUserPanel : OsuTestScene
|
||||
{
|
||||
private readonly UserPanel peppy;
|
||||
private readonly Bindable<UserActivity> activity = new Bindable<UserActivity>();
|
||||
|
||||
public TestSceneUserPanel()
|
||||
private UserPanel peppy;
|
||||
|
||||
[Resolved]
|
||||
private RulesetStore rulesetStore { get; set; }
|
||||
|
||||
[SetUp]
|
||||
public void SetUp() => Schedule(() =>
|
||||
{
|
||||
UserPanel flyte;
|
||||
|
||||
Add(new FillFlowContainer
|
||||
Child = new FillFlowContainer
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
@ -44,34 +52,38 @@ namespace osu.Game.Tests.Visual.Online
|
||||
SupportLevel = 3,
|
||||
}) { Width = 300 },
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
flyte.Status.Value = new UserStatusOnline();
|
||||
peppy.Status.Value = null;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void UserStatusesTests()
|
||||
{
|
||||
AddStep("online", () => { peppy.Status.Value = new UserStatusOnline(); });
|
||||
AddStep(@"do not disturb", () => { peppy.Status.Value = new UserStatusDoNotDisturb(); });
|
||||
AddStep(@"offline", () => { peppy.Status.Value = new UserStatusOffline(); });
|
||||
AddStep(@"null status", () => { peppy.Status.Value = null; });
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void UserActivitiesTests()
|
||||
{
|
||||
Bindable<UserActivity> activity = new Bindable<UserActivity>();
|
||||
|
||||
peppy.Activity.BindTo(activity);
|
||||
});
|
||||
|
||||
AddStep("idle", () => { activity.Value = null; });
|
||||
AddStep("spectating", () => { activity.Value = new UserActivity.Spectating(); });
|
||||
AddStep("solo", () => { activity.Value = new UserActivity.SoloGame(null, null); });
|
||||
AddStep("choosing", () => { activity.Value = new UserActivity.ChoosingBeatmap(); });
|
||||
AddStep("editing", () => { activity.Value = new UserActivity.Editing(null); });
|
||||
AddStep("modding", () => { activity.Value = new UserActivity.Modding(); });
|
||||
[Test]
|
||||
public void TestUserStatus()
|
||||
{
|
||||
AddStep("online", () => peppy.Status.Value = new UserStatusOnline());
|
||||
AddStep("do not disturb", () => peppy.Status.Value = new UserStatusDoNotDisturb());
|
||||
AddStep("offline", () => peppy.Status.Value = new UserStatusOffline());
|
||||
AddStep("null status", () => peppy.Status.Value = null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestUserActivity()
|
||||
{
|
||||
AddStep("set online status", () => peppy.Status.Value = new UserStatusOnline());
|
||||
|
||||
AddStep("idle", () => activity.Value = null);
|
||||
AddStep("spectating", () => activity.Value = new UserActivity.Spectating());
|
||||
AddStep("solo (osu!)", () => activity.Value = soloGameStatusForRuleset(0));
|
||||
AddStep("solo (osu!taiko)", () => activity.Value = soloGameStatusForRuleset(1));
|
||||
AddStep("solo (osu!catch)", () => activity.Value = soloGameStatusForRuleset(2));
|
||||
AddStep("solo (osu!mania)", () => activity.Value = soloGameStatusForRuleset(3));
|
||||
AddStep("choosing", () => activity.Value = new UserActivity.ChoosingBeatmap());
|
||||
AddStep("editing", () => activity.Value = new UserActivity.Editing(null));
|
||||
AddStep("modding", () => activity.Value = new UserActivity.Modding());
|
||||
}
|
||||
|
||||
private UserActivity soloGameStatusForRuleset(int rulesetId) => new UserActivity.SoloGame(null, rulesetStore.GetRuleset(rulesetId));
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,8 @@ using NUnit.Framework;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Overlays.Comments;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Game.Overlays;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Online
|
||||
{
|
||||
@ -18,6 +20,9 @@ namespace osu.Game.Tests.Visual.Online
|
||||
typeof(VotePill)
|
||||
};
|
||||
|
||||
[Cached]
|
||||
private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue);
|
||||
|
||||
private VotePill votePill;
|
||||
|
||||
[Test]
|
||||
|
@ -13,6 +13,7 @@ using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Catch;
|
||||
using osu.Game.Rulesets.Mania;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Objects.Legacy;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Rulesets.Taiko;
|
||||
@ -194,7 +195,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
public new BufferedWedgeInfo Info => base.Info;
|
||||
}
|
||||
|
||||
private class TestHitObject : HitObject, IHasPosition
|
||||
private class TestHitObject : ConvertHitObject, IHasPosition
|
||||
{
|
||||
public float X { get; } = 0;
|
||||
public float Y { get; } = 0;
|
||||
|
@ -0,0 +1,57 @@
|
||||
// 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.Collections.Generic;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Overlays.Home.Friends;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Tests.Visual.UserInterface
|
||||
{
|
||||
public class TestSceneUserListToolbar : OsuTestScene
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(UserSortTabControl),
|
||||
typeof(OverlaySortTabControl<>),
|
||||
typeof(OverlayPanelDisplayStyleControl),
|
||||
typeof(UserListToolbar),
|
||||
};
|
||||
|
||||
[Cached]
|
||||
private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple);
|
||||
|
||||
public TestSceneUserListToolbar()
|
||||
{
|
||||
UserListToolbar toolbar;
|
||||
OsuSpriteText sort;
|
||||
OsuSpriteText displayStyle;
|
||||
|
||||
Add(toolbar = new UserListToolbar
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
});
|
||||
|
||||
Add(new FillFlowContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Vertical,
|
||||
Spacing = new Vector2(0, 5),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
sort = new OsuSpriteText(),
|
||||
displayStyle = new OsuSpriteText()
|
||||
}
|
||||
});
|
||||
|
||||
toolbar.SortCriteria.BindValueChanged(criteria => sort.Text = $"Criteria: {criteria.NewValue}", true);
|
||||
toolbar.DisplayStyle.BindValueChanged(style => displayStyle.Text = $"Style: {style.NewValue}", true);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,125 @@
|
||||
// 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.Collections.Generic;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Tests.Visual;
|
||||
using osu.Game.Tournament.Components;
|
||||
using osu.Game.Tournament.Models;
|
||||
using osu.Game.Tournament.Screens.Drawings.Components;
|
||||
using osu.Game.Tournament.Screens.Gameplay.Components;
|
||||
using osu.Game.Tournament.Screens.Ladder.Components;
|
||||
using osu.Game.Users;
|
||||
|
||||
namespace osu.Game.Tournament.Tests.Components
|
||||
{
|
||||
public class TestSceneDrawableTournamentTeam : OsuGridTestScene
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(DrawableTeamFlag),
|
||||
typeof(DrawableTeamTitle),
|
||||
typeof(DrawableTeamTitleWithHeader),
|
||||
typeof(DrawableMatchTeam),
|
||||
typeof(DrawableTeamWithPlayers),
|
||||
typeof(GroupTeam),
|
||||
typeof(TeamDisplay),
|
||||
};
|
||||
|
||||
public TestSceneDrawableTournamentTeam()
|
||||
: base(4, 3)
|
||||
{
|
||||
var team = new TournamentTeam
|
||||
{
|
||||
FlagName = { Value = "AU" },
|
||||
FullName = { Value = "Australia" },
|
||||
Players =
|
||||
{
|
||||
new User { Username = "ASecretBox" },
|
||||
new User { Username = "Dereban" },
|
||||
new User { Username = "mReKk" },
|
||||
new User { Username = "uyghti" },
|
||||
new User { Username = "Parkes" },
|
||||
new User { Username = "Shiroha" },
|
||||
new User { Username = "Jordan The Bear" },
|
||||
}
|
||||
};
|
||||
|
||||
var match = new TournamentMatch { Team1 = { Value = team } };
|
||||
|
||||
int i = 0;
|
||||
|
||||
Cell(i++).AddRange(new Drawable[]
|
||||
{
|
||||
new TournamentSpriteText { Text = "DrawableTeamFlag" },
|
||||
new DrawableTeamFlag(team)
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
}
|
||||
});
|
||||
|
||||
Cell(i++).AddRange(new Drawable[]
|
||||
{
|
||||
new TournamentSpriteText { Text = "DrawableTeamTitle" },
|
||||
new DrawableTeamTitle(team)
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
}
|
||||
});
|
||||
|
||||
Cell(i++).AddRange(new Drawable[]
|
||||
{
|
||||
new TournamentSpriteText { Text = "DrawableTeamTitleWithHeader" },
|
||||
new DrawableTeamTitleWithHeader(team, TeamColour.Red)
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
}
|
||||
});
|
||||
|
||||
Cell(i++).AddRange(new Drawable[]
|
||||
{
|
||||
new TournamentSpriteText { Text = "DrawableMatchTeam" },
|
||||
new DrawableMatchTeam(team, match, false)
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
}
|
||||
});
|
||||
|
||||
Cell(i++).AddRange(new Drawable[]
|
||||
{
|
||||
new TournamentSpriteText { Text = "TeamWithPlayers" },
|
||||
new DrawableTeamWithPlayers(team, TeamColour.Blue)
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
}
|
||||
});
|
||||
|
||||
Cell(i++).AddRange(new Drawable[]
|
||||
{
|
||||
new TournamentSpriteText { Text = "GroupTeam" },
|
||||
new GroupTeam(team)
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
}
|
||||
});
|
||||
|
||||
Cell(i).AddRange(new Drawable[]
|
||||
{
|
||||
new TournamentSpriteText { Text = "TeamDisplay" },
|
||||
new TeamDisplay(team, TeamColour.Red, new Bindable<int?>(2), 6)
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -1,16 +1,31 @@
|
||||
// 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.Collections.Generic;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Game.Tournament.Components;
|
||||
using osu.Game.Tournament.Screens;
|
||||
using osu.Game.Tournament.Screens.Gameplay;
|
||||
using osu.Game.Tournament.Screens.Gameplay.Components;
|
||||
|
||||
namespace osu.Game.Tournament.Tests.Screens
|
||||
{
|
||||
public class TestSceneGameplayScreen : TournamentTestScene
|
||||
{
|
||||
[Cached]
|
||||
private TournamentMatchChatDisplay chat = new TournamentMatchChatDisplay();
|
||||
private TournamentMatchChatDisplay chat = new TournamentMatchChatDisplay { Width = 0.5f };
|
||||
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(TeamScore),
|
||||
typeof(TeamScoreDisplay),
|
||||
typeof(TeamDisplay),
|
||||
typeof(MatchHeader),
|
||||
typeof(MatchScoreDisplay),
|
||||
typeof(BeatmapInfoScreen),
|
||||
typeof(SongBar),
|
||||
};
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
|
@ -2,6 +2,8 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Tournament.Components;
|
||||
using osu.Game.Tournament.Screens.Schedule;
|
||||
|
||||
namespace osu.Game.Tournament.Tests.Screens
|
||||
@ -11,6 +13,7 @@ namespace osu.Game.Tournament.Tests.Screens
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
Add(new TourneyVideo("main") { RelativeSizeAxes = Axes.Both });
|
||||
Add(new ScheduleScreen());
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,25 @@
|
||||
// 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 osu.Framework.Allocation;
|
||||
using osu.Game.Tournament.Models;
|
||||
using osu.Game.Tournament.Screens.Editors;
|
||||
|
||||
namespace osu.Game.Tournament.Tests.Screens
|
||||
{
|
||||
public class TestSceneSeedingEditorScreen : LadderTestScene
|
||||
{
|
||||
[Cached]
|
||||
private readonly LadderInfo ladder = new LadderInfo();
|
||||
|
||||
public TestSceneSeedingEditorScreen()
|
||||
{
|
||||
var match = TestSceneSeedingScreen.CreateSampleSeededMatch();
|
||||
|
||||
Add(new SeedingEditorScreen(match.Team1.Value)
|
||||
{
|
||||
Width = 0.85f // create room for control panel
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
127
osu.Game.Tournament.Tests/Screens/TestSceneSeedingScreen.cs
Normal file
@ -0,0 +1,127 @@
|
||||
// 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 osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Tournament.Models;
|
||||
using osu.Game.Tournament.Screens.TeamIntro;
|
||||
using osu.Game.Users;
|
||||
|
||||
namespace osu.Game.Tournament.Tests.Screens
|
||||
{
|
||||
public class TestSceneSeedingScreen : LadderTestScene
|
||||
{
|
||||
[Cached]
|
||||
private readonly LadderInfo ladder = new LadderInfo();
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
ladder.CurrentMatch.Value = CreateSampleSeededMatch();
|
||||
|
||||
Add(new SeedingScreen
|
||||
{
|
||||
FillMode = FillMode.Fit,
|
||||
FillAspectRatio = 16 / 9f
|
||||
});
|
||||
}
|
||||
|
||||
public static TournamentMatch CreateSampleSeededMatch() => new TournamentMatch
|
||||
{
|
||||
Team1 =
|
||||
{
|
||||
Value = new TournamentTeam
|
||||
{
|
||||
FlagName = { Value = "JP" },
|
||||
FullName = { Value = "Japan" },
|
||||
LastYearPlacing = { Value = 10 },
|
||||
Seed = { Value = "Low" },
|
||||
SeedingResults =
|
||||
{
|
||||
new SeedingResult
|
||||
{
|
||||
Mod = { Value = "NM" },
|
||||
Seed = { Value = 10 },
|
||||
Beatmaps =
|
||||
{
|
||||
new SeedingBeatmap
|
||||
{
|
||||
BeatmapInfo = new BeatmapInfo { Metadata = new BeatmapMetadata { Title = "Test Title", Artist = "Test Artist" } },
|
||||
Score = 12345672,
|
||||
Seed = { Value = 24 },
|
||||
},
|
||||
new SeedingBeatmap
|
||||
{
|
||||
BeatmapInfo = new BeatmapInfo { Metadata = new BeatmapMetadata { Title = "Test Title", Artist = "Test Artist" } },
|
||||
Score = 1234567,
|
||||
Seed = { Value = 12 },
|
||||
},
|
||||
new SeedingBeatmap
|
||||
{
|
||||
BeatmapInfo = new BeatmapInfo { Metadata = new BeatmapMetadata { Title = "Test Title", Artist = "Test Artist" } },
|
||||
Score = 1234567,
|
||||
Seed = { Value = 16 },
|
||||
}
|
||||
}
|
||||
},
|
||||
new SeedingResult
|
||||
{
|
||||
Mod = { Value = "DT" },
|
||||
Seed = { Value = 5 },
|
||||
Beatmaps =
|
||||
{
|
||||
new SeedingBeatmap
|
||||
{
|
||||
BeatmapInfo = new BeatmapInfo { Metadata = new BeatmapMetadata { Title = "Test Title", Artist = "Test Artist" } },
|
||||
Score = 234567,
|
||||
Seed = { Value = 3 },
|
||||
},
|
||||
new SeedingBeatmap
|
||||
{
|
||||
BeatmapInfo = new BeatmapInfo { Metadata = new BeatmapMetadata { Title = "Test Title", Artist = "Test Artist" } },
|
||||
Score = 234567,
|
||||
Seed = { Value = 6 },
|
||||
},
|
||||
new SeedingBeatmap
|
||||
{
|
||||
BeatmapInfo = new BeatmapInfo { Metadata = new BeatmapMetadata { Title = "Test Title", Artist = "Test Artist" } },
|
||||
Score = 234567,
|
||||
Seed = { Value = 12 },
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
Players =
|
||||
{
|
||||
new User { Username = "Hello", Statistics = new UserStatistics { Ranks = new UserStatistics.UserRanks { Global = 12 } } },
|
||||
new User { Username = "Hello", Statistics = new UserStatistics { Ranks = new UserStatistics.UserRanks { Global = 16 } } },
|
||||
new User { Username = "Hello", Statistics = new UserStatistics { Ranks = new UserStatistics.UserRanks { Global = 20 } } },
|
||||
new User { Username = "Hello", Statistics = new UserStatistics { Ranks = new UserStatistics.UserRanks { Global = 24 } } },
|
||||
new User { Username = "Hello", Statistics = new UserStatistics { Ranks = new UserStatistics.UserRanks { Global = 30 } } },
|
||||
}
|
||||
}
|
||||
},
|
||||
Team2 =
|
||||
{
|
||||
Value = new TournamentTeam
|
||||
{
|
||||
FlagName = { Value = "US" },
|
||||
FullName = { Value = "United States" },
|
||||
Players =
|
||||
{
|
||||
new User { Username = "Hello" },
|
||||
new User { Username = "Hello" },
|
||||
new User { Username = "Hello" },
|
||||
new User { Username = "Hello" },
|
||||
new User { Username = "Hello" },
|
||||
}
|
||||
}
|
||||
},
|
||||
Round =
|
||||
{
|
||||
Value = new TournamentRound { Name = { Value = "Quarterfinals" } }
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -21,6 +21,7 @@ namespace osu.Game.Tournament.Tests.Screens
|
||||
match.Team1.Value = Ladder.Teams.FirstOrDefault(t => t.Acronym.Value == "USA");
|
||||
match.Team2.Value = Ladder.Teams.FirstOrDefault(t => t.Acronym.Value == "JPN");
|
||||
match.Round.Value = Ladder.Rounds.FirstOrDefault(g => g.Name.Value == "Finals");
|
||||
match.Completed.Value = true;
|
||||
ladder.CurrentMatch.Value = match;
|
||||
|
||||
Add(new TeamWinScreen
|
||||
|
@ -5,7 +5,6 @@ using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
@ -35,7 +34,7 @@ namespace osu.Game.Tournament.Components
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = new Color4(54, 54, 54, 255)
|
||||
},
|
||||
new OsuSpriteText
|
||||
new TournamentSpriteText
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
|
33
osu.Game.Tournament/Components/DrawableTeamFlag.cs
Normal file
@ -0,0 +1,33 @@
|
||||
// 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 JetBrains.Annotations;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Game.Tournament.Models;
|
||||
|
||||
namespace osu.Game.Tournament.Components
|
||||
{
|
||||
public class DrawableTeamFlag : Sprite
|
||||
{
|
||||
private readonly TournamentTeam team;
|
||||
|
||||
[UsedImplicitly]
|
||||
private Bindable<string> flag;
|
||||
|
||||
public DrawableTeamFlag(TournamentTeam team)
|
||||
{
|
||||
this.team = team;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(TextureStore textures)
|
||||
{
|
||||
if (team == null) return;
|
||||
|
||||
(flag = team.FlagName.GetBoundCopy()).BindValueChanged(acronym => Texture = textures.Get($@"Flags/{team.FlagName}"), true);
|
||||
}
|
||||
}
|
||||
}
|
20
osu.Game.Tournament/Components/DrawableTeamHeader.cs
Normal file
@ -0,0 +1,20 @@
|
||||
// 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 osu.Game.Tournament.Models;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Tournament.Components
|
||||
{
|
||||
public class DrawableTeamHeader : TournamentSpriteTextWithBackground
|
||||
{
|
||||
public DrawableTeamHeader(TeamColour colour)
|
||||
{
|
||||
Background.Colour = TournamentGame.GetTeamColour(colour);
|
||||
|
||||
Text.Colour = TournamentGame.TEXT_COLOUR;
|
||||
Text.Text = $"Team {colour}".ToUpperInvariant();
|
||||
Text.Scale = new Vector2(0.6f);
|
||||
}
|
||||
}
|
||||
}
|
32
osu.Game.Tournament/Components/DrawableTeamTitle.cs
Normal file
@ -0,0 +1,32 @@
|
||||
// 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 JetBrains.Annotations;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Game.Tournament.Models;
|
||||
|
||||
namespace osu.Game.Tournament.Components
|
||||
{
|
||||
public class DrawableTeamTitle : TournamentSpriteTextWithBackground
|
||||
{
|
||||
private readonly TournamentTeam team;
|
||||
|
||||
[UsedImplicitly]
|
||||
private Bindable<string> acronym;
|
||||
|
||||
public DrawableTeamTitle(TournamentTeam team)
|
||||
{
|
||||
this.team = team;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(TextureStore textures)
|
||||
{
|
||||
if (team == null) return;
|
||||
|
||||
(acronym = team.Acronym.GetBoundCopy()).BindValueChanged(acronym => Text.Text = team?.FullName.Value ?? string.Empty, true);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
// 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 osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Tournament.Models;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Tournament.Components
|
||||
{
|
||||
public class DrawableTeamTitleWithHeader : CompositeDrawable
|
||||
{
|
||||
public DrawableTeamTitleWithHeader(TournamentTeam team, TeamColour colour)
|
||||
{
|
||||
AutoSizeAxes = Axes.Both;
|
||||
|
||||
InternalChild = new FillFlowContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Vertical,
|
||||
Spacing = new Vector2(0, 10),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new DrawableTeamHeader(colour),
|
||||
new DrawableTeamTitle(team),
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
66
osu.Game.Tournament/Components/DrawableTeamWithPlayers.cs
Normal file
@ -0,0 +1,66 @@
|
||||
// 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 osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Tournament.Models;
|
||||
using osu.Game.Users;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Tournament.Components
|
||||
{
|
||||
public class DrawableTeamWithPlayers : CompositeDrawable
|
||||
{
|
||||
public DrawableTeamWithPlayers(TournamentTeam team, TeamColour colour)
|
||||
{
|
||||
AutoSizeAxes = Axes.Both;
|
||||
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
new FillFlowContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Vertical,
|
||||
Spacing = new Vector2(30),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new DrawableTeamTitleWithHeader(team, colour),
|
||||
new FillFlowContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Horizontal,
|
||||
Padding = new MarginPadding { Left = 10 },
|
||||
Spacing = new Vector2(30),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new FillFlowContainer
|
||||
{
|
||||
Direction = FillDirection.Vertical,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
ChildrenEnumerable = team?.Players.Select(createPlayerText).Take(5) ?? Enumerable.Empty<Drawable>()
|
||||
},
|
||||
new FillFlowContainer
|
||||
{
|
||||
Direction = FillDirection.Vertical,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
ChildrenEnumerable = team?.Players.Select(createPlayerText).Skip(5) ?? Enumerable.Empty<Drawable>()
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
TournamentSpriteText createPlayerText(User p) =>
|
||||
new TournamentSpriteText
|
||||
{
|
||||
Text = p.Username,
|
||||
Font = OsuFont.Torus.With(size: 24, weight: FontWeight.SemiBold),
|
||||
Colour = Color4.White,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@ -9,7 +9,6 @@ using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Tournament.Models;
|
||||
|
||||
namespace osu.Game.Tournament.Components
|
||||
@ -19,27 +18,24 @@ namespace osu.Game.Tournament.Components
|
||||
public readonly TournamentTeam Team;
|
||||
|
||||
protected readonly Sprite Flag;
|
||||
protected readonly OsuSpriteText AcronymText;
|
||||
protected readonly TournamentSpriteText AcronymText;
|
||||
|
||||
[UsedImplicitly]
|
||||
private Bindable<string> acronym;
|
||||
|
||||
[UsedImplicitly]
|
||||
private Bindable<string> flag;
|
||||
|
||||
protected DrawableTournamentTeam(TournamentTeam team)
|
||||
{
|
||||
Team = team;
|
||||
|
||||
Flag = new Sprite
|
||||
Flag = new DrawableTeamFlag(team)
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
FillMode = FillMode.Fit
|
||||
};
|
||||
|
||||
AcronymText = new OsuSpriteText
|
||||
AcronymText = new TournamentSpriteText
|
||||
{
|
||||
Font = OsuFont.GetFont(weight: FontWeight.Regular),
|
||||
Font = OsuFont.Torus.With(weight: FontWeight.Regular),
|
||||
};
|
||||
}
|
||||
|
||||
@ -49,7 +45,6 @@ namespace osu.Game.Tournament.Components
|
||||
if (Team == null) return;
|
||||
|
||||
(acronym = Team.Acronym.GetBoundCopy()).BindValueChanged(acronym => AcronymText.Text = Team?.Acronym.Value?.ToUpperInvariant() ?? string.Empty, true);
|
||||
(flag = Team.FlagName.GetBoundCopy()).BindValueChanged(acronym => Flag.Texture = textures.Get($@"Flags/{Team.FlagName}"), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,16 @@
|
||||
// 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 osu.Game.Graphics;
|
||||
|
||||
namespace osu.Game.Tournament.Components
|
||||
{
|
||||
public class DrawableTournamentTitleText : TournamentSpriteText
|
||||
{
|
||||
public DrawableTournamentTitleText()
|
||||
{
|
||||
Text = "osu!taiko world cup 2020";
|
||||
Font = OsuFont.Torus.With(size: 26, weight: FontWeight.SemiBold);
|
||||
}
|
||||
}
|
||||
}
|