1
0
mirror of https://github.com/ppy/osu.git synced 2025-01-13 14:12:56 +08:00

Merge branch 'master' into textbox-AllowIme-false

This commit is contained in:
Dean Herbert 2022-01-18 17:03:51 +09:00 committed by GitHub
commit 39c9c4985b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
142 changed files with 1177 additions and 476 deletions

View File

@ -0,0 +1 @@
osu.Android

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="UserContentModel">
<attachedFolders />
<explicitIncludes />
<explicitExcludes />
</component>
</project>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="com.jetbrains.rider.android.RiderAndroidMiscFileCreationComponent">
<option name="ENSURE_MISC_FILE_EXISTS" value="true" />
</component>
</project>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RiderProjectSettingsUpdater">
<option name="vcsConfiguration" value="2" />
</component>
</project>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="com.jetbrains.rider.android.RiderAndroidMiscFileCreationComponent">
<option name="ENSURE_MISC_FILE_EXISTS" value="true" />
</component>
</project>

View File

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/.idea.osu/riderModule.iml" filepath="$PROJECT_DIR$/.idea/.idea.osu/riderModule.iml" />
</modules>
</component>
</project>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RiderProjectSettingsUpdater">
<option name="vcsConfiguration" value="1" />
<option name="vcsConfiguration" value="2" />
</component>
</project>

View File

@ -31,7 +31,7 @@ If you are looking to install or test osu! without setting up a development envi
**Latest build:**
| [Windows 8.1+ (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 10+](https://osu.ppy.sh/home/testflight) | [Android 5+](https://github.com/ppy/osu/releases/latest/download/sh.ppy.osulazer.apk)
| [Windows 8.1+ (x64)](https://github.com/ppy/osu/releases/latest/download/install.exe) | [macOS 10.15+](https://github.com/ppy/osu/releases/latest/download/osu.app.zip) | [Linux (x64)](https://github.com/ppy/osu/releases/latest/download/osu.AppImage) | [iOS 10+](https://osu.ppy.sh/home/testflight) | [Android 5+](https://github.com/ppy/osu/releases/latest/download/sh.ppy.osulazer.apk)
| ------------- | ------------- | ------------- | ------------- | ------------- |
- The iOS testflight link may fill up (Apple has a hard limit of 10,000 users). We reset it occasionally when this happens. Please do not ask about this. Check back regularly for link resets or follow [peppy](https://twitter.com/ppy) on twitter for announcements of link resets.

View File

@ -4,7 +4,6 @@
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Platform;
using osu.Game.Tests.Visual;
using osuTK.Graphics;
@ -13,7 +12,7 @@ namespace osu.Game.Rulesets.EmptyFreeform.Tests
public class TestSceneOsuGame : OsuTestScene
{
[BackgroundDependencyLoader]
private void load(GameHost host, OsuGameBase gameBase)
private void load()
{
Children = new Drawable[]
{

View File

@ -12,7 +12,7 @@
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
<PackageReference Include="NUnit" Version="3.13.2" />
<PackageReference Include="NUnit3TestAdapter" Version="4.1.0" />
<PackageReference Include="NUnit3TestAdapter" Version="4.2.0" />
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
</ItemGroup>
<ItemGroup>

View File

@ -4,7 +4,6 @@
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Platform;
using osu.Game.Tests.Visual;
using osuTK.Graphics;
@ -13,7 +12,7 @@ namespace osu.Game.Rulesets.Pippidon.Tests
public class TestSceneOsuGame : OsuTestScene
{
[BackgroundDependencyLoader]
private void load(GameHost host, OsuGameBase gameBase)
private void load()
{
Children = new Drawable[]
{

View File

@ -12,7 +12,7 @@
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
<PackageReference Include="NUnit" Version="3.13.2" />
<PackageReference Include="NUnit3TestAdapter" Version="4.1.0" />
<PackageReference Include="NUnit3TestAdapter" Version="4.2.0" />
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
</ItemGroup>
<ItemGroup>

View File

@ -4,7 +4,6 @@
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Platform;
using osu.Game.Tests.Visual;
using osuTK.Graphics;
@ -13,7 +12,7 @@ namespace osu.Game.Rulesets.EmptyScrolling.Tests
public class TestSceneOsuGame : OsuTestScene
{
[BackgroundDependencyLoader]
private void load(GameHost host, OsuGameBase gameBase)
private void load()
{
Children = new Drawable[]
{

View File

@ -12,7 +12,7 @@
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
<PackageReference Include="NUnit" Version="3.13.2" />
<PackageReference Include="NUnit3TestAdapter" Version="4.1.0" />
<PackageReference Include="NUnit3TestAdapter" Version="4.2.0" />
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
</ItemGroup>
<ItemGroup>

View File

@ -4,7 +4,6 @@
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Platform;
using osu.Game.Tests.Visual;
using osuTK.Graphics;
@ -13,7 +12,7 @@ namespace osu.Game.Rulesets.Pippidon.Tests
public class TestSceneOsuGame : OsuTestScene
{
[BackgroundDependencyLoader]
private void load(GameHost host, OsuGameBase gameBase)
private void load()
{
Children = new Drawable[]
{

View File

@ -12,7 +12,7 @@
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
<PackageReference Include="NUnit" Version="3.13.2" />
<PackageReference Include="NUnit3TestAdapter" Version="4.1.0" />
<PackageReference Include="NUnit3TestAdapter" Version="4.2.0" />
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
</ItemGroup>
<ItemGroup>

View File

@ -7,7 +7,6 @@ using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Textures;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
@ -28,7 +27,7 @@ namespace osu.Game.Rulesets.Pippidon.UI
private PippidonCharacter pippidon;
[BackgroundDependencyLoader]
private void load(TextureStore textures)
private void load()
{
AddRangeInternal(new Drawable[]
{

View File

@ -51,11 +51,11 @@
<Reference Include="Java.Interop" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="ppy.osu.Game.Resources" Version="2022.109.0" />
<PackageReference Include="ppy.osu.Framework.Android" Version="2022.111.0" />
<PackageReference Include="ppy.osu.Game.Resources" Version="2022.115.0" />
<PackageReference Include="ppy.osu.Framework.Android" Version="2022.118.0" />
</ItemGroup>
<ItemGroup Label="Transitive Dependencies">
<!-- Realm needs to be directly referenced in all Xamarin projects, as it will not pull in its transitive dependencies otherwise. -->
<PackageReference Include="Realm" Version="10.7.1" />
<PackageReference Include="Realm" Version="10.8.0" />
</ItemGroup>
</Project>

View File

@ -10,14 +10,11 @@ using System.Runtime.Versioning;
using System.Threading.Tasks;
using Microsoft.Win32;
using osu.Desktop.Security;
using osu.Desktop.Overlays;
using osu.Framework.Platform;
using osu.Game;
using osu.Desktop.Updater;
using osu.Framework;
using osu.Framework.Logging;
using osu.Framework.Screens;
using osu.Game.Screens.Menu;
using osu.Game.Updater;
using osu.Desktop.Windows;
using osu.Framework.Threading;
@ -27,13 +24,9 @@ namespace osu.Desktop
{
internal class OsuGameDesktop : OsuGame
{
private readonly bool noVersionOverlay;
private VersionManager versionManager;
public OsuGameDesktop(string[] args = null)
: base(args)
{
noVersionOverlay = args?.Any(a => a == "--no-version-overlay") ?? false;
}
public override StableStorage GetStorageForStableInstall()
@ -114,9 +107,6 @@ namespace osu.Desktop
{
base.LoadComplete();
if (!noVersionOverlay)
LoadComponentAsync(versionManager = new VersionManager { Depth = int.MinValue }, ScreenContainer.Add);
LoadComponentAsync(new DiscordRichPresence(), Add);
if (RuntimeInfo.OS == RuntimeInfo.Platform.Windows)
@ -125,23 +115,6 @@ namespace osu.Desktop
LoadComponentAsync(new ElevatedPrivilegesChecker(), Add);
}
protected override void ScreenChanged(IScreen lastScreen, IScreen newScreen)
{
base.ScreenChanged(lastScreen, newScreen);
switch (newScreen)
{
case IntroScreen _:
case MainMenu _:
versionManager?.Show();
break;
default:
versionManager?.Hide();
break;
}
}
public override void SetHost(GameHost host)
{
base.SetHost(host);

View File

@ -73,7 +73,7 @@ namespace osu.Desktop.Security
}
[BackgroundDependencyLoader]
private void load(OsuColour colours, NotificationOverlay notificationOverlay)
private void load(OsuColour colours)
{
Icon = FontAwesome.Solid.ShieldAlt;
IconBackground.Colour = colours.YellowDark;

View File

@ -4,6 +4,8 @@
using System;
using System.Runtime.InteropServices;
// ReSharper disable IdentifierTypo
namespace osu.Desktop.Windows
{
internal class WindowsKey

View File

@ -9,7 +9,7 @@
<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.13.1" />
<PackageReference Include="nunit" Version="3.13.2" />
<PackageReference Include="NUnit3TestAdapter" Version="4.1.0" />
<PackageReference Include="NUnit3TestAdapter" Version="4.2.0" />
</ItemGroup>
<ItemGroup>

View File

@ -4,7 +4,7 @@
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
<PackageReference Include="NUnit" Version="3.13.2" />
<PackageReference Include="NUnit3TestAdapter" Version="4.1.0" />
<PackageReference Include="NUnit3TestAdapter" Version="4.2.0" />
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
</ItemGroup>
<PropertyGroup Label="Project">

View File

@ -4,11 +4,14 @@ Version: 2.5
[Mania]
Keys: 4
ColumnLineWidth: 3,1,3,1,1
Hit0: mania/hit0
Hit50: mania/hit50
Hit100: mania/hit100
Hit200: mania/hit200
Hit300: mania/hit300
Hit300g: mania/hit300g
// some skins found in the wild had configuration keys where the @2x suffix was included in the values.
// the expected compatibility behaviour is that the presence of the @2x suffix shouldn't change anything
// if @2x assets are present.
Hit0: mania/hit0@2x
Hit50: mania/hit50@2x
Hit100: mania/hit100@2x
Hit200: mania/hit200@2x
Hit300: mania/hit300@2x
Hit300g: mania/hit300g@2x
StageLeft: mania/stage-left
StageRight: mania/stage-right

View File

@ -5,8 +5,10 @@ using System;
using System.Linq;
using osu.Framework.Extensions;
using osu.Framework.Graphics;
using osu.Framework.Testing;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Mania.Scoring;
using osu.Game.Rulesets.Mania.Skinning.Legacy;
using osu.Game.Rulesets.Mania.UI;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Scoring;
@ -23,7 +25,9 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning
{
if (hitWindows.IsHitResultAllowed(result))
{
AddStep("Show " + result.GetDescription(), () => SetContents(_ =>
AddStep("Show " + result.GetDescription(), () =>
{
SetContents(_ =>
new DrawableManiaJudgement(new JudgementResult(new HitObject { StartTime = Time.Current }, new Judgement())
{
Type = result
@ -31,7 +35,14 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
}));
});
// for test purposes, undo the Y adjustment related to the `ScorePosition` legacy positioning config value
// (see `LegacyManiaJudgementPiece.load()`).
// this prevents the judgements showing somewhere below or above the bounding box of the judgement.
foreach (var legacyPiece in this.ChildrenOfType<LegacyManiaJudgementPiece>())
legacyPiece.Y = 0;
});
}
}
}

View File

@ -4,7 +4,7 @@
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
<PackageReference Include="NUnit" Version="3.13.2" />
<PackageReference Include="NUnit3TestAdapter" Version="4.1.0" />
<PackageReference Include="NUnit3TestAdapter" Version="4.2.0" />
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
</ItemGroup>
<PropertyGroup Label="Project">

View File

@ -9,7 +9,6 @@ using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics;
using osu.Game.Rulesets.Mania.Edit.Blueprints.Components;
using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.UI.Scrolling;
using osuTK;
namespace osu.Game.Rulesets.Mania.Edit.Blueprints
@ -28,7 +27,7 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints
}
[BackgroundDependencyLoader]
private void load(IScrollingInfo scrollingInfo)
private void load()
{
InternalChildren = new Drawable[]
{

View File

@ -49,7 +49,7 @@ namespace osu.Game.Rulesets.Mania
public override ScoreProcessor CreateScoreProcessor() => new ManiaScoreProcessor();
public override HealthProcessor CreateHealthProcessor(double drainStartTime) => new DrainingHealthProcessor(drainStartTime, 0.5);
public override HealthProcessor CreateHealthProcessor(double drainStartTime) => new ManiaHealthProcessor(drainStartTime, 0.5);
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new ManiaBeatmapConverter(beatmap, this);

View File

@ -0,0 +1,23 @@
// 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.Scoring;
namespace osu.Game.Rulesets.Mania.Scoring
{
public class ManiaHealthProcessor : DrainingHealthProcessor
{
/// <inheritdoc/>
public ManiaHealthProcessor(double drainStartTime, double drainLenience = 0)
: base(drainStartTime, drainLenience)
{
}
protected override HitResult GetSimulatedHitResult(Judgement judgement)
{
// Users are not expected to attain perfect judgements for all notes due to the tighter hit window.
return judgement.MaxResult == HitResult.Perfect ? HitResult.Great : judgement.MaxResult;
}
}
}

View File

@ -0,0 +1,225 @@
// 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.Input.Events;
using osu.Framework.Testing;
using osu.Framework.Utils;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Input.Bindings;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Osu.Edit;
using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.UI;
using osu.Game.Screens.Edit;
using osu.Game.Screens.Edit.Compose.Components;
using osu.Game.Tests.Beatmaps;
using osu.Game.Tests.Visual;
using osuTK;
using osuTK.Input;
namespace osu.Game.Rulesets.Osu.Tests.Editor
{
public class TestSceneSliderSnapping : EditorTestScene
{
private const double beat_length = 1000;
protected override Ruleset CreateEditorRuleset() => new OsuRuleset();
protected override IBeatmap CreateBeatmap(RulesetInfo ruleset)
{
var controlPointInfo = new ControlPointInfo();
controlPointInfo.Add(0, new TimingControlPoint { BeatLength = beat_length });
return new TestBeatmap(ruleset, false)
{
ControlPointInfo = controlPointInfo
};
}
private Slider slider;
public override void SetUpSteps()
{
base.SetUpSteps();
AddStep("add unsnapped slider", () => EditorBeatmap.Add(slider = new Slider
{
StartTime = 0,
Position = OsuPlayfield.BASE_SIZE / 5,
Path = new SliderPath
{
ControlPoints =
{
new PathControlPoint(Vector2.Zero),
new PathControlPoint(OsuPlayfield.BASE_SIZE * 2 / 5),
new PathControlPoint(OsuPlayfield.BASE_SIZE * 3 / 5)
}
}
}));
AddStep("set beat divisor to 1/1", () =>
{
var beatDivisor = (BindableBeatDivisor)Editor.Dependencies.Get(typeof(BindableBeatDivisor));
beatDivisor.Value = 1;
});
}
[Test]
public void TestMovingUnsnappedSliderNodesSnaps()
{
PathControlPointPiece sliderEnd = null;
assertSliderSnapped(false);
AddStep("select slider", () => EditorBeatmap.SelectedHitObjects.Add(slider));
AddStep("select slider end", () =>
{
sliderEnd = this.ChildrenOfType<PathControlPointPiece>().Single(piece => piece.ControlPoint == slider.Path.ControlPoints.Last());
InputManager.MoveMouseTo(sliderEnd.ScreenSpaceDrawQuad.Centre);
});
AddStep("move slider end", () =>
{
InputManager.PressButton(MouseButton.Left);
InputManager.MoveMouseTo(sliderEnd.ScreenSpaceDrawQuad.Centre - new Vector2(0, 20));
InputManager.ReleaseButton(MouseButton.Left);
});
assertSliderSnapped(true);
}
[Test]
public void TestAddingControlPointToUnsnappedSliderNodesSnaps()
{
assertSliderSnapped(false);
AddStep("select slider", () => EditorBeatmap.SelectedHitObjects.Add(slider));
AddStep("move mouse to new point location", () =>
{
var firstPiece = this.ChildrenOfType<PathControlPointPiece>().Single(piece => piece.ControlPoint == slider.Path.ControlPoints[0]);
var secondPiece = this.ChildrenOfType<PathControlPointPiece>().Single(piece => piece.ControlPoint == slider.Path.ControlPoints[1]);
InputManager.MoveMouseTo((firstPiece.ScreenSpaceDrawQuad.Centre + secondPiece.ScreenSpaceDrawQuad.Centre) / 2);
});
AddStep("move slider end", () =>
{
InputManager.PressKey(Key.ControlLeft);
InputManager.Click(MouseButton.Left);
InputManager.ReleaseKey(Key.ControlLeft);
});
assertSliderSnapped(true);
}
[Test]
public void TestRemovingControlPointFromUnsnappedSliderNodesSnaps()
{
assertSliderSnapped(false);
AddStep("select slider", () => EditorBeatmap.SelectedHitObjects.Add(slider));
AddStep("move mouse to second control point", () =>
{
var secondPiece = this.ChildrenOfType<PathControlPointPiece>().Single(piece => piece.ControlPoint == slider.Path.ControlPoints[1]);
InputManager.MoveMouseTo(secondPiece);
});
AddStep("quick delete", () =>
{
InputManager.PressKey(Key.ShiftLeft);
InputManager.PressButton(MouseButton.Right);
InputManager.ReleaseKey(Key.ShiftLeft);
});
assertSliderSnapped(true);
}
[Test]
public void TestResizingUnsnappedSliderSnaps()
{
SelectionBoxScaleHandle handle = null;
assertSliderSnapped(false);
AddStep("select slider", () => EditorBeatmap.SelectedHitObjects.Add(slider));
AddStep("move mouse to scale handle", () =>
{
handle = this.ChildrenOfType<SelectionBoxScaleHandle>().First();
InputManager.MoveMouseTo(handle.ScreenSpaceDrawQuad.Centre);
});
AddStep("scale slider", () =>
{
InputManager.PressButton(MouseButton.Left);
InputManager.MoveMouseTo(handle.ScreenSpaceDrawQuad.Centre + new Vector2(20, 20));
InputManager.ReleaseButton(MouseButton.Left);
});
assertSliderSnapped(true);
}
[Test]
public void TestRotatingUnsnappedSliderDoesNotSnap()
{
SelectionBoxRotationHandle handle = null;
assertSliderSnapped(false);
AddStep("select slider", () => EditorBeatmap.SelectedHitObjects.Add(slider));
AddStep("move mouse to rotate handle", () =>
{
handle = this.ChildrenOfType<SelectionBoxRotationHandle>().First();
InputManager.MoveMouseTo(handle.ScreenSpaceDrawQuad.Centre);
});
AddStep("scale slider", () =>
{
InputManager.PressButton(MouseButton.Left);
InputManager.MoveMouseTo(handle.ScreenSpaceDrawQuad.Centre + new Vector2(0, 20));
InputManager.ReleaseButton(MouseButton.Left);
});
assertSliderSnapped(false);
}
[Test]
public void TestFlippingSliderDoesNotSnap()
{
OsuSelectionHandler selectionHandler = null;
assertSliderSnapped(false);
AddStep("select slider", () => EditorBeatmap.SelectedHitObjects.Add(slider));
AddStep("flip slider horizontally", () =>
{
selectionHandler = this.ChildrenOfType<OsuSelectionHandler>().Single();
selectionHandler.OnPressed(new KeyBindingPressEvent<GlobalAction>(InputManager.CurrentState, GlobalAction.EditorFlipHorizontally));
});
assertSliderSnapped(false);
AddStep("flip slider vertically", () =>
{
selectionHandler = this.ChildrenOfType<OsuSelectionHandler>().Single();
selectionHandler.OnPressed(new KeyBindingPressEvent<GlobalAction>(InputManager.CurrentState, GlobalAction.EditorFlipVertically));
});
assertSliderSnapped(false);
}
[Test]
public void TestReversingSliderDoesNotSnap()
{
assertSliderSnapped(false);
AddStep("select slider", () => EditorBeatmap.SelectedHitObjects.Add(slider));
AddStep("reverse slider", () =>
{
InputManager.PressKey(Key.ControlLeft);
InputManager.Key(Key.G);
InputManager.ReleaseKey(Key.ControlLeft);
});
assertSliderSnapped(false);
}
private void assertSliderSnapped(bool snapped)
=> AddAssert($"slider is {(snapped ? "" : "not ")}snapped", () =>
{
double durationInBeatLengths = slider.Duration / beat_length;
double fractionalPart = durationInBeatLengths - (int)durationInBeatLengths;
return Precision.AlmostEquals(fractionalPart, 0) == snapped;
});
}
}

View File

@ -5,7 +5,7 @@
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
<PackageReference Include="Moq" Version="4.16.1" />
<PackageReference Include="NUnit" Version="3.13.2" />
<PackageReference Include="NUnit3TestAdapter" Version="4.1.0" />
<PackageReference Include="NUnit3TestAdapter" Version="4.2.0" />
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
</ItemGroup>
<PropertyGroup Label="Project">

View File

@ -283,6 +283,9 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
}
}
// Snap the path to the current beat divisor before checking length validity.
slider.SnapTo(snapProvider);
if (!slider.Path.HasValidLength)
{
for (int i = 0; i < slider.Path.ControlPoints.Count; i++)
@ -290,6 +293,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
slider.Position = oldPosition;
slider.StartTime = oldStartTime;
// Snap the path length again to undo the invalid length.
slider.SnapTo(snapProvider);
return;
}

View File

@ -9,7 +9,6 @@ using osu.Framework.Graphics;
using osu.Framework.Input;
using osu.Framework.Input.Events;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Graphics;
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Types;
@ -50,7 +49,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
private void load()
{
InternalChildren = new Drawable[]
{

View File

@ -80,7 +80,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
controlPoints.BindTo(HitObject.Path.ControlPoints);
pathVersion.BindTo(HitObject.Path.Version);
pathVersion.BindValueChanged(_ => updatePath());
pathVersion.BindValueChanged(_ => editorBeatmap?.Update(HitObject));
BodyPiece.UpdateFrom(HitObject);
}
@ -208,6 +208,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
// Move the control points from the insertion index onwards to make room for the insertion
controlPoints.Insert(insertionIndex, pathControlPoint);
HitObject.SnapTo(composer);
return pathControlPoint;
}
@ -227,7 +229,10 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
controlPoints.Remove(c);
}
// If there are 0 or 1 remaining control points, the slider is in a degenerate (single point) form and should be deleted
// Snap the slider to the current beat divisor before checking length validity.
HitObject.SnapTo(composer);
// If there are 0 or 1 remaining control points, or the slider has an invalid length, it is in a degenerate form and should be deleted
if (controlPoints.Count <= 1 || !HitObject.Path.HasValidLength)
{
placementHandler?.Delete(HitObject);
@ -242,12 +247,6 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
HitObject.Position += first;
}
private void updatePath()
{
HitObject.Path.ExpectedDistance.Value = composer?.GetSnappedDistanceFromDistance(HitObject, (float)HitObject.Path.CalculatedDistance) ?? (float)HitObject.Path.CalculatedDistance;
editorBeatmap?.Update(HitObject);
}
private void convertToStream()
{
if (editorBeatmap == null || changeHandler == null || beatDivisor == null)

View File

@ -1,12 +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.
#nullable enable
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Primitives;
using osu.Framework.Utils;
using osu.Game.Extensions;
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Osu.Objects;
@ -18,6 +22,9 @@ namespace osu.Game.Rulesets.Osu.Edit
{
public class OsuSelectionHandler : EditorSelectionHandler
{
[Resolved(CanBeNull = true)]
private IPositionSnapProvider? positionSnapProvider { get; set; }
/// <summary>
/// During a transform, the initial origin is stored so it can be used throughout the operation.
/// </summary>
@ -27,7 +34,7 @@ namespace osu.Game.Rulesets.Osu.Edit
/// During a transform, the initial path types of a single selected slider are stored so they
/// can be maintained throughout the operation.
/// </summary>
private List<PathType?> referencePathTypes;
private List<PathType?>? referencePathTypes;
protected override void OnSelectionChanged()
{
@ -197,6 +204,10 @@ namespace osu.Game.Rulesets.Osu.Edit
for (int i = 0; i < slider.Path.ControlPoints.Count; ++i)
slider.Path.ControlPoints[i].Type = referencePathTypes[i];
// Snap the slider's length to the current beat divisor
// to calculate the final resulting duration / bounding box before the final checks.
slider.SnapTo(positionSnapProvider);
//if sliderhead or sliderend end up outside playfield, revert scaling.
Quad scaledQuad = getSurroundingQuad(new OsuHitObject[] { slider });
(bool xInBounds, bool yInBounds) = isQuadInBounds(scaledQuad);
@ -206,6 +217,9 @@ namespace osu.Game.Rulesets.Osu.Edit
foreach (var point in slider.Path.ControlPoints)
point.Position = oldControlPoints.Dequeue();
// Snap the slider's length again to undo the potentially-invalid length applied by the previous snap.
slider.SnapTo(positionSnapProvider);
}
private void scaleHitObjects(OsuHitObject[] hitObjects, Anchor reference, Vector2 scale)

View File

@ -10,7 +10,6 @@ using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Audio;
using osu.Game.Graphics;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Drawables;
@ -69,7 +68,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
private void load()
{
Origin = Anchor.Centre;
RelativeSizeAxes = Axes.Both;

View File

@ -65,8 +65,8 @@ namespace osu.Game.Rulesets.Osu.Objects
double startTime = StartTime + (float)(i + 1) / totalSpins * Duration;
AddNested(i < SpinsRequired
? new SpinnerTick { StartTime = startTime }
: new SpinnerBonusTick { StartTime = startTime });
? new SpinnerTick { StartTime = startTime, Position = Position }
: new SpinnerBonusTick { StartTime = startTime, Position = Position });
}
}

View File

@ -3,15 +3,13 @@
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Game.Graphics;
using osu.Game.Rulesets.Objects.Drawables;
namespace osu.Game.Rulesets.Osu.Skinning.Default
{
public class SpinnerBackgroundLayer : SpinnerFill
{
[BackgroundDependencyLoader]
private void load(OsuColour colours, DrawableHitObject drawableHitObject)
private void load()
{
Disc.Alpha = 0;
Anchor = Anchor.Centre;

View File

@ -40,7 +40,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
private GameplayState gameplayState { get; set; }
[BackgroundDependencyLoader]
private void load(ISkinSource skin, OsuColour colours)
private void load(ISkinSource skin)
{
var texture = skin.GetTexture("star2");
var starBreakAdditive = skin.GetConfig<OsuSkinColour, Color4>(OsuSkinColour.StarBreakAdditive)?.Value ?? new Color4(255, 182, 193, 255);

View File

@ -12,6 +12,8 @@ namespace osu.Game.Rulesets.Osu.Skinning
CursorExpand,
CursorRotate,
HitCircleOverlayAboveNumber,
// ReSharper disable once IdentifierTypo
HitCircleOverlayAboveNumer, // Some old skins will have this typo
SpinnerFrequencyModulate,
SpinnerNoBlink

View File

@ -58,7 +58,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
private OsuConfigManager config { get; set; }
[BackgroundDependencyLoader(true)]
private void load(OsuConfigManager config, OsuRulesetConfigManager rulesetConfig)
private void load(OsuRulesetConfigManager rulesetConfig)
{
rulesetConfig?.BindWith(OsuRulesetSetting.ShowCursorTrail, showTrail);
}

View File

@ -0,0 +1,36 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System.Linq;
using NUnit.Framework;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Taiko.Objects;
namespace osu.Game.Rulesets.Taiko.Tests
{
public class TestSceneDrumRollJudgements : TestSceneTaikoPlayer
{
[Test]
public void TestStrongDrumRollFullyJudgedOnKilled()
{
AddUntilStep("gameplay finished", () => Player.ScoreProcessor.HasCompleted.Value);
AddAssert("all judgements are misses", () => Player.Results.All(r => r.Type == r.Judgement.MinResult));
}
protected override bool Autoplay => false;
protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) => new Beatmap<TaikoHitObject>
{
BeatmapInfo = { Ruleset = new TaikoRuleset().RulesetInfo },
HitObjects =
{
new DrumRoll
{
StartTime = 1000,
Duration = 1000,
IsStrong = true
}
}
};
}
}

View File

@ -4,7 +4,7 @@
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
<PackageReference Include="NUnit" Version="3.13.2" />
<PackageReference Include="NUnit3TestAdapter" Version="4.1.0" />
<PackageReference Include="NUnit3TestAdapter" Version="4.2.0" />
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
</ItemGroup>
<PropertyGroup Label="Project">

View File

@ -197,6 +197,14 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
ApplyResult(r => r.Type = ParentHitObject.IsHit ? r.Judgement.MaxResult : r.Judgement.MinResult);
}
public override void OnKilled()
{
base.OnKilled();
if (Time.Current > ParentHitObject.HitObject.GetEndTime() && !Judged)
ApplyResult(r => r.Type = r.Judgement.MinResult);
}
public override bool OnPressed(KeyBindingPressEvent<TaikoAction> e) => false;
}
}

View File

@ -5,6 +5,7 @@ using System;
using JetBrains.Annotations;
using osu.Framework.Graphics;
using osu.Framework.Input.Events;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Taiko.Skinning.Default;
using osu.Game.Skinning;
@ -52,6 +53,14 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
ApplyResult(r => r.Type = r.Judgement.MaxResult);
}
public override void OnKilled()
{
base.OnKilled();
if (Time.Current > HitObject.GetEndTime() && !Judged)
ApplyResult(r => r.Type = r.Judgement.MinResult);
}
protected override void UpdateHitStateTransforms(ArmedState state)
{
switch (state)
@ -92,6 +101,14 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
ApplyResult(r => r.Type = ParentHitObject.IsHit ? r.Judgement.MaxResult : r.Judgement.MinResult);
}
public override void OnKilled()
{
base.OnKilled();
if (Time.Current > ParentHitObject.HitObject.GetEndTime() && !Judged)
ApplyResult(r => r.Type = r.Judgement.MinResult);
}
public override bool OnPressed(KeyBindingPressEvent<TaikoAction> e) => false;
}
}

View File

@ -5,7 +5,6 @@ using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics;
using osu.Game.Rulesets.Taiko.Objects;
using osuTK;
@ -19,7 +18,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Default
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
private void load()
{
AccentColour = Hit.COLOUR_CENTRE;
}

View File

@ -5,7 +5,6 @@ using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics;
using osu.Game.Rulesets.Taiko.Objects;
using osuTK;
using osuTK.Graphics;
@ -20,7 +19,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Default
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
private void load()
{
AccentColour = Hit.COLOUR_RIM;
}

View File

@ -7,7 +7,6 @@ using osu.Framework.Audio.Track;
using osu.Framework.Bindables;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Textures;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Graphics.Containers;
using osu.Game.Rulesets.Judgements;
@ -39,7 +38,7 @@ namespace osu.Game.Rulesets.Taiko.UI
}
[BackgroundDependencyLoader(true)]
private void load(TextureStore textures, GameplayState gameplayState)
private void load(GameplayState gameplayState)
{
InternalChildren = new[]
{

View File

@ -46,7 +46,7 @@ namespace osu.Game.Tests.Online.Chat
}
[Test]
public void TestContainsUsernameBetweenInterpunction()
public void TestContainsUsernameBetweenPunctuation()
{
Assert.IsTrue(MessageNotifier.CheckContainsUsername("Hello 'test'-message", "Test"));
}

View File

@ -6,18 +6,24 @@ using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Track;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Textures;
using osu.Framework.Screens;
using osu.Framework.Testing;
using osu.Game.Beatmaps;
using osu.Game.Configuration;
using osu.Game.Database;
using osu.Game.Graphics;
using osu.Game.Graphics.Backgrounds;
using osu.Game.Graphics.Sprites;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Screens;
using osu.Game.Screens.Backgrounds;
using osu.Game.Skinning;
using osu.Game.Storyboards;
using osu.Game.Storyboards.Drawables;
using osu.Game.Tests.Beatmaps;
namespace osu.Game.Tests.Visual.Background
@ -129,6 +135,46 @@ namespace osu.Game.Tests.Visual.Background
AddAssert("top level background reused existing", () => screen.CheckLastLoadChange() == false);
}
[Test]
public void TestBeatmapBackgroundWithStoryboardClockAlwaysUsesCurrentTrack()
{
BackgroundScreenBeatmap nestedScreen = null;
WorkingBeatmap originalWorking = null;
setSupporter(true);
setSourceMode(BackgroundSource.BeatmapWithStoryboard);
AddStep("change beatmap", () => originalWorking = Beatmap.Value = createTestWorkingBeatmapWithStoryboard());
AddAssert("background changed", () => screen.CheckLastLoadChange() == true);
AddUntilStep("wait for beatmap background to be loaded", () => getCurrentBackground()?.GetType() == typeof(BeatmapBackgroundWithStoryboard));
AddStep("start music", () => MusicController.Play());
AddUntilStep("storyboard clock running", () => screen.ChildrenOfType<DrawableStoryboard>().SingleOrDefault()?.Clock.IsRunning == true);
// of note, this needs to be a type that doesn't match BackgroundScreenDefault else it is silently not pushed by the background stack.
AddStep("push new background to stack", () => stack.Push(nestedScreen = new BackgroundScreenBeatmap(Beatmap.Value)));
AddUntilStep("wait for screen to load", () => nestedScreen.IsLoaded && nestedScreen.IsCurrentScreen());
// we're testing a case where scheduling may be used to avoid issues, so ensure the scheduler is no longer running.
AddUntilStep("wait for top level not alive", () => !screen.IsAlive);
AddStep("stop music", () => MusicController.Stop());
AddStep("change beatmap", () => Beatmap.Value = createTestWorkingBeatmapWithStoryboard());
AddStep("change beatmap back", () => Beatmap.Value = originalWorking);
AddStep("restart music", () => MusicController.Play());
AddAssert("top level background hasn't changed yet", () => screen.CheckLastLoadChange() == null);
AddStep("pop screen back to top level", () => screen.MakeCurrent());
AddStep("top level screen is current", () => screen.IsCurrentScreen());
AddAssert("top level background reused existing", () => screen.CheckLastLoadChange() == false);
AddUntilStep("storyboard clock running", () => screen.ChildrenOfType<DrawableStoryboard>().Single().Clock.IsRunning);
AddStep("stop music", () => MusicController.Stop());
AddStep("restore default beatmap", () => Beatmap.SetDefault());
}
[Test]
public void TestBackgroundTypeSwitch()
{
@ -198,6 +244,7 @@ namespace osu.Game.Tests.Visual.Background
});
private WorkingBeatmap createTestWorkingBeatmapWithUniqueBackground() => new UniqueBackgroundTestWorkingBeatmap(Audio);
private WorkingBeatmap createTestWorkingBeatmapWithStoryboard() => new TestWorkingBeatmapWithStoryboard(Audio);
private class TestBackgroundScreenDefault : BackgroundScreenDefault
{
@ -233,6 +280,51 @@ namespace osu.Game.Tests.Visual.Background
protected override Texture GetBackground() => new Texture(1, 1);
}
private class TestWorkingBeatmapWithStoryboard : TestWorkingBeatmap
{
public TestWorkingBeatmapWithStoryboard(AudioManager audioManager)
: base(new Beatmap(), createStoryboard(), audioManager)
{
}
protected override Track GetBeatmapTrack() => new TrackVirtual(100000);
private static Storyboard createStoryboard()
{
var storyboard = new Storyboard();
storyboard.Layers.Last().Add(new TestStoryboardElement());
return storyboard;
}
private class TestStoryboardElement : IStoryboardElementWithDuration
{
public string Path => string.Empty;
public bool IsDrawable => true;
public double StartTime => double.MinValue;
public double EndTime => double.MaxValue;
public Drawable CreateDrawable() => new DrawableTestStoryboardElement();
}
private class DrawableTestStoryboardElement : OsuSpriteText
{
public override bool RemoveWhenNotAlive => false;
public DrawableTestStoryboardElement()
{
Anchor = Origin = Anchor.Centre;
Font = OsuFont.Default.With(size: 32);
Text = "(not started)";
}
protected override void Update()
{
base.Update();
Text = Time.Current.ToString("N2");
}
}
}
private void setCustomSkin()
{
// feign a skin switch. this doesn't do anything except force CurrentSkin to become a LegacySkin.

View File

@ -36,7 +36,7 @@ using osuTK.Graphics;
namespace osu.Game.Tests.Visual.Background
{
[TestFixture]
public class TestSceneUserDimBackgrounds : OsuManualInputManagerTestScene
public class TestSceneUserDimBackgrounds : ScreenTestScene
{
private DummySongSelect songSelect;
private TestPlayerLoader playerLoader;
@ -56,14 +56,12 @@ namespace osu.Game.Tests.Visual.Background
Beatmap.SetDefault();
}
[SetUp]
public virtual void SetUp() => Schedule(() =>
public override void SetUpSteps()
{
var stack = new OsuScreenStack { RelativeSizeAxes = Axes.Both };
Child = stack;
base.SetUpSteps();
stack.Push(songSelect = new DummySongSelect());
});
AddStep("push song select", () => Stack.Push(songSelect = new DummySongSelect()));
}
/// <summary>
/// User settings should always be ignored on song select screen.

View File

@ -6,7 +6,6 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Game.Beatmaps.Drawables.Cards;
using osu.Game.Graphics;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Overlays;
@ -18,7 +17,7 @@ namespace osu.Game.Tests.Visual.Beatmaps
private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue);
[BackgroundDependencyLoader]
private void load(OsuColour colours)
private void load()
{
var beatmapSet = new APIBeatmapSet
{

View File

@ -4,6 +4,7 @@
using System.Linq;
using NUnit.Framework;
using osu.Framework.Testing;
using osu.Framework.Utils;
using osu.Game.Beatmaps;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Edit;
@ -85,11 +86,17 @@ namespace osu.Game.Tests.Visual.Editing
AddAssert("is one object", () => EditorBeatmap.HitObjects.Count == 1);
Slider slider = null;
AddStep("retrieve slider", () => slider = (Slider)EditorBeatmap.HitObjects.Single());
AddAssert("path matches", () =>
{
var path = ((Slider)EditorBeatmap.HitObjects.Single()).Path;
var path = slider.Path;
return path.ControlPoints.Count == 2 && path.ControlPoints.SequenceEqual(addedObject.Path.ControlPoints);
});
// see `HitObject.control_point_leniency`.
AddAssert("sample control point has correct time", () => Precision.AlmostEquals(slider.SampleControlPoint.Time, slider.GetEndTime(), 1));
AddAssert("difficulty control point has correct time", () => slider.DifficultyControlPoint.Time == slider.StartTime);
}
[Test]

View File

@ -25,7 +25,7 @@ namespace osu.Game.Tests.Visual.Gameplay
protected OsuConfigManager Config { get; private set; }
[BackgroundDependencyLoader]
private void load(RulesetStore rulesets)
private void load()
{
Dependencies.Cache(Config = new OsuConfigManager(LocalStorage));
Config.GetBindable<double>(OsuSetting.DimLevel).Value = 1.0;

View File

@ -0,0 +1,88 @@
// 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.Allocation;
using osu.Framework.Extensions;
using osu.Framework.Input.Bindings;
using osu.Framework.Testing;
using osu.Game.Database;
using osu.Game.Graphics.UserInterface;
using osu.Game.Input.Bindings;
using osu.Game.Overlays.Settings.Sections.Input;
using osu.Game.Screens.Play;
using osu.Game.Screens.Select;
using osu.Game.Tests.Beatmaps.IO;
using osuTK.Input;
namespace osu.Game.Tests.Visual.Navigation
{
public class TestSceneChangeAndUseGameplayBindings : OsuGameTestScene
{
[Test]
public void TestGameplayKeyBindings()
{
AddAssert("databased key is default", () => firstOsuRulesetKeyBindings.KeyCombination.Keys.SequenceEqual(new[] { InputKey.Z }));
AddStep("open settings", () => { Game.Settings.Show(); });
// Until step requires as settings has a delayed load.
AddUntilStep("wait for button", () => configureBindingsButton?.Enabled.Value == true);
AddStep("scroll to section", () => Game.Settings.SectionsContainer.ScrollTo(configureBindingsButton));
AddStep("press button", () => configureBindingsButton.TriggerClick());
AddUntilStep("wait for panel", () => keyBindingPanel?.IsLoaded == true);
AddUntilStep("wait for osu subsection", () => osuBindingSubsection?.IsLoaded == true);
AddStep("scroll to section", () => keyBindingPanel.SectionsContainer.ScrollTo(osuBindingSubsection));
AddWaitStep("wait for scroll to end", 3);
AddStep("start rebinding first osu! key", () =>
{
var button = osuBindingSubsection.ChildrenOfType<KeyBindingRow>().First();
InputManager.MoveMouseTo(button);
InputManager.Click(MouseButton.Left);
});
AddStep("Press 's'", () => InputManager.Key(Key.S));
AddUntilStep("wait for database updated", () => firstOsuRulesetKeyBindings.KeyCombination.Keys.SequenceEqual(new[] { InputKey.S }));
AddStep("close settings", () => Game.Settings.Hide());
AddStep("import beatmap", () => ImportBeatmapTest.LoadQuickOszIntoOsu(Game).WaitSafely());
PushAndConfirm(() => new PlaySongSelect());
AddStep("enter gameplay", () => InputManager.Key(Key.Enter));
AddUntilStep("wait for gameplay", () => player?.IsBreakTime.Value == false);
AddStep("press 'z'", () => InputManager.Key(Key.Z));
AddAssert("key counter didn't increase", () => keyCounter.CountPresses == 0);
AddStep("press 's'", () => InputManager.Key(Key.S));
AddAssert("key counter did increase", () => keyCounter.CountPresses == 1);
}
private KeyBindingsSubsection osuBindingSubsection => keyBindingPanel
.ChildrenOfType<VariantBindingsSubsection>()
.FirstOrDefault(s => s.Ruleset.ShortName == "osu");
private OsuButton configureBindingsButton => Game.Settings
.ChildrenOfType<BindingSettings>().SingleOrDefault()?
.ChildrenOfType<OsuButton>()?
.First(b => b.Text.ToString() == "Configure");
private KeyBindingPanel keyBindingPanel => Game.Settings
.ChildrenOfType<KeyBindingPanel>().SingleOrDefault();
private RealmKeyBinding firstOsuRulesetKeyBindings => Game.Dependencies
.Get<RealmContextFactory>().Context
.All<RealmKeyBinding>()
.AsEnumerable()
.First(k => k.RulesetName == "osu" && k.ActionInt == 0);
private Player player => Game.ScreenStack.CurrentScreen as Player;
private KeyCounter keyCounter => player.ChildrenOfType<KeyCounter>().First();
}
}

View File

@ -251,8 +251,9 @@ namespace osu.Game.Tests.Visual.Navigation
[Test]
public void TestModSelectInput()
{
TestPlaySongSelect songSelect = null;
AddUntilStep("Wait for toolbar to load", () => Game.Toolbar.IsLoaded);
TestPlaySongSelect songSelect = null;
PushAndConfirm(() => songSelect = new TestPlaySongSelect());
AddStep("Show mods overlay", () => songSelect.ModSelectOverlay.Show());
@ -272,8 +273,9 @@ namespace osu.Game.Tests.Visual.Navigation
[Test]
public void TestBeatmapOptionsInput()
{
TestPlaySongSelect songSelect = null;
AddUntilStep("Wait for toolbar to load", () => Game.Toolbar.IsLoaded);
TestPlaySongSelect songSelect = null;
PushAndConfirm(() => songSelect = new TestPlaySongSelect());
AddStep("Show options overlay", () => songSelect.BeatmapOptionsOverlay.Show());
@ -293,6 +295,8 @@ namespace osu.Game.Tests.Visual.Navigation
[Test]
public void TestSettingsViaHotkeyFromMainMenu()
{
AddUntilStep("Wait for toolbar to load", () => Game.Toolbar.IsLoaded);
AddAssert("toolbar not displayed", () => Game.Toolbar.State.Value == Visibility.Hidden);
AddStep("press settings hotkey", () =>
@ -308,10 +312,11 @@ namespace osu.Game.Tests.Visual.Navigation
[Test]
public void TestToolbarHiddenByUser()
{
AddStep("Enter menu", () => InputManager.Key(Key.Enter));
AddUntilStep("Wait for toolbar to load", () => Game.Toolbar.IsLoaded);
AddStep("Enter menu", () => InputManager.Key(Key.Enter));
AddUntilStep("Toolbar is visible", () => Game.Toolbar.State.Value == Visibility.Visible);
AddStep("Hide toolbar", () =>
{
InputManager.PressKey(Key.ControlLeft);

View File

@ -1,11 +1,15 @@
// 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 System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Testing;
using osu.Framework.Utils;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests.Responses;
@ -24,10 +28,11 @@ namespace osu.Game.Tests.Visual.Online
[Cached]
private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue);
public TestSceneScoresContainer()
{
TestScoresContainer scoresContainer;
private TestScoresContainer scoresContainer;
[SetUpSteps]
public void SetUp() => Schedule(() =>
{
Child = new Container
{
Anchor = Anchor.TopCentre,
@ -41,16 +46,110 @@ namespace osu.Game.Tests.Visual.Online
RelativeSizeAxes = Axes.Both,
Colour = Color4.Black,
},
scoresContainer = new TestScoresContainer(),
scoresContainer = new TestScoresContainer
{
Beatmap = { Value = CreateAPIBeatmap() }
}
}
};
});
var allScores = new APIScoresCollection
[Test]
public void TestNoUserBest()
{
AddStep("Scores with no user best", () =>
{
var allScores = createScores();
allScores.UserScore = null;
scoresContainer.Scores = allScores;
});
AddUntilStep("wait for scores displayed", () => scoresContainer.ChildrenOfType<ScoreTableRowBackground>().Any());
AddAssert("no user best displayed", () => scoresContainer.ChildrenOfType<DrawableTopScore>().Count() == 1);
AddStep("Load null scores", () => scoresContainer.Scores = null);
AddUntilStep("wait for scores not displayed", () => !scoresContainer.ChildrenOfType<ScoreTableRowBackground>().Any());
AddAssert("no best score displayed", () => !scoresContainer.ChildrenOfType<DrawableTopScore>().Any());
AddStep("Load only one score", () =>
{
var allScores = createScores();
allScores.Scores.RemoveRange(1, allScores.Scores.Count - 1);
scoresContainer.Scores = allScores;
});
AddUntilStep("wait for scores not displayed", () => scoresContainer.ChildrenOfType<ScoreTableRowBackground>().Count() == 1);
AddAssert("no best score displayed", () => scoresContainer.ChildrenOfType<DrawableTopScore>().Count() == 1);
}
[Test]
public void TestUserBest()
{
AddStep("Load scores with personal best", () =>
{
var allScores = createScores();
allScores.UserScore = createUserBest();
scoresContainer.Scores = allScores;
});
AddUntilStep("wait for scores displayed", () => scoresContainer.ChildrenOfType<ScoreTableRowBackground>().Any());
AddAssert("best score displayed", () => scoresContainer.ChildrenOfType<DrawableTopScore>().Count() == 2);
AddStep("Load scores with personal best (null position)", () =>
{
var allScores = createScores();
var userBest = createUserBest();
userBest.Position = null;
allScores.UserScore = userBest;
scoresContainer.Scores = allScores;
});
AddUntilStep("wait for scores displayed", () => scoresContainer.ChildrenOfType<ScoreTableRowBackground>().Any());
AddAssert("best score displayed", () => scoresContainer.ChildrenOfType<DrawableTopScore>().Count() == 2);
AddStep("Load scores with personal best (first place)", () =>
{
var allScores = createScores();
allScores.UserScore = new APIScoreWithPosition
{
Score = allScores.Scores.First(),
Position = 1,
};
scoresContainer.Scores = allScores;
});
AddUntilStep("wait for scores displayed", () => scoresContainer.ChildrenOfType<ScoreTableRowBackground>().Any());
AddAssert("best score displayed", () => scoresContainer.ChildrenOfType<DrawableTopScore>().Count() == 1);
AddStep("Scores with no user best", () =>
{
var allScores = createScores();
allScores.UserScore = null;
scoresContainer.Scores = allScores;
});
AddUntilStep("best score not displayed", () => scoresContainer.ChildrenOfType<DrawableTopScore>().Count() == 1);
}
private int onlineID = 1;
private APIScoresCollection createScores()
{
var scores = new APIScoresCollection
{
Scores = new List<APIScore>
{
new APIScore
{
Date = DateTimeOffset.Now,
OnlineID = onlineID++,
User = new APIUser
{
Id = 6602580,
@ -76,6 +175,8 @@ namespace osu.Game.Tests.Visual.Online
},
new APIScore
{
Date = DateTimeOffset.Now,
OnlineID = onlineID++,
User = new APIUser
{
Id = 4608074,
@ -100,6 +201,8 @@ namespace osu.Game.Tests.Visual.Online
},
new APIScore
{
Date = DateTimeOffset.Now,
OnlineID = onlineID++,
User = new APIUser
{
Id = 1014222,
@ -123,6 +226,8 @@ namespace osu.Game.Tests.Visual.Online
},
new APIScore
{
Date = DateTimeOffset.Now,
OnlineID = onlineID++,
User = new APIUser
{
Id = 1541390,
@ -145,6 +250,8 @@ namespace osu.Game.Tests.Visual.Online
},
new APIScore
{
Date = DateTimeOffset.Now,
OnlineID = onlineID++,
User = new APIUser
{
Id = 7151382,
@ -164,10 +271,26 @@ namespace osu.Game.Tests.Visual.Online
}
};
var myBestScore = new APIScoreWithPosition
foreach (var s in scores.Scores)
{
s.Statistics = new Dictionary<string, int>
{
{ "count_300", RNG.Next(2000) },
{ "count_100", RNG.Next(2000) },
{ "count_50", RNG.Next(2000) },
{ "count_miss", RNG.Next(2000) }
};
}
return scores;
}
private APIScoreWithPosition createUserBest() => new APIScoreWithPosition
{
Score = new APIScore
{
Date = DateTimeOffset.Now,
OnlineID = onlineID++,
User = new APIUser
{
Id = 7151382,
@ -187,92 +310,6 @@ namespace osu.Game.Tests.Visual.Online
Position = 1337,
};
var myBestScoreWithNullPosition = new APIScoreWithPosition
{
Score = new APIScore
{
User = new APIUser
{
Id = 7151382,
Username = @"Mayuri Hana",
Country = new Country
{
FullName = @"Thailand",
FlagName = @"TH",
},
},
Rank = ScoreRank.D,
PP = 160,
MaxCombo = 1234,
TotalScore = 123456,
Accuracy = 0.6543,
},
Position = null,
};
var oneScore = new APIScoresCollection
{
Scores = new List<APIScore>
{
new APIScore
{
User = new APIUser
{
Id = 6602580,
Username = @"waaiiru",
Country = new Country
{
FullName = @"Spain",
FlagName = @"ES",
},
},
Mods = new[]
{
new APIMod { Acronym = new OsuModDoubleTime().Acronym },
new APIMod { Acronym = new OsuModHidden().Acronym },
new APIMod { Acronym = new OsuModFlashlight().Acronym },
new APIMod { Acronym = new OsuModHardRock().Acronym },
},
Rank = ScoreRank.XH,
PP = 200,
MaxCombo = 1234,
TotalScore = 1234567890,
Accuracy = 1,
}
}
};
foreach (var s in allScores.Scores)
{
s.Statistics = new Dictionary<string, int>
{
{ "count_300", RNG.Next(2000) },
{ "count_100", RNG.Next(2000) },
{ "count_50", RNG.Next(2000) },
{ "count_miss", RNG.Next(2000) }
};
}
AddStep("Load all scores", () =>
{
allScores.UserScore = null;
scoresContainer.Scores = allScores;
});
AddStep("Load null scores", () => scoresContainer.Scores = null);
AddStep("Load only one score", () => scoresContainer.Scores = oneScore);
AddStep("Load scores with my best", () =>
{
allScores.UserScore = myBestScore;
scoresContainer.Scores = allScores;
});
AddStep("Load scores with null my best position", () =>
{
allScores.UserScore = myBestScoreWithNullPosition;
scoresContainer.Scores = allScores;
});
}
private class TestScoresContainer : ScoresContainer
{
public new APIScoresCollection Scores

View File

@ -20,8 +20,8 @@ namespace osu.Game.Tests.Visual.Online
private readonly Bindable<UserActivity> activity = new Bindable<UserActivity>();
private readonly Bindable<UserStatus> status = new Bindable<UserStatus>();
private UserGridPanel peppy;
private TestUserListPanel evast;
private UserGridPanel boundPanel1;
private TestUserListPanel boundPanel2;
[Resolved]
private IRulesetStore rulesetStore { get; set; }
@ -29,8 +29,6 @@ namespace osu.Game.Tests.Visual.Online
[SetUp]
public void SetUp() => Schedule(() =>
{
UserGridPanel flyte;
activity.Value = null;
status.Value = null;
@ -56,14 +54,15 @@ namespace osu.Game.Tests.Visual.Online
Colour = "99EB47",
CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c3.jpg",
}),
flyte = new UserGridPanel(new APIUser
new UserGridPanel(new APIUser
{
Username = @"flyte",
Id = 3103765,
Country = new Country { FlagName = @"JP" },
CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c6.jpg"
CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c6.jpg",
Status = { Value = new UserStatusOnline() }
}) { Width = 300 },
peppy = new UserGridPanel(new APIUser
boundPanel1 = new UserGridPanel(new APIUser
{
Username = @"peppy",
Id = 2,
@ -72,7 +71,7 @@ namespace osu.Game.Tests.Visual.Online
IsSupporter = true,
SupportLevel = 3,
}) { Width = 300 },
evast = new TestUserListPanel(new APIUser
boundPanel2 = new TestUserListPanel(new APIUser
{
Username = @"Evast",
Id = 8195163,
@ -84,13 +83,11 @@ namespace osu.Game.Tests.Visual.Online
},
};
flyte.Status.Value = new UserStatusOnline();
boundPanel1.Status.BindTo(status);
boundPanel1.Activity.BindTo(activity);
peppy.Status.BindTo(status);
peppy.Activity.BindTo(activity);
evast.Status.BindTo(status);
evast.Activity.BindTo(activity);
boundPanel2.Status.BindTo(status);
boundPanel2.Activity.BindTo(activity);
});
[Test]
@ -121,14 +118,14 @@ namespace osu.Game.Tests.Visual.Online
[Test]
public void TestUserActivityChange()
{
AddAssert("visit message is visible", () => evast.LastVisitMessage.IsPresent);
AddAssert("visit message is visible", () => boundPanel2.LastVisitMessage.IsPresent);
AddStep("set online status", () => status.Value = new UserStatusOnline());
AddAssert("visit message is not visible", () => !evast.LastVisitMessage.IsPresent);
AddAssert("visit message is not visible", () => !boundPanel2.LastVisitMessage.IsPresent);
AddStep("set choosing activity", () => activity.Value = new UserActivity.ChoosingBeatmap());
AddStep("set offline status", () => status.Value = new UserStatusOffline());
AddAssert("visit message is visible", () => evast.LastVisitMessage.IsPresent);
AddAssert("visit message is visible", () => boundPanel2.LastVisitMessage.IsPresent);
AddStep("set online status", () => status.Value = new UserStatusOnline());
AddAssert("visit message is not visible", () => !evast.LastVisitMessage.IsPresent);
AddAssert("visit message is not visible", () => !boundPanel2.LastVisitMessage.IsPresent);
}
private UserActivity soloGameStatusForRuleset(int rulesetId) => new UserActivity.InSoloGame(null, rulesetStore.GetRuleset(rulesetId));

View File

@ -18,6 +18,7 @@ using osu.Game.Rulesets;
using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Screens.OnlinePlay.Components;
using osu.Game.Screens.OnlinePlay.Match.Components;
using osu.Game.Screens.OnlinePlay.Playlists;
using osu.Game.Screens.Play;
using osu.Game.Tests.Beatmaps;
@ -71,6 +72,8 @@ namespace osu.Game.Tests.Visual.Playlists
AddUntilStep("Progress details are hidden", () => match.ChildrenOfType<RoomLocalUserInfo>().FirstOrDefault()?.Parent.Alpha == 0);
AddUntilStep("Leaderboard shows two aggregate scores", () => match.ChildrenOfType<MatchLeaderboardScore>().Count(s => s.ScoreText.Text != "0") == 2);
AddStep("start match", () => match.ChildrenOfType<PlaylistsReadyButton>().First().TriggerClick());
AddUntilStep("player loader loaded", () => Stack.CurrentScreen is PlayerLoader);
}

View File

@ -203,7 +203,7 @@ namespace osu.Game.Tests.Visual.Ranking
{
DelayedFetchResultsScreen screen = null;
var tcs = new TaskCompletionSource();
var tcs = new TaskCompletionSource<bool>();
AddStep("load results", () => Child = new TestResultsContainer(screen = new DelayedFetchResultsScreen(TestResources.CreateTestScoreInfo(), tcs.Task)));
@ -218,7 +218,7 @@ namespace osu.Game.Tests.Visual.Ranking
AddAssert("no fetch yet", () => !screen.FetchCompleted);
AddStep("allow fetch", () => tcs.SetResult());
AddStep("allow fetch", () => tcs.SetResult(true));
AddUntilStep("wait for fetch", () => screen.FetchCompleted);
AddAssert("expanded panel still on screen", () => this.ChildrenOfType<ScorePanel>().Single(p => p.State == PanelState.Expanded).ScreenSpaceDrawQuad.TopLeft.X > 0);

View File

@ -14,7 +14,6 @@ using osu.Game.Graphics.Containers;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Rulesets;
using osu.Game.Tests.Beatmaps.IO;
using osuTK;
@ -28,7 +27,7 @@ namespace osu.Game.Tests.Visual.UserInterface
private IAPIProvider api;
[BackgroundDependencyLoader]
private void load(OsuGameBase osu, IAPIProvider api, RulesetStore rulesets)
private void load(OsuGameBase osu, IAPIProvider api)
{
this.api = api;

View File

@ -6,7 +6,7 @@
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
<PackageReference Include="Nito.AsyncEx" Version="5.1.2" />
<PackageReference Include="NUnit" Version="3.13.2" />
<PackageReference Include="NUnit3TestAdapter" Version="4.1.0" />
<PackageReference Include="NUnit3TestAdapter" Version="4.2.0" />
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
<PackageReference Include="Moq" Version="4.16.1" />
</ItemGroup>

View File

@ -2,14 +2,13 @@
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Allocation;
using osu.Framework.Platform;
namespace osu.Game.Tournament.Tests
{
public class TestSceneTournamentSceneManager : TournamentTestScene
{
[BackgroundDependencyLoader]
private void load(Storage storage)
private void load()
{
Add(new TournamentSceneManager());
}

View File

@ -7,7 +7,7 @@
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
<PackageReference Include="NUnit" Version="3.13.2" />
<PackageReference Include="NUnit3TestAdapter" Version="4.1.0" />
<PackageReference Include="NUnit3TestAdapter" Version="4.2.0" />
</ItemGroup>
<PropertyGroup Label="Project">
<OutputType>WinExe</OutputType>

View File

@ -4,7 +4,6 @@
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
@ -22,7 +21,7 @@ namespace osu.Game.Tournament.Components
}
[BackgroundDependencyLoader]
private void load(TextureStore textures)
private void load()
{
if (team == null) return;

View File

@ -5,7 +5,6 @@ using JetBrains.Annotations;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Textures;
using osu.Game.Graphics;
using osu.Game.Tournament.Models;
@ -33,7 +32,7 @@ namespace osu.Game.Tournament.Components
}
[BackgroundDependencyLoader]
private void load(TextureStore textures)
private void load()
{
if (Team == null) return;

View File

@ -9,7 +9,6 @@ using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Textures;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Drawables;
using osu.Game.Graphics;
@ -45,7 +44,7 @@ namespace osu.Game.Tournament.Components
}
[BackgroundDependencyLoader]
private void load(LadderInfo ladder, TextureStore textures)
private void load(LadderInfo ladder)
{
currentMatch.BindValueChanged(matchChanged);
currentMatch.BindTo(ladder.CurrentMatch);

View File

@ -12,7 +12,6 @@ using osu.Game.Online.API;
using osu.Game.Online.API.Requests;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Overlays.Settings;
using osu.Game.Rulesets;
using osu.Game.Tournament.Components;
using osu.Game.Tournament.Models;
using osuTK;
@ -218,7 +217,7 @@ namespace osu.Game.Tournament.Screens.Editors
}
[BackgroundDependencyLoader]
private void load(RulesetStore rulesets)
private void load()
{
beatmapId.Value = Model.ID;
beatmapId.BindValueChanged(id =>

View File

@ -12,7 +12,6 @@ using osu.Game.Online.API;
using osu.Game.Online.API.Requests;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Overlays.Settings;
using osu.Game.Rulesets;
using osu.Game.Tournament.Components;
using osu.Game.Tournament.Models;
using osuTK;
@ -220,7 +219,7 @@ namespace osu.Game.Tournament.Screens.Editors
}
[BackgroundDependencyLoader]
private void load(RulesetStore rulesets)
private void load()
{
beatmapId.Value = Model.ID;
beatmapId.BindValueChanged(id =>

View File

@ -11,7 +11,6 @@ using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
using osu.Game.Tournament.IPC;
using osu.Game.Tournament.Models;
using osuTK;
namespace osu.Game.Tournament.Screens.Gameplay.Components
@ -91,7 +90,7 @@ namespace osu.Game.Tournament.Screens.Gameplay.Components
}
[BackgroundDependencyLoader]
private void load(LadderInfo ladder, MatchIPCInfo ipc)
private void load(MatchIPCInfo ipc)
{
score1.BindValueChanged(_ => updateScores());
score1.BindTo(ipc.Score1);

View File

@ -6,7 +6,6 @@ using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Platform;
using osu.Framework.Threading;
using osu.Game.Graphics.UserInterface;
using osu.Game.Overlays.Settings;
@ -37,7 +36,7 @@ namespace osu.Game.Tournament.Screens.Gameplay
private Drawable chroma;
[BackgroundDependencyLoader]
private void load(LadderInfo ladder, MatchIPCInfo ipc, Storage storage)
private void load(LadderInfo ladder, MatchIPCInfo ipc)
{
this.ipc = ipc;

View File

@ -81,7 +81,7 @@ namespace osu.Game.Tournament.Screens.Ladder.Components
}
[BackgroundDependencyLoader(true)]
private void load(OsuColour colours, LadderEditorScreen ladderEditor)
private void load(LadderEditorScreen ladderEditor)
{
this.ladderEditor = ladderEditor;

View File

@ -9,8 +9,6 @@ using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Lines;
using osu.Framework.Platform;
using osu.Game.Graphics;
using osu.Game.Tournament.Components;
using osu.Game.Tournament.Models;
using osu.Game.Tournament.Screens.Editors;
@ -30,7 +28,7 @@ namespace osu.Game.Tournament.Screens.Ladder
protected Container Content;
[BackgroundDependencyLoader]
private void load(OsuColour colours, Storage storage)
private void load()
{
normalPathColour = Color4Extensions.FromHex("#66D1FF");
losersPathColour = Color4Extensions.FromHex("#FFC700");

View File

@ -8,7 +8,6 @@ using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Platform;
using osu.Game.Graphics;
using osu.Game.Tournament.Components;
using osu.Game.Tournament.Models;
@ -25,7 +24,7 @@ namespace osu.Game.Tournament.Screens.Schedule
private LadderInfo ladder;
[BackgroundDependencyLoader]
private void load(LadderInfo ladder, Storage storage)
private void load(LadderInfo ladder)
{
this.ladder = ladder;

View File

@ -8,7 +8,6 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
using osu.Framework.Platform;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Tournament.Components;
@ -25,7 +24,7 @@ namespace osu.Game.Tournament.Screens.TeamIntro
private readonly Bindable<TournamentTeam> currentTeam = new Bindable<TournamentTeam>();
[BackgroundDependencyLoader]
private void load(Storage storage)
private void load()
{
RelativeSizeAxes = Axes.Both;

View File

@ -5,7 +5,6 @@ using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Platform;
using osu.Game.Tournament.Components;
using osu.Game.Tournament.Models;
using osuTK;
@ -17,7 +16,7 @@ namespace osu.Game.Tournament.Screens.TeamIntro
private Container mainContainer;
[BackgroundDependencyLoader]
private void load(Storage storage)
private void load()
{
RelativeSizeAxes = Axes.Both;

View File

@ -5,7 +5,6 @@ using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Platform;
using osu.Game.Graphics;
using osu.Game.Tournament.Components;
using osu.Game.Tournament.Models;
@ -23,7 +22,7 @@ namespace osu.Game.Tournament.Screens.TeamWin
private TourneyVideo redWinVideo;
[BackgroundDependencyLoader]
private void load(LadderInfo ladder, Storage storage)
private void load()
{
RelativeSizeAxes = Axes.Both;

View File

@ -7,11 +7,9 @@ using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Platform;
using osu.Framework.Threading;
using osu.Game.Graphics;
using osu.Game.Tournament.Components;
using osu.Game.Tournament.Models;
using osu.Game.Tournament.Screens;
using osu.Game.Tournament.Screens.Drawings;
using osu.Game.Tournament.Screens.Editors;
@ -52,7 +50,7 @@ namespace osu.Game.Tournament
}
[BackgroundDependencyLoader]
private void load(LadderInfo ladder, Storage storage)
private void load()
{
InternalChildren = new Drawable[]
{

View File

@ -80,7 +80,7 @@ namespace osu.Game.Collections
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
private void load()
{
Children = new Drawable[]
{

View File

@ -2,6 +2,7 @@
// See the LICENCE file in the repository root for full licence text.
using System;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading;
@ -188,10 +189,17 @@ namespace osu.Game.Database
private RealmConfiguration getConfiguration()
{
// This is currently the only usage of temporary files at the osu! side.
// If we use the temporary folder in more situations in the future, this should be moved to a higher level (helper method or OsuGameBase).
string tempPathLocation = Path.Combine(Path.GetTempPath(), @"lazer");
if (!Directory.Exists(tempPathLocation))
Directory.CreateDirectory(tempPathLocation);
return new RealmConfiguration(storage.GetFullPath(Filename, true))
{
SchemaVersion = schema_version,
MigrationCallback = onMigration,
FallbackPipePath = tempPathLocation,
};
}

View File

@ -1,20 +1,29 @@
// 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.
#nullable enable
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Timing;
using osu.Game.Beatmaps;
using osu.Game.Overlays;
using osu.Game.Storyboards.Drawables;
namespace osu.Game.Graphics.Backgrounds
{
public class BeatmapBackgroundWithStoryboard : BeatmapBackground
{
private readonly InterpolatingFramedClock storyboardClock;
[Resolved(CanBeNull = true)]
private MusicController? musicController { get; set; }
public BeatmapBackgroundWithStoryboard(WorkingBeatmap beatmap, string fallbackTextureName = "Backgrounds/bg1")
: base(beatmap, fallbackTextureName)
{
storyboardClock = new InterpolatingFramedClock();
}
[BackgroundDependencyLoader]
@ -30,8 +39,40 @@ namespace osu.Game.Graphics.Backgrounds
{
RelativeSizeAxes = Axes.Both,
Volume = { Value = 0 },
Child = new DrawableStoryboard(Beatmap.Storyboard) { Clock = new InterpolatingFramedClock(Beatmap.Track) }
Child = new DrawableStoryboard(Beatmap.Storyboard) { Clock = storyboardClock }
}, AddInternal);
}
protected override void LoadComplete()
{
base.LoadComplete();
if (musicController != null)
musicController.TrackChanged += onTrackChanged;
updateStoryboardClockSource(Beatmap);
}
private void onTrackChanged(WorkingBeatmap newBeatmap, TrackChangeDirection _) => updateStoryboardClockSource(newBeatmap);
private void updateStoryboardClockSource(WorkingBeatmap newBeatmap)
{
if (newBeatmap != Beatmap)
return;
// `MusicController` will sometimes reload the track, even when the working beatmap technically hasn't changed.
// ensure that the storyboard's clock is always using the latest track instance.
storyboardClock.ChangeSource(newBeatmap.Track);
// more often than not, the previous source track's time will be in the future relative to the new source track.
// explicitly process a single frame so that `InterpolatingFramedClock`'s interpolation logic is bypassed
// and the storyboard clock is correctly rewound to the source track's time exactly.
storyboardClock.ProcessFrame();
}
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
if (musicController != null)
musicController.TrackChanged -= onTrackChanged;
}
}
}

View File

@ -7,14 +7,13 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.OpenGL.Vertices;
using osu.Framework.Graphics.Shaders;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
namespace osu.Game.Graphics.Sprites
{
public class LogoAnimation : Sprite
{
[BackgroundDependencyLoader]
private void load(ShaderManager shaders, TextureStore textures)
private void load(ShaderManager shaders)
{
TextureShader = shaders.Load(VertexShaderDescriptor.TEXTURE_2, @"LogoAnimation");
RoundedTextureShader = shaders.Load(VertexShaderDescriptor.TEXTURE_2, @"LogoAnimation"); // Masking isn't supported for now

View File

@ -2,7 +2,6 @@
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
@ -30,7 +29,7 @@ namespace osu.Game.Graphics.UserInterface
}
[BackgroundDependencyLoader]
private void load(AudioManager audio)
private void load()
{
BackgroundColour = Color4.Transparent;
BackgroundColourHover = Color4Extensions.FromHex(@"172023");

View File

@ -2,7 +2,6 @@
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Bindables;
using osu.Framework.Graphics.Containers;
using osu.Framework.Input.Events;
@ -18,7 +17,7 @@ namespace osu.Game.Graphics.UserInterface
private Bindable<double?> lastPlaybackTime;
[BackgroundDependencyLoader]
private void load(AudioManager audio, SessionStatics statics)
private void load(SessionStatics statics)
{
lastPlaybackTime = statics.GetBindable<double?>(Static.LastHoverSoundPlaybackTime);
}

View File

@ -3,7 +3,6 @@
using osuTK.Graphics;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Effects;
@ -41,7 +40,7 @@ namespace osu.Game.Graphics.UserInterface
}
[BackgroundDependencyLoader]
private void load(OsuColour colours, AudioManager audio)
private void load(OsuColour colours)
{
BackgroundColour = colours.ContextMenuGray;
}

View File

@ -16,7 +16,7 @@ namespace osu.Game.Graphics.UserInterface
private Sample sampleClose;
[BackgroundDependencyLoader]
private void load(OsuColour colours, AudioManager audio)
private void load(AudioManager audio)
{
sampleClick = audio.Samples.Get($@"UI/{HoverSampleSet.Default.GetDescription()}-select");
sampleOpen = audio.Samples.Get(@"UI/dropdown-open");

View File

@ -44,6 +44,11 @@ namespace osu.Game.Localisation
/// </summary>
public static LocalisableString ClearAllCaches => new TranslatableString(getKey(@"clear_all_caches"), @"Clear all caches");
/// <summary>
/// "Compact realm"
/// </summary>
public static LocalisableString CompactRealm => new TranslatableString(getKey(@"compact_realm"), @"Compact realm");
private static string getKey(string key) => $"{prefix}:{key}";
}
}

View File

@ -22,6 +22,8 @@ namespace osu.Game.Online.API.Requests
public enum RecentActivityType
{
Achievement,
// ReSharper disable once IdentifierTypo
BeatmapPlaycount,
BeatmapsetApprove,
BeatmapsetDelete,

View File

@ -90,13 +90,16 @@ namespace osu.Game.Online.Chat
{
// Polling will eventually be replaced with websocket, but let's avoid doing these background operations as much as possible for now.
// The only loss will be delayed PM/message highlight notifications.
int millisecondsBetweenPolls = HighPollRate.Value ? 1000 : 60000;
if (HighPollRate.Value)
TimeBetweenPolls.Value = 1000;
else if (!isIdle.Value)
TimeBetweenPolls.Value = 60000;
else
TimeBetweenPolls.Value = 600000;
if (isIdle.Value)
millisecondsBetweenPolls *= 10;
if (TimeBetweenPolls.Value != millisecondsBetweenPolls)
{
TimeBetweenPolls.Value = millisecondsBetweenPolls;
Logger.Log($"Chat is now polling every {TimeBetweenPolls.Value} ms");
}
}
/// <summary>

View File

@ -25,7 +25,7 @@ namespace osu.Game.Online.Chat
protected readonly ChatTextBox TextBox;
protected ChannelManager ChannelManager;
private ChannelManager channelManager;
private StandAloneDrawableChannel drawableChannel;
@ -80,7 +80,7 @@ namespace osu.Game.Online.Chat
[BackgroundDependencyLoader(true)]
private void load(ChannelManager manager)
{
ChannelManager ??= manager;
channelManager ??= manager;
}
protected virtual StandAloneDrawableChannel CreateDrawableChannel(Channel channel) =>
@ -94,9 +94,9 @@ namespace osu.Game.Online.Chat
return;
if (text[0] == '/')
ChannelManager?.PostCommand(text.Substring(1), Channel.Value);
channelManager?.PostCommand(text.Substring(1), Channel.Value);
else
ChannelManager?.PostMessage(text, target: Channel.Value);
channelManager?.PostMessage(text, target: Channel.Value);
TextBox.Text = string.Empty;
}

View File

@ -53,7 +53,9 @@ namespace osu.Game.Online.Leaderboards
private Drawable avatar;
private Drawable scoreRank;
private OsuSpriteText nameLabel;
private GlowingSpriteText scoreLabel;
public GlowingSpriteText ScoreText { get; private set; }
private Container flagBadgeContainer;
private FillFlowContainer<ModIcon> modsContainer;
@ -198,7 +200,7 @@ namespace osu.Game.Online.Leaderboards
Spacing = new Vector2(5f, 0f),
Children = new Drawable[]
{
scoreLabel = new GlowingSpriteText
ScoreText = new GlowingSpriteText
{
TextColour = Color4.White,
GlowColour = Color4Extensions.FromHex(@"83ccfa"),
@ -240,7 +242,7 @@ namespace osu.Game.Online.Leaderboards
public override void Show()
{
foreach (var d in new[] { avatar, nameLabel, scoreLabel, scoreRank, flagBadgeContainer, modsContainer }.Concat(statisticsLabels))
foreach (var d in new[] { avatar, nameLabel, ScoreText, scoreRank, flagBadgeContainer, modsContainer }.Concat(statisticsLabels))
d.FadeOut();
Alpha = 0;
@ -262,7 +264,7 @@ namespace osu.Game.Online.Leaderboards
using (BeginDelayedSequence(250))
{
scoreLabel.FadeIn(200);
ScoreText.FadeIn(200);
scoreRank.FadeIn(200);
using (BeginDelayedSequence(50))

View File

@ -154,6 +154,8 @@ namespace osu.Game
private MainMenu menuScreen;
private VersionManager versionManager;
[CanBeNull]
private IntroScreen introScreen;
@ -743,6 +745,9 @@ namespace osu.Game
ScreenStack.ScreenPushed += screenPushed;
ScreenStack.ScreenExited += screenExited;
if (!args?.Any(a => a == @"--no-version-overlay") ?? true)
loadComponentSingleFile(versionManager = new VersionManager { Depth = int.MinValue }, ScreenContainer.Add);
loadComponentSingleFile(osuLogo, logo =>
{
logoContainer.Add(logo);
@ -820,7 +825,17 @@ namespace osu.Game
loadComponentSingleFile(CreateHighPerformanceSession(), Add);
chatOverlay.State.ValueChanged += state => channelManager.HighPollRate.Value = state.NewValue == Visibility.Visible;
chatOverlay.State.BindValueChanged(_ => updateChatPollRate());
// Multiplayer modes need to increase poll rate temporarily.
API.Activity.BindValueChanged(_ => updateChatPollRate(), true);
void updateChatPollRate()
{
channelManager.HighPollRate.Value =
chatOverlay.State.Value == Visibility.Visible
|| API.Activity.Value is UserActivity.InLobby
|| API.Activity.Value is UserActivity.InMultiplayerGame;
}
Add(difficultyRecommender);
Add(externalLinkOpener = new ExternalLinkOpener());
@ -1116,10 +1131,16 @@ namespace osu.Game
{
case IntroScreen intro:
introScreen = intro;
versionManager?.Show();
break;
case MainMenu menu:
menuScreen = menu;
versionManager?.Show();
break;
default:
versionManager?.Hide();
break;
}

View File

@ -44,7 +44,7 @@ namespace osu.Game.Overlays.AccountCreation
private GameHost host { get; set; }
[BackgroundDependencyLoader]
private void load(OsuColour colours)
private void load()
{
InternalChildren = new Drawable[]
{

View File

@ -10,7 +10,6 @@ using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Screens;
using osu.Framework.Threading;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Online.API;
using osu.Game.Overlays.AccountCreation;
@ -35,7 +34,7 @@ namespace osu.Game.Overlays
private readonly IBindable<APIState> apiState = new Bindable<APIState>();
[BackgroundDependencyLoader]
private void load(OsuColour colours, IAPIProvider api)
private void load(IAPIProvider api)
{
apiState.BindTo(api.State);
apiState.BindValueChanged(apiStateChanged, true);

View File

@ -65,6 +65,9 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
scoreTable.ClearScores();
scoreTable.Hide();
loading.Hide();
loading.FinishTransforms();
if (value?.Scores.Any() != true)
return;
@ -258,9 +261,6 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
{
Scores = null;
notSupporterPlaceholder.Show();
loading.Hide();
loading.FinishTransforms();
return;
}
@ -272,9 +272,6 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
getScoresRequest = new GetScoresRequest(Beatmap.Value, Beatmap.Value.Ruleset, scope.Value, modSelector.SelectedMods);
getScoresRequest.Success += scores =>
{
loading.Hide();
loading.FinishTransforms();
Scores = scores;
if (!scores.Scores.Any())

View File

@ -46,7 +46,7 @@ namespace osu.Game.Overlays.Changelog
}
[BackgroundDependencyLoader]
private void load(OsuColour colours, OverlayColourProvider colourProvider)
private void load()
{
foreach (var categoryEntries in Build.ChangelogEntries.GroupBy(b => b.Category).OrderBy(c => c.Key))
{

View File

@ -7,7 +7,6 @@ using System.Threading;
using System.Threading.Tasks;
using JetBrains.Annotations;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Input.Events;
@ -35,7 +34,7 @@ namespace osu.Game.Overlays
}
[BackgroundDependencyLoader]
private void load(AudioManager audio)
private void load()
{
Header.Build.BindTarget = Current;

View File

@ -317,7 +317,7 @@ namespace osu.Game.Overlays.Comments
private class NoCommentsPlaceholder : CompositeDrawable
{
[BackgroundDependencyLoader]
private void load(OverlayColourProvider colourProvider)
private void load()
{
Height = 80;
RelativeSizeAxes = Axes.X;

View File

@ -7,7 +7,6 @@ using osu.Framework.Extensions.LocalisationExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Textures;
using osu.Framework.Localisation;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Overlays.Profile.Header.Components;
@ -30,7 +29,7 @@ namespace osu.Game.Overlays.Profile.Header
}
[BackgroundDependencyLoader]
private void load(OverlayColourProvider colourProvider, TextureStore textures)
private void load(OverlayColourProvider colourProvider)
{
Container<Drawable> hiddenDetailContainer;
Container<Drawable> expandedDetailContainer;

Some files were not shown because too many files have changed in this diff Show More