mirror of
https://github.com/ppy/osu.git
synced 2025-02-15 06:52:56 +08:00
commit
3c5a829ddd
0
.gitmodules
vendored
0
.gitmodules
vendored
@ -1,2 +0,0 @@
|
|||||||
language: csharp
|
|
||||||
solution: osu.sln
|
|
@ -19,8 +19,9 @@ Detailed changelogs are published on the [official osu! site](https://osu.ppy.sh
|
|||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
- A desktop platform with the [.NET Core SDK 2.2](https://www.microsoft.com/net/learn/get-started) or higher installed.
|
- A desktop platform with the [.NET Core SDK 2.2](https://www.microsoft.com/net/learn/get-started) or higher installed.
|
||||||
|
- When running on linux, please have a system-wide ffmpeg installation available to support video decoding.
|
||||||
|
- When running on Windows 7 or 8.1, **[additional prerequisites](https://docs.microsoft.com/en-us/dotnet/core/windows-prerequisites?tabs=netcore2x)** may be required to correctly run .NET Core applications if your operating system is not up-to-date with the latest service packs.
|
||||||
- When working with the codebase, we recommend using an IDE with intellisense and syntax highlighting, such as [Visual Studio 2017+](https://visualstudio.microsoft.com/vs/), [Jetbrains Rider](https://www.jetbrains.com/rider/) or [Visual Studio Code](https://code.visualstudio.com/).
|
- When working with the codebase, we recommend using an IDE with intellisense and syntax highlighting, such as [Visual Studio 2017+](https://visualstudio.microsoft.com/vs/), [Jetbrains Rider](https://www.jetbrains.com/rider/) or [Visual Studio Code](https://code.visualstudio.com/).
|
||||||
- Note that there are **[additional requirements for Windows 7 and Windows 8.1](https://docs.microsoft.com/en-us/dotnet/core/windows-prerequisites?tabs=netcore2x)** which you may need to manually install if your operating system is not up-to-date.
|
|
||||||
|
|
||||||
## Running osu!
|
## Running osu!
|
||||||
|
|
||||||
@ -34,7 +35,7 @@ If you are not interested in developing the game, you can still consume our [bin
|
|||||||
| ------------- | ------------- |
|
| ------------- | ------------- |
|
||||||
|
|
||||||
- **Linux** users are recommended to self-compile until we have official deployment in place.
|
- **Linux** users are recommended to self-compile until we have official deployment in place.
|
||||||
- **iOS** users can join the [TestFlight beta program](https://t.co/PasE1zrHhw) (note that due to high demand this is regularly full).
|
- **iOS** users can join the [TestFlight beta program](https://testflight.apple.com/join/2tLcjWlF) (note that due to high demand this is regularly full).
|
||||||
- **Android** users can self-compile, and expect a public beta soon.
|
- **Android** users can self-compile, and expect a public beta soon.
|
||||||
|
|
||||||
If your platform is not listed above, there is still a chance you can manually build it by following the instructions below.
|
If your platform is not listed above, there is still a chance you can manually build it by following the instructions below.
|
||||||
|
@ -49,9 +49,7 @@
|
|||||||
<None Include="$(MSBuildThisFileDirectory)\osu.licenseheader">
|
<None Include="$(MSBuildThisFileDirectory)\osu.licenseheader">
|
||||||
<Link>osu.licenseheader</Link>
|
<Link>osu.licenseheader</Link>
|
||||||
</None>
|
</None>
|
||||||
<AndroidNativeLibrary Include="$(MSBuildThisFileDirectory)\osu.Android\lib\**\*.so">
|
<AndroidNativeLibrary Include="$(OutputPath)\**\*.so" />
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
|
||||||
</AndroidNativeLibrary>
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
@ -62,7 +60,7 @@
|
|||||||
<Reference Include="Java.Interop" />
|
<Reference Include="Java.Interop" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2019.702.0" />
|
<PackageReference Include="ppy.osu.Game.Resources" Version="2019.809.0" />
|
||||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2019.730.0" />
|
<PackageReference Include="ppy.osu.Framework.Android" Version="2019.814.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -113,13 +113,14 @@ namespace osu.Desktop.Overlays
|
|||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuColour colours, ChangelogOverlay changelog)
|
private void load(OsuColour colours, ChangelogOverlay changelog, NotificationOverlay notificationOverlay)
|
||||||
{
|
{
|
||||||
Icon = FontAwesome.Solid.CheckSquare;
|
Icon = FontAwesome.Solid.CheckSquare;
|
||||||
IconBackgound.Colour = colours.BlueDark;
|
IconBackgound.Colour = colours.BlueDark;
|
||||||
|
|
||||||
Activated = delegate
|
Activated = delegate
|
||||||
{
|
{
|
||||||
|
notificationOverlay.Hide();
|
||||||
changelog.ShowBuild(OsuGameBase.CLIENT_STREAM_NAME, version);
|
changelog.ShowBuild(OsuGameBase.CLIENT_STREAM_NAME, version);
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
@ -13,14 +13,6 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="Info.plist" />
|
<None Include="Info.plist" />
|
||||||
<None Include="Entitlements.plist" />
|
<None Include="Entitlements.plist" />
|
||||||
<None Include="..\osu.iOS\libbass.a">
|
|
||||||
<Link>libbass.a</Link>
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</None>
|
|
||||||
<None Include="..\osu.iOS\libbass_fx.a">
|
|
||||||
<Link>libbass_fx.a</Link>
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</None>
|
|
||||||
<LinkDescription Include="..\osu.iOS\Linker.xml">
|
<LinkDescription Include="..\osu.iOS\Linker.xml">
|
||||||
<Link>Linker.xml</Link>
|
<Link>Linker.xml</Link>
|
||||||
</LinkDescription>
|
</LinkDescription>
|
||||||
|
@ -6,6 +6,7 @@ using System.Collections.Generic;
|
|||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.MathUtils;
|
using osu.Framework.MathUtils;
|
||||||
|
using osu.Game.Rulesets.Catch.Mods;
|
||||||
using osu.Game.Rulesets.Catch.Objects;
|
using osu.Game.Rulesets.Catch.Objects;
|
||||||
using osu.Game.Rulesets.Catch.UI;
|
using osu.Game.Rulesets.Catch.UI;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
@ -22,10 +23,10 @@ namespace osu.Game.Rulesets.Catch.Tests
|
|||||||
[TestCase("spinner")]
|
[TestCase("spinner")]
|
||||||
[TestCase("spinner-and-circles")]
|
[TestCase("spinner-and-circles")]
|
||||||
[TestCase("slider")]
|
[TestCase("slider")]
|
||||||
public new void Test(string name)
|
[TestCase("hardrock-stream", new[] { typeof(CatchModHardRock) })]
|
||||||
{
|
[TestCase("hardrock-repeat-slider", new[] { typeof(CatchModHardRock) })]
|
||||||
base.Test(name);
|
[TestCase("hardrock-spinner", new[] { typeof(CatchModHardRock) })]
|
||||||
}
|
public new void Test(string name, params Type[] mods) => base.Test(name, mods);
|
||||||
|
|
||||||
protected override IEnumerable<ConvertValue> CreateConvertValue(HitObject hitObject)
|
protected override IEnumerable<ConvertValue> CreateConvertValue(HitObject hitObject)
|
||||||
{
|
{
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" />
|
||||||
<PackageReference Include="NUnit" Version="3.12.0" />
|
<PackageReference Include="NUnit" Version="3.12.0" />
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="3.13.0" />
|
<PackageReference Include="NUnit3TestAdapter" Version="3.14.0" />
|
||||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<PropertyGroup Label="Project">
|
<PropertyGroup Label="Project">
|
||||||
|
@ -10,6 +10,7 @@ using osu.Game.Rulesets.Catch.UI;
|
|||||||
using osu.Game.Rulesets.Objects.Types;
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osu.Game.Rulesets.Catch.MathUtils;
|
using osu.Game.Rulesets.Catch.MathUtils;
|
||||||
|
using osu.Game.Rulesets.Mods;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.Beatmaps
|
namespace osu.Game.Rulesets.Catch.Beatmaps
|
||||||
{
|
{
|
||||||
@ -26,7 +27,7 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
|
|||||||
{
|
{
|
||||||
base.PostProcess();
|
base.PostProcess();
|
||||||
|
|
||||||
applyPositionOffsets();
|
ApplyPositionOffsets(Beatmap);
|
||||||
|
|
||||||
initialiseHyperDash((List<CatchHitObject>)Beatmap.HitObjects);
|
initialiseHyperDash((List<CatchHitObject>)Beatmap.HitObjects);
|
||||||
|
|
||||||
@ -40,19 +41,29 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void applyPositionOffsets()
|
public static void ApplyPositionOffsets(IBeatmap beatmap, params Mod[] mods)
|
||||||
{
|
{
|
||||||
var rng = new FastRandom(RNG_SEED);
|
var rng = new FastRandom(RNG_SEED);
|
||||||
// todo: HardRock displacement should be applied here
|
|
||||||
|
|
||||||
foreach (var obj in Beatmap.HitObjects)
|
bool shouldApplyHardRockOffset = mods.Any(m => m is ModHardRock);
|
||||||
|
float? lastPosition = null;
|
||||||
|
double lastStartTime = 0;
|
||||||
|
|
||||||
|
foreach (var obj in beatmap.HitObjects.OfType<CatchHitObject>())
|
||||||
{
|
{
|
||||||
|
obj.XOffset = 0;
|
||||||
|
|
||||||
switch (obj)
|
switch (obj)
|
||||||
{
|
{
|
||||||
|
case Fruit fruit:
|
||||||
|
if (shouldApplyHardRockOffset)
|
||||||
|
applyHardRockOffset(fruit, ref lastPosition, ref lastStartTime, rng);
|
||||||
|
break;
|
||||||
|
|
||||||
case BananaShower bananaShower:
|
case BananaShower bananaShower:
|
||||||
foreach (var banana in bananaShower.NestedHitObjects.OfType<Banana>())
|
foreach (var banana in bananaShower.NestedHitObjects.OfType<Banana>())
|
||||||
{
|
{
|
||||||
banana.X = (float)rng.NextDouble();
|
banana.XOffset = (float)rng.NextDouble();
|
||||||
rng.Next(); // osu!stable retrieved a random banana type
|
rng.Next(); // osu!stable retrieved a random banana type
|
||||||
rng.Next(); // osu!stable retrieved a random banana rotation
|
rng.Next(); // osu!stable retrieved a random banana rotation
|
||||||
rng.Next(); // osu!stable retrieved a random banana colour
|
rng.Next(); // osu!stable retrieved a random banana colour
|
||||||
@ -63,12 +74,13 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
|
|||||||
case JuiceStream juiceStream:
|
case JuiceStream juiceStream:
|
||||||
foreach (var nested in juiceStream.NestedHitObjects)
|
foreach (var nested in juiceStream.NestedHitObjects)
|
||||||
{
|
{
|
||||||
var hitObject = (CatchHitObject)nested;
|
var catchObject = (CatchHitObject)nested;
|
||||||
if (hitObject is TinyDroplet)
|
catchObject.XOffset = 0;
|
||||||
hitObject.X += rng.Next(-20, 20) / CatchPlayfield.BASE_WIDTH;
|
|
||||||
else if (hitObject is Droplet)
|
if (catchObject is TinyDroplet)
|
||||||
|
catchObject.XOffset = MathHelper.Clamp(rng.Next(-20, 20) / CatchPlayfield.BASE_WIDTH, -catchObject.X, 1 - catchObject.X);
|
||||||
|
else if (catchObject is Droplet)
|
||||||
rng.Next(); // osu!stable retrieved a random droplet rotation
|
rng.Next(); // osu!stable retrieved a random droplet rotation
|
||||||
hitObject.X = MathHelper.Clamp(hitObject.X, 0, 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -76,6 +88,105 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void applyHardRockOffset(CatchHitObject hitObject, ref float? lastPosition, ref double lastStartTime, FastRandom rng)
|
||||||
|
{
|
||||||
|
if (hitObject is JuiceStream stream)
|
||||||
|
{
|
||||||
|
lastPosition = stream.EndX;
|
||||||
|
lastStartTime = stream.EndTime;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(hitObject is Fruit))
|
||||||
|
return;
|
||||||
|
|
||||||
|
float offsetPosition = hitObject.X;
|
||||||
|
double startTime = hitObject.StartTime;
|
||||||
|
|
||||||
|
if (lastPosition == null)
|
||||||
|
{
|
||||||
|
lastPosition = offsetPosition;
|
||||||
|
lastStartTime = startTime;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
float positionDiff = offsetPosition - lastPosition.Value;
|
||||||
|
double timeDiff = startTime - lastStartTime;
|
||||||
|
|
||||||
|
if (timeDiff > 1000)
|
||||||
|
{
|
||||||
|
lastPosition = offsetPosition;
|
||||||
|
lastStartTime = startTime;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (positionDiff == 0)
|
||||||
|
{
|
||||||
|
applyRandomOffset(ref offsetPosition, timeDiff / 4d, rng);
|
||||||
|
hitObject.XOffset = offsetPosition - hitObject.X;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Math.Abs(positionDiff * CatchPlayfield.BASE_WIDTH) < timeDiff / 3d)
|
||||||
|
applyOffset(ref offsetPosition, positionDiff);
|
||||||
|
|
||||||
|
hitObject.XOffset = offsetPosition - hitObject.X;
|
||||||
|
|
||||||
|
lastPosition = offsetPosition;
|
||||||
|
lastStartTime = startTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Applies a random offset in a random direction to a position, ensuring that the final position remains within the boundary of the playfield.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="position">The position which the offset should be applied to.</param>
|
||||||
|
/// <param name="maxOffset">The maximum offset, cannot exceed 20px.</param>
|
||||||
|
/// <param name="rng">The random number generator.</param>
|
||||||
|
private static void applyRandomOffset(ref float position, double maxOffset, FastRandom rng)
|
||||||
|
{
|
||||||
|
bool right = rng.NextBool();
|
||||||
|
float rand = Math.Min(20, (float)rng.Next(0, Math.Max(0, maxOffset))) / CatchPlayfield.BASE_WIDTH;
|
||||||
|
|
||||||
|
if (right)
|
||||||
|
{
|
||||||
|
// Clamp to the right bound
|
||||||
|
if (position + rand <= 1)
|
||||||
|
position += rand;
|
||||||
|
else
|
||||||
|
position -= rand;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Clamp to the left bound
|
||||||
|
if (position - rand >= 0)
|
||||||
|
position -= rand;
|
||||||
|
else
|
||||||
|
position += rand;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Applies an offset to a position, ensuring that the final position remains within the boundary of the playfield.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="position">The position which the offset should be applied to.</param>
|
||||||
|
/// <param name="amount">The amount to offset by.</param>
|
||||||
|
private static void applyOffset(ref float position, float amount)
|
||||||
|
{
|
||||||
|
if (amount > 0)
|
||||||
|
{
|
||||||
|
// Clamp to the right bound
|
||||||
|
if (position + amount < 1)
|
||||||
|
position += amount;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Clamp to the left bound
|
||||||
|
if (position + amount > 0)
|
||||||
|
position += amount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void initialiseHyperDash(List<CatchHitObject> objects)
|
private void initialiseHyperDash(List<CatchHitObject> objects)
|
||||||
{
|
{
|
||||||
List<CatchHitObject> objectWithDroplets = new List<CatchHitObject>();
|
List<CatchHitObject> objectWithDroplets = new List<CatchHitObject>();
|
||||||
|
@ -61,6 +61,14 @@ namespace osu.Game.Rulesets.Catch.MathUtils
|
|||||||
/// <returns>The random value.</returns>
|
/// <returns>The random value.</returns>
|
||||||
public int Next(int lowerBound, int upperBound) => (int)(lowerBound + NextDouble() * (upperBound - lowerBound));
|
public int Next(int lowerBound, int upperBound) => (int)(lowerBound + NextDouble() * (upperBound - lowerBound));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Generates a random integer value within the range [<paramref name="lowerBound"/>, <paramref name="upperBound"/>).
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="lowerBound">The lower bound of the range.</param>
|
||||||
|
/// <param name="upperBound">The upper bound of the range.</param>
|
||||||
|
/// <returns>The random value.</returns>
|
||||||
|
public int Next(double lowerBound, double upperBound) => (int)(lowerBound + NextDouble() * (upperBound - lowerBound));
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Generates a random double value within the range [0, 1).
|
/// Generates a random double value within the range [0, 1).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -1,121 +1,17 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using osu.Framework.MathUtils;
|
|
||||||
using osu.Game.Rulesets.Catch.Objects;
|
|
||||||
using osu.Game.Rulesets.Catch.UI;
|
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using System;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Catch.Beatmaps;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.Mods
|
namespace osu.Game.Rulesets.Catch.Mods
|
||||||
{
|
{
|
||||||
public class CatchModHardRock : ModHardRock, IApplicableToHitObject
|
public class CatchModHardRock : ModHardRock, IApplicableToBeatmap
|
||||||
{
|
{
|
||||||
public override double ScoreMultiplier => 1.12;
|
public override double ScoreMultiplier => 1.12;
|
||||||
public override bool Ranked => true;
|
public override bool Ranked => true;
|
||||||
|
|
||||||
private float? lastPosition;
|
public void ApplyToBeatmap(IBeatmap beatmap) => CatchBeatmapProcessor.ApplyPositionOffsets(beatmap, this);
|
||||||
private double lastStartTime;
|
|
||||||
|
|
||||||
public void ApplyToHitObject(HitObject hitObject)
|
|
||||||
{
|
|
||||||
if (hitObject is JuiceStream stream)
|
|
||||||
{
|
|
||||||
lastPosition = stream.EndX;
|
|
||||||
lastStartTime = stream.EndTime;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(hitObject is Fruit))
|
|
||||||
return;
|
|
||||||
|
|
||||||
var catchObject = (CatchHitObject)hitObject;
|
|
||||||
|
|
||||||
float position = catchObject.X;
|
|
||||||
double startTime = hitObject.StartTime;
|
|
||||||
|
|
||||||
if (lastPosition == null)
|
|
||||||
{
|
|
||||||
lastPosition = position;
|
|
||||||
lastStartTime = startTime;
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
float positionDiff = position - lastPosition.Value;
|
|
||||||
double timeDiff = startTime - lastStartTime;
|
|
||||||
|
|
||||||
if (timeDiff > 1000)
|
|
||||||
{
|
|
||||||
lastPosition = position;
|
|
||||||
lastStartTime = startTime;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (positionDiff == 0)
|
|
||||||
{
|
|
||||||
applyRandomOffset(ref position, timeDiff / 4d);
|
|
||||||
catchObject.X = position;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Math.Abs(positionDiff * CatchPlayfield.BASE_WIDTH) < timeDiff / 3d)
|
|
||||||
applyOffset(ref position, positionDiff);
|
|
||||||
|
|
||||||
catchObject.X = position;
|
|
||||||
|
|
||||||
lastPosition = position;
|
|
||||||
lastStartTime = startTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Applies a random offset in a random direction to a position, ensuring that the final position remains within the boundary of the playfield.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="position">The position which the offset should be applied to.</param>
|
|
||||||
/// <param name="maxOffset">The maximum offset, cannot exceed 20px.</param>
|
|
||||||
private void applyRandomOffset(ref float position, double maxOffset)
|
|
||||||
{
|
|
||||||
bool right = RNG.NextBool();
|
|
||||||
float rand = Math.Min(20, (float)RNG.NextDouble(0, Math.Max(0, maxOffset))) / CatchPlayfield.BASE_WIDTH;
|
|
||||||
|
|
||||||
if (right)
|
|
||||||
{
|
|
||||||
// Clamp to the right bound
|
|
||||||
if (position + rand <= 1)
|
|
||||||
position += rand;
|
|
||||||
else
|
|
||||||
position -= rand;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Clamp to the left bound
|
|
||||||
if (position - rand >= 0)
|
|
||||||
position -= rand;
|
|
||||||
else
|
|
||||||
position += rand;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Applies an offset to a position, ensuring that the final position remains within the boundary of the playfield.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="position">The position which the offset should be applied to.</param>
|
|
||||||
/// <param name="amount">The amount to offset by.</param>
|
|
||||||
private void applyOffset(ref float position, float amount)
|
|
||||||
{
|
|
||||||
if (amount > 0)
|
|
||||||
{
|
|
||||||
// Clamp to the right bound
|
|
||||||
if (position + amount < 1)
|
|
||||||
position += amount;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Clamp to the left bound
|
|
||||||
if (position + amount > 0)
|
|
||||||
position += amount;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
|
using osu.Game.Rulesets.Catch.Beatmaps;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Objects.Types;
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
|
|
||||||
@ -12,7 +13,18 @@ namespace osu.Game.Rulesets.Catch.Objects
|
|||||||
{
|
{
|
||||||
public const double OBJECT_RADIUS = 44;
|
public const double OBJECT_RADIUS = 44;
|
||||||
|
|
||||||
public float X { get; set; }
|
private float x;
|
||||||
|
|
||||||
|
public float X
|
||||||
|
{
|
||||||
|
get => x + XOffset;
|
||||||
|
set => x = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A random offset applied to <see cref="X"/>, set by the <see cref="CatchBeatmapProcessor"/>.
|
||||||
|
/// </summary>
|
||||||
|
internal float XOffset { get; set; }
|
||||||
|
|
||||||
public double TimePreempt = 1000;
|
public double TimePreempt = 1000;
|
||||||
|
|
||||||
|
@ -0,0 +1,150 @@
|
|||||||
|
{
|
||||||
|
"Mappings": [{
|
||||||
|
"StartTime": 369,
|
||||||
|
"Objects": [{
|
||||||
|
"StartTime": 369,
|
||||||
|
"Position": 177
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 450,
|
||||||
|
"Position": 216.539276
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 532,
|
||||||
|
"Position": 256.5667
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 614,
|
||||||
|
"Position": 296.594116
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 696,
|
||||||
|
"Position": 336.621521
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 778,
|
||||||
|
"Position": 376.99762
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 860,
|
||||||
|
"Position": 337.318878
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 942,
|
||||||
|
"Position": 297.291443
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 1024,
|
||||||
|
"Position": 257.264038
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 1106,
|
||||||
|
"Position": 217.2366
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 1188,
|
||||||
|
"Position": 177
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 1270,
|
||||||
|
"Position": 216.818192
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 1352,
|
||||||
|
"Position": 256.8456
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 1434,
|
||||||
|
"Position": 296.873047
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 1516,
|
||||||
|
"Position": 336.900452
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 1598,
|
||||||
|
"Position": 376.99762
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 1680,
|
||||||
|
"Position": 337.039948
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 1762,
|
||||||
|
"Position": 297.0125
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 1844,
|
||||||
|
"Position": 256.9851
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 1926,
|
||||||
|
"Position": 216.957672
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 2008,
|
||||||
|
"Position": 177
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 2090,
|
||||||
|
"Position": 217.097137
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 2172,
|
||||||
|
"Position": 257.124573
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 2254,
|
||||||
|
"Position": 297.152
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 2336,
|
||||||
|
"Position": 337.179443
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 2418,
|
||||||
|
"Position": 376.99762
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 2500,
|
||||||
|
"Position": 336.760956
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 2582,
|
||||||
|
"Position": 296.733643
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 2664,
|
||||||
|
"Position": 256.7062
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 2746,
|
||||||
|
"Position": 216.678772
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 2828,
|
||||||
|
"Position": 177
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 2909,
|
||||||
|
"Position": 216.887909
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 2991,
|
||||||
|
"Position": 256.915344
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 3073,
|
||||||
|
"Position": 296.942749
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 3155,
|
||||||
|
"Position": 336.970184
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 3237,
|
||||||
|
"Position": 376.99762
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}]
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
osu file format v14
|
||||||
|
|
||||||
|
[General]
|
||||||
|
StackLeniency: 0.4
|
||||||
|
Mode: 0
|
||||||
|
|
||||||
|
[Difficulty]
|
||||||
|
CircleSize:4
|
||||||
|
OverallDifficulty:7
|
||||||
|
ApproachRate:8
|
||||||
|
SliderMultiplier:1.6
|
||||||
|
SliderTickRate:4
|
||||||
|
|
||||||
|
[TimingPoints]
|
||||||
|
369,327.868852459016,4,2,2,32,1,0
|
||||||
|
|
||||||
|
[HitObjects]
|
||||||
|
177,191,369,6,0,L|382:192,7,200
|
@ -0,0 +1,74 @@
|
|||||||
|
{
|
||||||
|
"Mappings": [{
|
||||||
|
"StartTime": 369,
|
||||||
|
"Objects": [{
|
||||||
|
"StartTime": 369,
|
||||||
|
"Position": 65
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 450,
|
||||||
|
"Position": 482
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 532,
|
||||||
|
"Position": 164
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 614,
|
||||||
|
"Position": 315
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 696,
|
||||||
|
"Position": 145
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 778,
|
||||||
|
"Position": 159
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 860,
|
||||||
|
"Position": 310
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 942,
|
||||||
|
"Position": 441
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 1024,
|
||||||
|
"Position": 428
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 1106,
|
||||||
|
"Position": 243
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 1188,
|
||||||
|
"Position": 422
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 1270,
|
||||||
|
"Position": 481
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 1352,
|
||||||
|
"Position": 104
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 1434,
|
||||||
|
"Position": 473
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 1516,
|
||||||
|
"Position": 135
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 1598,
|
||||||
|
"Position": 360
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 1680,
|
||||||
|
"Position": 123
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}]
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
osu file format v14
|
||||||
|
|
||||||
|
[General]
|
||||||
|
StackLeniency: 0.4
|
||||||
|
Mode: 0
|
||||||
|
|
||||||
|
[Difficulty]
|
||||||
|
CircleSize:4
|
||||||
|
OverallDifficulty:7
|
||||||
|
ApproachRate:8
|
||||||
|
SliderMultiplier:1.6
|
||||||
|
SliderTickRate:4
|
||||||
|
|
||||||
|
[TimingPoints]
|
||||||
|
369,327.868852459016,4,2,2,32,1,0
|
||||||
|
|
||||||
|
[HitObjects]
|
||||||
|
256,192,369,12,0,1680,0:0:0:0:
|
@ -0,0 +1,234 @@
|
|||||||
|
{
|
||||||
|
"Mappings": [{
|
||||||
|
"StartTime": 369,
|
||||||
|
"Objects": [{
|
||||||
|
"StartTime": 369,
|
||||||
|
"Position": 258
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 450,
|
||||||
|
"Objects": [{
|
||||||
|
"StartTime": 450,
|
||||||
|
"Position": 254
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 532,
|
||||||
|
"Objects": [{
|
||||||
|
"StartTime": 532,
|
||||||
|
"Position": 241
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 614,
|
||||||
|
"Objects": [{
|
||||||
|
"StartTime": 614,
|
||||||
|
"Position": 238
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 696,
|
||||||
|
"Objects": [{
|
||||||
|
"StartTime": 696,
|
||||||
|
"Position": 238
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 778,
|
||||||
|
"Objects": [{
|
||||||
|
"StartTime": 778,
|
||||||
|
"Position": 278
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 860,
|
||||||
|
"Objects": [{
|
||||||
|
"StartTime": 860,
|
||||||
|
"Position": 238
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 942,
|
||||||
|
"Objects": [{
|
||||||
|
"StartTime": 942,
|
||||||
|
"Position": 278
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 1024,
|
||||||
|
"Objects": [{
|
||||||
|
"StartTime": 1024,
|
||||||
|
"Position": 238
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 1106,
|
||||||
|
"Objects": [{
|
||||||
|
"StartTime": 1106,
|
||||||
|
"Position": 278
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 1188,
|
||||||
|
"Objects": [{
|
||||||
|
"StartTime": 1188,
|
||||||
|
"Position": 278
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 1270,
|
||||||
|
"Objects": [{
|
||||||
|
"StartTime": 1270,
|
||||||
|
"Position": 278
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 1352,
|
||||||
|
"Objects": [{
|
||||||
|
"StartTime": 1352,
|
||||||
|
"Position": 238
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 1434,
|
||||||
|
"Objects": [{
|
||||||
|
"StartTime": 1434,
|
||||||
|
"Position": 258
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 1516,
|
||||||
|
"Objects": [{
|
||||||
|
"StartTime": 1516,
|
||||||
|
"Position": 253
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 1598,
|
||||||
|
"Objects": [{
|
||||||
|
"StartTime": 1598,
|
||||||
|
"Position": 238
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 1680,
|
||||||
|
"Objects": [{
|
||||||
|
"StartTime": 1680,
|
||||||
|
"Position": 260
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 1762,
|
||||||
|
"Objects": [{
|
||||||
|
"StartTime": 1762,
|
||||||
|
"Position": 238
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 1844,
|
||||||
|
"Objects": [{
|
||||||
|
"StartTime": 1844,
|
||||||
|
"Position": 278
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 1926,
|
||||||
|
"Objects": [{
|
||||||
|
"StartTime": 1926,
|
||||||
|
"Position": 278
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 2008,
|
||||||
|
"Objects": [{
|
||||||
|
"StartTime": 2008,
|
||||||
|
"Position": 238
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 2090,
|
||||||
|
"Objects": [{
|
||||||
|
"StartTime": 2090,
|
||||||
|
"Position": 238
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 2172,
|
||||||
|
"Objects": [{
|
||||||
|
"StartTime": 2172,
|
||||||
|
"Position": 243
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 2254,
|
||||||
|
"Objects": [{
|
||||||
|
"StartTime": 2254,
|
||||||
|
"Position": 278
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 2336,
|
||||||
|
"Objects": [{
|
||||||
|
"StartTime": 2336,
|
||||||
|
"Position": 278
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 2418,
|
||||||
|
"Objects": [{
|
||||||
|
"StartTime": 2418,
|
||||||
|
"Position": 238
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 2500,
|
||||||
|
"Objects": [{
|
||||||
|
"StartTime": 2500,
|
||||||
|
"Position": 258
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 2582,
|
||||||
|
"Objects": [{
|
||||||
|
"StartTime": 2582,
|
||||||
|
"Position": 256
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 2664,
|
||||||
|
"Objects": [{
|
||||||
|
"StartTime": 2664,
|
||||||
|
"Position": 242
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 2746,
|
||||||
|
"Objects": [{
|
||||||
|
"StartTime": 2746,
|
||||||
|
"Position": 238
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 2828,
|
||||||
|
"Objects": [{
|
||||||
|
"StartTime": 2828,
|
||||||
|
"Position": 238
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 2909,
|
||||||
|
"Objects": [{
|
||||||
|
"StartTime": 2909,
|
||||||
|
"Position": 271
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 2991,
|
||||||
|
"Objects": [{
|
||||||
|
"StartTime": 2991,
|
||||||
|
"Position": 254
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1,50 @@
|
|||||||
|
osu file format v14
|
||||||
|
|
||||||
|
[General]
|
||||||
|
StackLeniency: 0.4
|
||||||
|
Mode: 0
|
||||||
|
|
||||||
|
[Difficulty]
|
||||||
|
CircleSize:4
|
||||||
|
OverallDifficulty:7
|
||||||
|
ApproachRate:8
|
||||||
|
SliderMultiplier:1.6
|
||||||
|
SliderTickRate:1
|
||||||
|
|
||||||
|
[TimingPoints]
|
||||||
|
369,327.868852459016,4,2,2,32,1,0
|
||||||
|
|
||||||
|
[HitObjects]
|
||||||
|
258,189,369,1,0,0:0:0:0:
|
||||||
|
258,189,450,1,0,0:0:0:0:
|
||||||
|
258,189,532,1,0,0:0:0:0:
|
||||||
|
258,189,614,1,0,0:0:0:0:
|
||||||
|
258,189,696,1,0,0:0:0:0:
|
||||||
|
258,189,778,1,0,0:0:0:0:
|
||||||
|
258,189,860,1,0,0:0:0:0:
|
||||||
|
258,189,942,1,0,0:0:0:0:
|
||||||
|
258,189,1024,1,0,0:0:0:0:
|
||||||
|
258,189,1106,1,0,0:0:0:0:
|
||||||
|
258,189,1188,1,0,0:0:0:0:
|
||||||
|
258,189,1270,1,0,0:0:0:0:
|
||||||
|
258,189,1352,1,0,0:0:0:0:
|
||||||
|
258,189,1434,1,0,0:0:0:0:
|
||||||
|
258,189,1516,1,0,0:0:0:0:
|
||||||
|
258,189,1598,1,0,0:0:0:0:
|
||||||
|
258,189,1680,1,0,0:0:0:0:
|
||||||
|
258,189,1762,1,0,0:0:0:0:
|
||||||
|
258,189,1844,1,0,0:0:0:0:
|
||||||
|
258,189,1926,1,0,0:0:0:0:
|
||||||
|
258,189,2008,1,0,0:0:0:0:
|
||||||
|
258,189,2090,1,0,0:0:0:0:
|
||||||
|
258,189,2172,1,0,0:0:0:0:
|
||||||
|
258,189,2254,1,0,0:0:0:0:
|
||||||
|
258,189,2336,1,0,0:0:0:0:
|
||||||
|
258,189,2418,1,0,0:0:0:0:
|
||||||
|
258,189,2500,1,0,0:0:0:0:
|
||||||
|
258,189,2582,1,0,0:0:0:0:
|
||||||
|
258,189,2664,1,0,0:0:0:0:
|
||||||
|
258,189,2746,1,0,0:0:0:0:
|
||||||
|
258,189,2828,1,0,0:0:0:0:
|
||||||
|
258,189,2909,1,0,0:0:0:0:
|
||||||
|
258,189,2991,1,0,0:0:0:0:
|
@ -13,14 +13,6 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="Info.plist" />
|
<None Include="Info.plist" />
|
||||||
<None Include="Entitlements.plist" />
|
<None Include="Entitlements.plist" />
|
||||||
<None Include="..\osu.iOS\libbass.a">
|
|
||||||
<Link>libbass.a</Link>
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</None>
|
|
||||||
<None Include="..\osu.iOS\libbass_fx.a">
|
|
||||||
<Link>libbass_fx.a</Link>
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</None>
|
|
||||||
<LinkDescription Include="..\osu.iOS\Linker.xml">
|
<LinkDescription Include="..\osu.iOS\Linker.xml">
|
||||||
<Link>Linker.xml</Link>
|
<Link>Linker.xml</Link>
|
||||||
</LinkDescription>
|
</LinkDescription>
|
||||||
|
@ -20,10 +20,7 @@ namespace osu.Game.Rulesets.Mania.Tests
|
|||||||
protected override string ResourceAssembly => "osu.Game.Rulesets.Mania";
|
protected override string ResourceAssembly => "osu.Game.Rulesets.Mania";
|
||||||
|
|
||||||
[TestCase("basic")]
|
[TestCase("basic")]
|
||||||
public new void Test(string name)
|
public void Test(string name) => base.Test(name);
|
||||||
{
|
|
||||||
base.Test(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override IEnumerable<ConvertValue> CreateConvertValue(HitObject hitObject)
|
protected override IEnumerable<ConvertValue> CreateConvertValue(HitObject hitObject)
|
||||||
{
|
{
|
||||||
@ -35,11 +32,37 @@ namespace osu.Game.Rulesets.Mania.Tests
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override ManiaConvertMapping CreateConvertMapping() => new ManiaConvertMapping(Converter);
|
private readonly Dictionary<HitObject, RngSnapshot> rngSnapshots = new Dictionary<HitObject, RngSnapshot>();
|
||||||
|
|
||||||
|
protected override void OnConversionGenerated(HitObject original, IEnumerable<HitObject> result, IBeatmapConverter beatmapConverter)
|
||||||
|
{
|
||||||
|
base.OnConversionGenerated(original, result, beatmapConverter);
|
||||||
|
|
||||||
|
rngSnapshots[original] = new RngSnapshot(beatmapConverter);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override ManiaConvertMapping CreateConvertMapping(HitObject source) => new ManiaConvertMapping(rngSnapshots[source]);
|
||||||
|
|
||||||
protected override Ruleset CreateRuleset() => new ManiaRuleset();
|
protected override Ruleset CreateRuleset() => new ManiaRuleset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class RngSnapshot
|
||||||
|
{
|
||||||
|
public readonly uint RandomW;
|
||||||
|
public readonly uint RandomX;
|
||||||
|
public readonly uint RandomY;
|
||||||
|
public readonly uint RandomZ;
|
||||||
|
|
||||||
|
public RngSnapshot(IBeatmapConverter converter)
|
||||||
|
{
|
||||||
|
var maniaConverter = (ManiaBeatmapConverter)converter;
|
||||||
|
RandomW = maniaConverter.Random.W;
|
||||||
|
RandomX = maniaConverter.Random.X;
|
||||||
|
RandomY = maniaConverter.Random.Y;
|
||||||
|
RandomZ = maniaConverter.Random.Z;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public class ManiaConvertMapping : ConvertMapping<ConvertValue>, IEquatable<ManiaConvertMapping>
|
public class ManiaConvertMapping : ConvertMapping<ConvertValue>, IEquatable<ManiaConvertMapping>
|
||||||
{
|
{
|
||||||
public uint RandomW;
|
public uint RandomW;
|
||||||
@ -51,13 +74,12 @@ namespace osu.Game.Rulesets.Mania.Tests
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public ManiaConvertMapping(IBeatmapConverter converter)
|
public ManiaConvertMapping(RngSnapshot snapshot)
|
||||||
{
|
{
|
||||||
var maniaConverter = (ManiaBeatmapConverter)converter;
|
RandomW = snapshot.RandomW;
|
||||||
RandomW = maniaConverter.Random.W;
|
RandomX = snapshot.RandomX;
|
||||||
RandomX = maniaConverter.Random.X;
|
RandomY = snapshot.RandomY;
|
||||||
RandomY = maniaConverter.Random.Y;
|
RandomZ = snapshot.RandomZ;
|
||||||
RandomZ = maniaConverter.Random.Z;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Equals(ManiaConvertMapping other) => other != null && RandomW == other.RandomW && RandomX == other.RandomX && RandomY == other.RandomY && RandomZ == other.RandomZ;
|
public bool Equals(ManiaConvertMapping other) => other != null && RandomW == other.RandomW && RandomX == other.RandomX && RandomY == other.RandomY && RandomZ == other.RandomZ;
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" />
|
||||||
<PackageReference Include="NUnit" Version="3.12.0" />
|
<PackageReference Include="NUnit" Version="3.12.0" />
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="3.13.0" />
|
<PackageReference Include="NUnit3TestAdapter" Version="3.14.0" />
|
||||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<PropertyGroup Label="Project">
|
<PropertyGroup Label="Project">
|
||||||
|
@ -16,7 +16,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Keep the same as last row.
|
/// Keep the same as last row.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
ForceStack = 1 << 0,
|
ForceStack = 1,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Keep different from last row.
|
/// Keep different from last row.
|
||||||
|
@ -100,7 +100,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Cached subtractionCache = new Cached();
|
private readonly Cached subtractionCache = new Cached();
|
||||||
|
|
||||||
public override bool Invalidate(Invalidation invalidation = Invalidation.All, Drawable source = null, bool shallPropagate = true)
|
public override bool Invalidate(Invalidation invalidation = Invalidation.All, Drawable source = null, bool shallPropagate = true)
|
||||||
{
|
{
|
||||||
|
@ -13,14 +13,6 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="Info.plist" />
|
<None Include="Info.plist" />
|
||||||
<None Include="Entitlements.plist" />
|
<None Include="Entitlements.plist" />
|
||||||
<None Include="..\osu.iOS\libbass.a">
|
|
||||||
<Link>libbass.a</Link>
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</None>
|
|
||||||
<None Include="..\osu.iOS\libbass_fx.a">
|
|
||||||
<Link>libbass_fx.a</Link>
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</None>
|
|
||||||
<LinkDescription Include="..\osu.iOS\Linker.xml">
|
<LinkDescription Include="..\osu.iOS\Linker.xml">
|
||||||
<Link>Linker.xml</Link>
|
<Link>Linker.xml</Link>
|
||||||
</LinkDescription>
|
</LinkDescription>
|
||||||
|
@ -8,7 +8,6 @@ using osu.Framework.MathUtils;
|
|||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Objects.Types;
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
using osu.Game.Rulesets.Osu.UI;
|
|
||||||
using osu.Game.Tests.Beatmaps;
|
using osu.Game.Tests.Beatmaps;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Tests
|
namespace osu.Game.Rulesets.Osu.Tests
|
||||||
@ -23,10 +22,8 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
[TestCase("slider-ticks")]
|
[TestCase("slider-ticks")]
|
||||||
[TestCase("repeat-slider")]
|
[TestCase("repeat-slider")]
|
||||||
[TestCase("uneven-repeat-slider")]
|
[TestCase("uneven-repeat-slider")]
|
||||||
public new void Test(string name)
|
[TestCase("old-stacking")]
|
||||||
{
|
public void Test(string name) => base.Test(name);
|
||||||
base.Test(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override IEnumerable<ConvertValue> CreateConvertValue(HitObject hitObject)
|
protected override IEnumerable<ConvertValue> CreateConvertValue(HitObject hitObject)
|
||||||
{
|
{
|
||||||
@ -34,22 +31,22 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
{
|
{
|
||||||
case Slider slider:
|
case Slider slider:
|
||||||
foreach (var nested in slider.NestedHitObjects)
|
foreach (var nested in slider.NestedHitObjects)
|
||||||
yield return createConvertValue(nested);
|
yield return createConvertValue((OsuHitObject)nested);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
yield return createConvertValue(hitObject);
|
yield return createConvertValue((OsuHitObject)hitObject);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
ConvertValue createConvertValue(HitObject obj) => new ConvertValue
|
ConvertValue createConvertValue(OsuHitObject obj) => new ConvertValue
|
||||||
{
|
{
|
||||||
StartTime = obj.StartTime,
|
StartTime = obj.StartTime,
|
||||||
EndTime = (obj as IHasEndTime)?.EndTime ?? obj.StartTime,
|
EndTime = (obj as IHasEndTime)?.EndTime ?? obj.StartTime,
|
||||||
X = (obj as IHasPosition)?.X ?? OsuPlayfield.BASE_SIZE.X / 2,
|
X = obj.StackedPosition.X,
|
||||||
Y = (obj as IHasPosition)?.Y ?? OsuPlayfield.BASE_SIZE.Y / 2,
|
Y = obj.StackedPosition.Y
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" />
|
||||||
<PackageReference Include="NUnit" Version="3.12.0" />
|
<PackageReference Include="NUnit" Version="3.12.0" />
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="3.13.0" />
|
<PackageReference Include="NUnit3TestAdapter" Version="3.14.0" />
|
||||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<PropertyGroup Label="Project">
|
<PropertyGroup Label="Project">
|
||||||
|
@ -6,6 +6,7 @@ using osu.Framework.Graphics;
|
|||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Objects.Types;
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Beatmaps
|
namespace osu.Game.Rulesets.Osu.Beatmaps
|
||||||
{
|
{
|
||||||
@ -208,17 +209,22 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
|
|||||||
if (beatmap.HitObjects[j].StartTime - stackThreshold > startTime)
|
if (beatmap.HitObjects[j].StartTime - stackThreshold > startTime)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
// The start position of the hitobject, or the position at the end of the path if the hitobject is a slider
|
||||||
|
Vector2 position2 = currHitObject is Slider currSlider
|
||||||
|
? currSlider.Position + currSlider.Path.PositionAt(1)
|
||||||
|
: currHitObject.Position;
|
||||||
|
|
||||||
if (Vector2Extensions.Distance(beatmap.HitObjects[j].Position, currHitObject.Position) < stack_distance)
|
if (Vector2Extensions.Distance(beatmap.HitObjects[j].Position, currHitObject.Position) < stack_distance)
|
||||||
{
|
{
|
||||||
currHitObject.StackHeight++;
|
currHitObject.StackHeight++;
|
||||||
startTime = (beatmap.HitObjects[j] as IHasEndTime)?.EndTime ?? beatmap.HitObjects[i].StartTime;
|
startTime = (beatmap.HitObjects[j] as IHasEndTime)?.EndTime ?? beatmap.HitObjects[j].StartTime;
|
||||||
}
|
}
|
||||||
else if (Vector2Extensions.Distance(beatmap.HitObjects[j].Position, currHitObject.EndPosition) < stack_distance)
|
else if (Vector2Extensions.Distance(beatmap.HitObjects[j].Position, position2) < stack_distance)
|
||||||
{
|
{
|
||||||
//Case for sliders - bump notes down and right, rather than up and left.
|
//Case for sliders - bump notes down and right, rather than up and left.
|
||||||
sliderStack++;
|
sliderStack++;
|
||||||
beatmap.HitObjects[j].StackHeight -= sliderStack;
|
beatmap.HitObjects[j].StackHeight -= sliderStack;
|
||||||
startTime = (beatmap.HitObjects[j] as IHasEndTime)?.EndTime ?? beatmap.HitObjects[i].StartTime;
|
startTime = (beatmap.HitObjects[j] as IHasEndTime)?.EndTime ?? beatmap.HitObjects[j].StartTime;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,13 +2,19 @@
|
|||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Framework.Input.StateChanges;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
|
using osu.Game.Rulesets.Osu.Replays;
|
||||||
|
using osu.Game.Rulesets.UI;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Mods
|
namespace osu.Game.Rulesets.Osu.Mods
|
||||||
{
|
{
|
||||||
public class OsuModAutopilot : Mod
|
public class OsuModAutopilot : Mod, IApplicableFailOverride, IUpdatableByPlayfield, IApplicableToDrawableRuleset<OsuHitObject>
|
||||||
{
|
{
|
||||||
public override string Name => "Autopilot";
|
public override string Name => "Autopilot";
|
||||||
public override string Acronym => "AP";
|
public override string Acronym => "AP";
|
||||||
@ -17,5 +23,40 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
public override string Description => @"Automatic cursor movement - just follow the rhythm.";
|
public override string Description => @"Automatic cursor movement - just follow the rhythm.";
|
||||||
public override double ScoreMultiplier => 1;
|
public override double ScoreMultiplier => 1;
|
||||||
public override Type[] IncompatibleMods => new[] { typeof(OsuModSpunOut), typeof(ModRelax), typeof(ModSuddenDeath), typeof(ModNoFail), typeof(ModAutoplay) };
|
public override Type[] IncompatibleMods => new[] { typeof(OsuModSpunOut), typeof(ModRelax), typeof(ModSuddenDeath), typeof(ModNoFail), typeof(ModAutoplay) };
|
||||||
|
|
||||||
|
public bool AllowFail => false;
|
||||||
|
|
||||||
|
private OsuInputManager inputManager;
|
||||||
|
|
||||||
|
private List<OsuReplayFrame> replayFrames;
|
||||||
|
|
||||||
|
private int currentFrame;
|
||||||
|
|
||||||
|
public void Update(Playfield playfield)
|
||||||
|
{
|
||||||
|
if (currentFrame == replayFrames.Count - 1) return;
|
||||||
|
|
||||||
|
double time = playfield.Time.Current;
|
||||||
|
|
||||||
|
// Very naive implementation of autopilot based on proximity to replay frames.
|
||||||
|
// TODO: this needs to be based on user interactions to better match stable (pausing until judgement is registered).
|
||||||
|
if (Math.Abs(replayFrames[currentFrame + 1].Time - time) <= Math.Abs(replayFrames[currentFrame].Time - time))
|
||||||
|
{
|
||||||
|
currentFrame++;
|
||||||
|
new MousePositionAbsoluteInput { Position = playfield.ToScreenSpace(replayFrames[currentFrame].Position) }.Apply(inputManager.CurrentState, inputManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Implement the functionality to automatically spin spinners
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ApplyToDrawableRuleset(DrawableRuleset<OsuHitObject> drawableRuleset)
|
||||||
|
{
|
||||||
|
// Grab the input manager to disable the user's cursor, and for future use
|
||||||
|
inputManager = (OsuInputManager)drawableRuleset.KeyBindingInputManager;
|
||||||
|
inputManager.AllowUserCursorMovement = false;
|
||||||
|
|
||||||
|
// Generate the replay frames the cursor should follow
|
||||||
|
replayFrames = new OsuAutoGenerator(drawableRuleset.Beatmap).Generate().Frames.Cast<OsuReplayFrame>().ToList();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -69,7 +69,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
|||||||
var spanProgress = slider.ProgressAt(completionProgress);
|
var spanProgress = slider.ProgressAt(completionProgress);
|
||||||
|
|
||||||
double start = 0;
|
double start = 0;
|
||||||
double end = SnakingIn.Value ? MathHelper.Clamp((Time.Current - (slider.StartTime - slider.TimePreempt)) / slider.TimeFadeIn, 0, 1) : 1;
|
double end = SnakingIn.Value ? MathHelper.Clamp((Time.Current - (slider.StartTime - slider.TimePreempt)) / (slider.TimePreempt / 3), 0, 1) : 1;
|
||||||
|
|
||||||
if (span >= slider.SpanCount() - 1)
|
if (span >= slider.SpanCount() - 1)
|
||||||
{
|
{
|
||||||
|
@ -69,7 +69,7 @@ namespace osu.Game.Rulesets.Osu.Objects
|
|||||||
base.ApplyDefaultsToSelf(controlPointInfo, difficulty);
|
base.ApplyDefaultsToSelf(controlPointInfo, difficulty);
|
||||||
|
|
||||||
TimePreempt = (float)BeatmapDifficulty.DifficultyRange(difficulty.ApproachRate, 1800, 1200, 450);
|
TimePreempt = (float)BeatmapDifficulty.DifficultyRange(difficulty.ApproachRate, 1800, 1200, 450);
|
||||||
TimeFadeIn = (float)BeatmapDifficulty.DifficultyRange(difficulty.ApproachRate, 1200, 800, 300);
|
TimeFadeIn = 400; // as per osu-stable
|
||||||
|
|
||||||
Scale = (1.0f - 0.7f * (difficulty.CircleSize - 5) / 5) / 2;
|
Scale = (1.0f - 0.7f * (difficulty.CircleSize - 5) / 5) / 2;
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@ namespace osu.Game.Rulesets.Osu.Objects
|
|||||||
public double EndTime => StartTime + this.SpanCount() * Path.Distance / Velocity;
|
public double EndTime => StartTime + this.SpanCount() * Path.Distance / Velocity;
|
||||||
public double Duration => EndTime - StartTime;
|
public double Duration => EndTime - StartTime;
|
||||||
|
|
||||||
private Cached<Vector2> endPositionCache;
|
private readonly Cached<Vector2> endPositionCache = new Cached<Vector2>();
|
||||||
|
|
||||||
public override Vector2 EndPosition => endPositionCache.IsValid ? endPositionCache.Value : endPositionCache.Value = Position + this.CurvePositionAt(1);
|
public override Vector2 EndPosition => endPositionCache.IsValid ? endPositionCache.Value : endPositionCache.Value = Position + this.CurvePositionAt(1);
|
||||||
|
|
||||||
|
@ -18,6 +18,12 @@ namespace osu.Game.Rulesets.Osu
|
|||||||
set => ((OsuKeyBindingContainer)KeyBindingContainer).AllowUserPresses = value;
|
set => ((OsuKeyBindingContainer)KeyBindingContainer).AllowUserPresses = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether the user's cursor movement events should be accepted.
|
||||||
|
/// Can be used to block only movement while still accepting button input.
|
||||||
|
/// </summary>
|
||||||
|
public bool AllowUserCursorMovement { get; set; } = true;
|
||||||
|
|
||||||
protected override RulesetKeyBindingContainer CreateKeyBindingContainer(RulesetInfo ruleset, int variant, SimultaneousBindingMode unique)
|
protected override RulesetKeyBindingContainer CreateKeyBindingContainer(RulesetInfo ruleset, int variant, SimultaneousBindingMode unique)
|
||||||
=> new OsuKeyBindingContainer(ruleset, variant, unique);
|
=> new OsuKeyBindingContainer(ruleset, variant, unique);
|
||||||
|
|
||||||
@ -26,6 +32,13 @@ namespace osu.Game.Rulesets.Osu
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override bool Handle(UIEvent e)
|
||||||
|
{
|
||||||
|
if (e is MouseMoveEvent && !AllowUserCursorMovement) return false;
|
||||||
|
|
||||||
|
return base.Handle(e);
|
||||||
|
}
|
||||||
|
|
||||||
private class OsuKeyBindingContainer : RulesetKeyBindingContainer
|
private class OsuKeyBindingContainer : RulesetKeyBindingContainer
|
||||||
{
|
{
|
||||||
public bool AllowUserPresses = true;
|
public bool AllowUserPresses = true;
|
||||||
|
@ -0,0 +1,278 @@
|
|||||||
|
{
|
||||||
|
"Mappings": [{
|
||||||
|
"StartTime": 32165,
|
||||||
|
"Objects": [{
|
||||||
|
"StartTime": 32165,
|
||||||
|
"EndTime": 32165,
|
||||||
|
"X": 32,
|
||||||
|
"Y": 320
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 32517,
|
||||||
|
"Objects": [{
|
||||||
|
"StartTime": 32517,
|
||||||
|
"EndTime": 32517,
|
||||||
|
"X": 246.396057,
|
||||||
|
"Y": 182.396057
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 32605,
|
||||||
|
"Objects": [{
|
||||||
|
"StartTime": 32605,
|
||||||
|
"EndTime": 32605,
|
||||||
|
"X": 249.597382,
|
||||||
|
"Y": 185.597382
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 32693,
|
||||||
|
"Objects": [{
|
||||||
|
"StartTime": 32693,
|
||||||
|
"EndTime": 32693,
|
||||||
|
"X": 252.798691,
|
||||||
|
"Y": 188.798691
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 32781,
|
||||||
|
"Objects": [{
|
||||||
|
"StartTime": 32781,
|
||||||
|
"EndTime": 32781,
|
||||||
|
"X": 256,
|
||||||
|
"Y": 192
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 33248,
|
||||||
|
"Objects": [{
|
||||||
|
"StartTime": 33248,
|
||||||
|
"EndTime": 33248,
|
||||||
|
"X": 39.3960648,
|
||||||
|
"Y": 76.3960648
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 33307,
|
||||||
|
"Objects": [{
|
||||||
|
"StartTime": 33307,
|
||||||
|
"EndTime": 33307,
|
||||||
|
"X": 42.5973778,
|
||||||
|
"Y": 79.597374
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 33383,
|
||||||
|
"Objects": [{
|
||||||
|
"StartTime": 33383,
|
||||||
|
"EndTime": 33383,
|
||||||
|
"X": 45.798687,
|
||||||
|
"Y": 82.79869
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 33459,
|
||||||
|
"Objects": [{
|
||||||
|
"StartTime": 33459,
|
||||||
|
"EndTime": 33459,
|
||||||
|
"X": 49,
|
||||||
|
"Y": 86
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 33635,
|
||||||
|
"EndTime": 33635,
|
||||||
|
"X": 123.847847,
|
||||||
|
"Y": 85.7988
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 33811,
|
||||||
|
"EndTime": 33811,
|
||||||
|
"X": 198.6957,
|
||||||
|
"Y": 85.5975952
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 33988,
|
||||||
|
"EndTime": 33988,
|
||||||
|
"X": 273.9688,
|
||||||
|
"Y": 85.39525
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 34164,
|
||||||
|
"EndTime": 34164,
|
||||||
|
"X": 348.816681,
|
||||||
|
"Y": 85.19404
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 34246,
|
||||||
|
"EndTime": 34246,
|
||||||
|
"X": 398.998718,
|
||||||
|
"Y": 85.05914
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 34341,
|
||||||
|
"Objects": [{
|
||||||
|
"StartTime": 34341,
|
||||||
|
"EndTime": 34341,
|
||||||
|
"X": 401.201324,
|
||||||
|
"Y": 88.20131
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 34400,
|
||||||
|
"Objects": [{
|
||||||
|
"StartTime": 34400,
|
||||||
|
"EndTime": 34400,
|
||||||
|
"X": 404.402618,
|
||||||
|
"Y": 91.402626
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 34459,
|
||||||
|
"Objects": [{
|
||||||
|
"StartTime": 34459,
|
||||||
|
"EndTime": 34459,
|
||||||
|
"X": 407.603943,
|
||||||
|
"Y": 94.6039352
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 34989,
|
||||||
|
"Objects": [{
|
||||||
|
"StartTime": 34989,
|
||||||
|
"EndTime": 34989,
|
||||||
|
"X": 163,
|
||||||
|
"Y": 138
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 35018,
|
||||||
|
"EndTime": 35018,
|
||||||
|
"X": 188,
|
||||||
|
"Y": 138
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 35106,
|
||||||
|
"Objects": [{
|
||||||
|
"StartTime": 35106,
|
||||||
|
"EndTime": 35106,
|
||||||
|
"X": 163,
|
||||||
|
"Y": 138
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 35135,
|
||||||
|
"EndTime": 35135,
|
||||||
|
"X": 188,
|
||||||
|
"Y": 138
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 35224,
|
||||||
|
"Objects": [{
|
||||||
|
"StartTime": 35224,
|
||||||
|
"EndTime": 35224,
|
||||||
|
"X": 163,
|
||||||
|
"Y": 138
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 35253,
|
||||||
|
"EndTime": 35253,
|
||||||
|
"X": 188,
|
||||||
|
"Y": 138
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 35695,
|
||||||
|
"Objects": [{
|
||||||
|
"StartTime": 35695,
|
||||||
|
"EndTime": 35695,
|
||||||
|
"X": 166,
|
||||||
|
"Y": 76
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 35871,
|
||||||
|
"EndTime": 35871,
|
||||||
|
"X": 240.99855,
|
||||||
|
"Y": 75.53417
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 36011,
|
||||||
|
"EndTime": 36011,
|
||||||
|
"X": 315.9971,
|
||||||
|
"Y": 75.0683441
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 36106,
|
||||||
|
"Objects": [{
|
||||||
|
"StartTime": 36106,
|
||||||
|
"EndTime": 36106,
|
||||||
|
"X": 315,
|
||||||
|
"Y": 75
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 36282,
|
||||||
|
"EndTime": 36282,
|
||||||
|
"X": 240.001526,
|
||||||
|
"Y": 75.47769
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 36422,
|
||||||
|
"EndTime": 36422,
|
||||||
|
"X": 165.003052,
|
||||||
|
"Y": 75.95539
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 36518,
|
||||||
|
"Objects": [{
|
||||||
|
"StartTime": 36518,
|
||||||
|
"EndTime": 36518,
|
||||||
|
"X": 166,
|
||||||
|
"Y": 76
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 36694,
|
||||||
|
"EndTime": 36694,
|
||||||
|
"X": 240.99855,
|
||||||
|
"Y": 75.53417
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 36834,
|
||||||
|
"EndTime": 36834,
|
||||||
|
"X": 315.9971,
|
||||||
|
"Y": 75.0683441
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 36929,
|
||||||
|
"Objects": [{
|
||||||
|
"StartTime": 36929,
|
||||||
|
"EndTime": 36929,
|
||||||
|
"X": 315,
|
||||||
|
"Y": 75
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 37105,
|
||||||
|
"EndTime": 37105,
|
||||||
|
"X": 240.001526,
|
||||||
|
"Y": 75.47769
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"StartTime": 37245,
|
||||||
|
"EndTime": 37245,
|
||||||
|
"X": 165.003052,
|
||||||
|
"Y": 75.95539
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
osu file format v3
|
||||||
|
|
||||||
|
[Difficulty]
|
||||||
|
HPDrainRate:3
|
||||||
|
CircleSize:5
|
||||||
|
OverallDifficulty:8
|
||||||
|
ApproachRate:8
|
||||||
|
SliderMultiplier:1.5
|
||||||
|
SliderTickRate:2
|
||||||
|
|
||||||
|
[TimingPoints]
|
||||||
|
48,352.941176470588,4,1,1,100,1,0
|
||||||
|
|
||||||
|
[HitObjects]
|
||||||
|
// Hit circles
|
||||||
|
32,320,32165,5,2,0:0:0:0:
|
||||||
|
256,192,32517,5,0,0:0:0:0:
|
||||||
|
256,192,32605,1,0,0:0:0:0:
|
||||||
|
256,192,32693,1,0,0:0:0:0:
|
||||||
|
256,192,32781,1,0,0:0:0:0:
|
||||||
|
|
||||||
|
// Hit circles on slider endpoints
|
||||||
|
49,86,33248,1,0,0:0:0:0:
|
||||||
|
49,86,33307,1,0,0:0:0:0:
|
||||||
|
49,86,33383,1,0,0:0:0:0:
|
||||||
|
49,86,33459,2,0,L|421:85,1,350
|
||||||
|
398,85,34341,1,0,0:0:0:0:
|
||||||
|
398,85,34400,1,0,0:0:0:0:
|
||||||
|
398,85,34459,1,0,0:0:0:0:
|
||||||
|
|
||||||
|
// Sliders
|
||||||
|
163,138,34989,2,0,L|196:138,1,25
|
||||||
|
163,138,35106,2,0,L|196:138,1,25
|
||||||
|
163,138,35224,2,0,L|196:138,1,25
|
||||||
|
|
||||||
|
// Reversed sliders
|
||||||
|
166,76,35695,2,0,L|327:75,1,150
|
||||||
|
315,75,36106,2,0,L|158:76,1,150
|
||||||
|
166,76,36518,2,0,L|327:75,1,150
|
||||||
|
315,75,36929,2,0,L|158:76,1,150
|
@ -13,13 +13,15 @@ namespace osu.Game.Rulesets.Osu.UI
|
|||||||
protected override Container<Drawable> Content => content;
|
protected override Container<Drawable> Content => content;
|
||||||
private readonly Container content;
|
private readonly Container content;
|
||||||
|
|
||||||
|
private const float playfield_size_adjust = 0.8f;
|
||||||
|
|
||||||
public OsuPlayfieldAdjustmentContainer()
|
public OsuPlayfieldAdjustmentContainer()
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre;
|
Anchor = Anchor.Centre;
|
||||||
Origin = Anchor.Centre;
|
Origin = Anchor.Centre;
|
||||||
|
|
||||||
// Calculated from osu!stable as 512 (default gamefield size) / 640 (default window size)
|
// Calculated from osu!stable as 512 (default gamefield size) / 640 (default window size)
|
||||||
Size = new Vector2(0.8f);
|
Size = new Vector2(playfield_size_adjust);
|
||||||
|
|
||||||
InternalChild = new Container
|
InternalChild = new Container
|
||||||
{
|
{
|
||||||
@ -41,7 +43,19 @@ namespace osu.Game.Rulesets.Osu.UI
|
|||||||
{
|
{
|
||||||
base.Update();
|
base.Update();
|
||||||
|
|
||||||
|
// The following calculation results in a constant of 1.6 when OsuPlayfieldAdjustmentContainer
|
||||||
|
// is consuming the full game_size. This matches the osu-stable "magic ratio".
|
||||||
|
//
|
||||||
|
// game_size = DrawSizePreservingFillContainer.TargetSize = new Vector2(1024, 768)
|
||||||
|
//
|
||||||
|
// Parent is a 4:3 aspect enforced, using height as the constricting dimension
|
||||||
|
// Parent.ChildSize.X = min(game_size.X, game_size.Y * (4 / 3)) * playfield_size_adjust
|
||||||
|
// Parent.ChildSize.X = 819.2
|
||||||
|
//
|
||||||
|
// Scale = 819.2 / 512
|
||||||
|
// Scale = 1.6
|
||||||
Scale = new Vector2(Parent.ChildSize.X / OsuPlayfield.BASE_SIZE.X);
|
Scale = new Vector2(Parent.ChildSize.X / OsuPlayfield.BASE_SIZE.X);
|
||||||
|
// Size = 0.625
|
||||||
Size = Vector2.Divide(Vector2.One, Scale);
|
Size = Vector2.Divide(Vector2.One, Scale);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,14 +13,6 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="Info.plist" />
|
<None Include="Info.plist" />
|
||||||
<None Include="Entitlements.plist" />
|
<None Include="Entitlements.plist" />
|
||||||
<None Include="..\osu.iOS\libbass.a">
|
|
||||||
<Link>libbass.a</Link>
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</None>
|
|
||||||
<None Include="..\osu.iOS\libbass_fx.a">
|
|
||||||
<Link>libbass_fx.a</Link>
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</None>
|
|
||||||
<LinkDescription Include="..\osu.iOS\Linker.xml">
|
<LinkDescription Include="..\osu.iOS\Linker.xml">
|
||||||
<Link>Linker.xml</Link>
|
<Link>Linker.xml</Link>
|
||||||
</LinkDescription>
|
</LinkDescription>
|
||||||
|
@ -20,10 +20,7 @@ namespace osu.Game.Rulesets.Taiko.Tests
|
|||||||
[NonParallelizable]
|
[NonParallelizable]
|
||||||
[TestCase("basic")]
|
[TestCase("basic")]
|
||||||
[TestCase("slider-generating-drumroll")]
|
[TestCase("slider-generating-drumroll")]
|
||||||
public new void Test(string name)
|
public void Test(string name) => base.Test(name);
|
||||||
{
|
|
||||||
base.Test(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override IEnumerable<ConvertValue> CreateConvertValue(HitObject hitObject)
|
protected override IEnumerable<ConvertValue> CreateConvertValue(HitObject hitObject)
|
||||||
{
|
{
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" />
|
||||||
<PackageReference Include="NUnit" Version="3.12.0" />
|
<PackageReference Include="NUnit" Version="3.12.0" />
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="3.13.0" />
|
<PackageReference Include="NUnit3TestAdapter" Version="3.14.0" />
|
||||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<PropertyGroup Label="Project">
|
<PropertyGroup Label="Project">
|
||||||
|
@ -13,14 +13,6 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="Info.plist" />
|
<None Include="Info.plist" />
|
||||||
<None Include="Entitlements.plist" />
|
<None Include="Entitlements.plist" />
|
||||||
<None Include="..\osu.iOS\libbass.a">
|
|
||||||
<Link>libbass.a</Link>
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</None>
|
|
||||||
<None Include="..\osu.iOS\libbass_fx.a">
|
|
||||||
<Link>libbass_fx.a</Link>
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</None>
|
|
||||||
<LinkDescription Include="..\osu.iOS\Linker.xml">
|
<LinkDescription Include="..\osu.iOS\Linker.xml">
|
||||||
<Link>Linker.xml</Link>
|
<Link>Linker.xml</Link>
|
||||||
</LinkDescription>
|
</LinkDescription>
|
||||||
|
@ -482,5 +482,17 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
|||||||
Assert.AreEqual(hitObjects[0].Samples[0].Bank, hitObjects[0].Samples[1].Bank);
|
Assert.AreEqual(hitObjects[0].Samples[0].Bank, hitObjects[0].Samples[1].Bank);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestInvalidEventStillPasses()
|
||||||
|
{
|
||||||
|
var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false };
|
||||||
|
|
||||||
|
using (var badResStream = TestResources.OpenResource("invalid-events.osu"))
|
||||||
|
using (var badStream = new StreamReader(badResStream))
|
||||||
|
{
|
||||||
|
Assert.DoesNotThrow(() => decoder.Decode(badStream));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
14
osu.Game.Tests/Resources/invalid-events.osu
Normal file
14
osu.Game.Tests/Resources/invalid-events.osu
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
osu file format v14
|
||||||
|
|
||||||
|
[Events]
|
||||||
|
bad,event,this,should,fail
|
||||||
|
//Background and Video events
|
||||||
|
0,0,"machinetop_background.jpg",0,0
|
||||||
|
//Break Periods
|
||||||
|
2,122474,140135
|
||||||
|
//Storyboard Layer 0 (Background)
|
||||||
|
this,is,also,bad
|
||||||
|
//Storyboard Layer 1 (Fail)
|
||||||
|
//Storyboard Layer 2 (Pass)
|
||||||
|
//Storyboard Layer 3 (Foreground)
|
||||||
|
//Storyboard Sound Samples
|
@ -119,14 +119,14 @@ namespace osu.Game.Tests.Visual.Background
|
|||||||
{
|
{
|
||||||
performFullSetup();
|
performFullSetup();
|
||||||
createFakeStoryboard();
|
createFakeStoryboard();
|
||||||
AddStep("Storyboard Enabled", () =>
|
AddStep("Enable Storyboard", () =>
|
||||||
{
|
{
|
||||||
player.ReplacesBackground.Value = true;
|
player.ReplacesBackground.Value = true;
|
||||||
player.StoryboardEnabled.Value = true;
|
player.StoryboardEnabled.Value = true;
|
||||||
});
|
});
|
||||||
waitForDim();
|
waitForDim();
|
||||||
AddAssert("Background is invisible, storyboard is visible", () => songSelect.IsBackgroundInvisible() && player.IsStoryboardVisible);
|
AddAssert("Background is invisible, storyboard is visible", () => songSelect.IsBackgroundInvisible() && player.IsStoryboardVisible);
|
||||||
AddStep("Storyboard Disabled", () =>
|
AddStep("Disable Storyboard", () =>
|
||||||
{
|
{
|
||||||
player.ReplacesBackground.Value = false;
|
player.ReplacesBackground.Value = false;
|
||||||
player.StoryboardEnabled.Value = false;
|
player.StoryboardEnabled.Value = false;
|
||||||
@ -149,22 +149,44 @@ namespace osu.Game.Tests.Visual.Background
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Check if the <see cref="UserDimContainer"/> is properly accepting user-defined visual changes at all.
|
/// Ensure <see cref="UserDimContainer"/> is properly accepting user-defined visual changes for a background.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Test]
|
[Test]
|
||||||
public void DisableUserDimTest()
|
public void DisableUserDimBackgroundTest()
|
||||||
{
|
{
|
||||||
performFullSetup();
|
performFullSetup();
|
||||||
waitForDim();
|
waitForDim();
|
||||||
AddAssert("Screen is dimmed and blur applied", () => songSelect.IsBackgroundDimmed() && songSelect.IsUserBlurApplied());
|
AddAssert("Screen is dimmed and blur applied", () => songSelect.IsBackgroundDimmed() && songSelect.IsUserBlurApplied());
|
||||||
AddStep("EnableUserDim disabled", () => songSelect.DimEnabled.Value = false);
|
AddStep("Enable user dim", () => songSelect.DimEnabled.Value = false);
|
||||||
waitForDim();
|
waitForDim();
|
||||||
AddAssert("Screen is undimmed and user blur removed", () => songSelect.IsBackgroundUndimmed() && songSelect.IsUserBlurDisabled());
|
AddAssert("Screen is undimmed and user blur removed", () => songSelect.IsBackgroundUndimmed() && songSelect.IsUserBlurDisabled());
|
||||||
AddStep("EnableUserDim enabled", () => songSelect.DimEnabled.Value = true);
|
AddStep("Disable user dim", () => songSelect.DimEnabled.Value = true);
|
||||||
waitForDim();
|
waitForDim();
|
||||||
AddAssert("Screen is dimmed and blur applied", () => songSelect.IsBackgroundDimmed() && songSelect.IsUserBlurApplied());
|
AddAssert("Screen is dimmed and blur applied", () => songSelect.IsBackgroundDimmed() && songSelect.IsUserBlurApplied());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Ensure <see cref="UserDimContainer"/> is properly accepting user-defined visual changes for a storyboard.
|
||||||
|
/// </summary>
|
||||||
|
[Test]
|
||||||
|
public void DisableUserDimStoryboardTest()
|
||||||
|
{
|
||||||
|
performFullSetup();
|
||||||
|
createFakeStoryboard();
|
||||||
|
AddStep("Enable Storyboard", () =>
|
||||||
|
{
|
||||||
|
player.ReplacesBackground.Value = true;
|
||||||
|
player.StoryboardEnabled.Value = true;
|
||||||
|
});
|
||||||
|
AddStep("Enable user dim", () => player.DimmableStoryboard.EnableUserDim.Value = true);
|
||||||
|
AddStep("Set dim level to 1", () => songSelect.DimLevel.Value = 1f);
|
||||||
|
waitForDim();
|
||||||
|
AddAssert("Storyboard is invisible", () => !player.IsStoryboardVisible);
|
||||||
|
AddStep("Disable user dim", () => player.DimmableStoryboard.EnableUserDim.Value = false);
|
||||||
|
waitForDim();
|
||||||
|
AddAssert("Storyboard is visible", () => player.IsStoryboardVisible);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Check if the visual settings container retains dim and blur when pausing
|
/// Check if the visual settings container retains dim and blur when pausing
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -1,8 +1,11 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Timing;
|
||||||
using osu.Game.Beatmaps.Timing;
|
using osu.Game.Beatmaps.Timing;
|
||||||
using osu.Game.Screens.Play;
|
using osu.Game.Screens.Play;
|
||||||
|
|
||||||
@ -11,78 +14,172 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class TestSceneBreakOverlay : OsuTestScene
|
public class TestSceneBreakOverlay : OsuTestScene
|
||||||
{
|
{
|
||||||
private readonly BreakOverlay breakOverlay;
|
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||||
|
{
|
||||||
|
typeof(BreakOverlay),
|
||||||
|
};
|
||||||
|
|
||||||
|
private readonly TestBreakOverlay breakOverlay;
|
||||||
|
|
||||||
|
private readonly IReadOnlyList<BreakPeriod> testBreaks = new List<BreakPeriod>
|
||||||
|
{
|
||||||
|
new BreakPeriod
|
||||||
|
{
|
||||||
|
StartTime = 1000,
|
||||||
|
EndTime = 5000,
|
||||||
|
},
|
||||||
|
new BreakPeriod
|
||||||
|
{
|
||||||
|
StartTime = 6000,
|
||||||
|
EndTime = 13500,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
public TestSceneBreakOverlay()
|
public TestSceneBreakOverlay()
|
||||||
{
|
{
|
||||||
Child = breakOverlay = new BreakOverlay(true);
|
Add(breakOverlay = new TestBreakOverlay(true));
|
||||||
|
|
||||||
AddStep("2s break", () => startBreak(2000));
|
|
||||||
AddStep("5s break", () => startBreak(5000));
|
|
||||||
AddStep("10s break", () => startBreak(10000));
|
|
||||||
AddStep("15s break", () => startBreak(15000));
|
|
||||||
AddStep("2s, 2s", startMultipleBreaks);
|
|
||||||
AddStep("0.5s, 0.7s, 1s, 2s", startAnotherMultipleBreaks);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void startBreak(double duration)
|
[Test]
|
||||||
|
public void TestShowBreaks()
|
||||||
{
|
{
|
||||||
breakOverlay.Breaks = new List<BreakPeriod>
|
setClock(false);
|
||||||
|
|
||||||
|
addShowBreakStep(2);
|
||||||
|
addShowBreakStep(5);
|
||||||
|
addShowBreakStep(15);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestNoEffectsBreak()
|
||||||
|
{
|
||||||
|
var shortBreak = new BreakPeriod { EndTime = 500 };
|
||||||
|
|
||||||
|
setClock(true);
|
||||||
|
loadBreaksStep("short break", new[] { shortBreak });
|
||||||
|
|
||||||
|
addBreakSeeks(shortBreak, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestMultipleBreaks()
|
||||||
|
{
|
||||||
|
setClock(true);
|
||||||
|
loadBreaksStep("multiple breaks", testBreaks);
|
||||||
|
|
||||||
|
foreach (var b in testBreaks)
|
||||||
|
addBreakSeeks(b, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestRewindBreaks()
|
||||||
|
{
|
||||||
|
setClock(true);
|
||||||
|
loadBreaksStep("multiple breaks", testBreaks);
|
||||||
|
|
||||||
|
foreach (var b in testBreaks.Reverse())
|
||||||
|
addBreakSeeks(b, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestSkipBreaks()
|
||||||
|
{
|
||||||
|
setClock(true);
|
||||||
|
loadBreaksStep("multiple breaks", testBreaks);
|
||||||
|
|
||||||
|
seekAndAssertBreak("seek to break start", testBreaks[1].StartTime, true);
|
||||||
|
AddAssert("is skipped to break #2", () => breakOverlay.CurrentBreakIndex == 1);
|
||||||
|
|
||||||
|
seekAndAssertBreak("seek to break middle", testBreaks[1].StartTime + testBreaks[1].Duration / 2, true);
|
||||||
|
seekAndAssertBreak("seek to break end", testBreaks[1].EndTime, false);
|
||||||
|
seekAndAssertBreak("seek to break after end", testBreaks[1].EndTime + 500, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addShowBreakStep(double seconds)
|
||||||
|
{
|
||||||
|
AddStep($"show '{seconds}s' break", () => breakOverlay.Breaks = new List<BreakPeriod>
|
||||||
{
|
{
|
||||||
new BreakPeriod
|
new BreakPeriod
|
||||||
{
|
{
|
||||||
StartTime = Clock.CurrentTime,
|
StartTime = Clock.CurrentTime,
|
||||||
EndTime = Clock.CurrentTime + duration,
|
EndTime = Clock.CurrentTime + seconds * 1000,
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void startMultipleBreaks()
|
private void setClock(bool useManual)
|
||||||
{
|
{
|
||||||
double currentTime = Clock.CurrentTime;
|
AddStep($"set {(useManual ? "manual" : "realtime")} clock", () => breakOverlay.SwitchClock(useManual));
|
||||||
|
|
||||||
breakOverlay.Breaks = new List<BreakPeriod>
|
|
||||||
{
|
|
||||||
new BreakPeriod
|
|
||||||
{
|
|
||||||
StartTime = currentTime,
|
|
||||||
EndTime = currentTime + 2000,
|
|
||||||
},
|
|
||||||
new BreakPeriod
|
|
||||||
{
|
|
||||||
StartTime = currentTime + 4000,
|
|
||||||
EndTime = currentTime + 6000,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void startAnotherMultipleBreaks()
|
private void loadBreaksStep(string breakDescription, IReadOnlyList<BreakPeriod> breaks)
|
||||||
{
|
{
|
||||||
double currentTime = Clock.CurrentTime;
|
AddStep($"load {breakDescription}", () => breakOverlay.Breaks = breaks);
|
||||||
|
seekAndAssertBreak("seek back to 0", 0, false);
|
||||||
|
}
|
||||||
|
|
||||||
breakOverlay.Breaks = new List<BreakPeriod>
|
private void addBreakSeeks(BreakPeriod b, bool isReversed)
|
||||||
|
{
|
||||||
|
if (isReversed)
|
||||||
{
|
{
|
||||||
new BreakPeriod // Duration is less than 650 - too short to appear
|
seekAndAssertBreak("seek to break after end", b.EndTime + 500, false);
|
||||||
{
|
seekAndAssertBreak("seek to break end", b.EndTime, false);
|
||||||
StartTime = currentTime,
|
seekAndAssertBreak("seek to break middle", b.StartTime + b.Duration / 2, b.HasEffect);
|
||||||
EndTime = currentTime + 500,
|
seekAndAssertBreak("seek to break start", b.StartTime, b.HasEffect);
|
||||||
},
|
}
|
||||||
new BreakPeriod
|
else
|
||||||
{
|
{
|
||||||
StartTime = currentTime + 1500,
|
seekAndAssertBreak("seek to break start", b.StartTime, b.HasEffect);
|
||||||
EndTime = currentTime + 2200,
|
seekAndAssertBreak("seek to break middle", b.StartTime + b.Duration / 2, b.HasEffect);
|
||||||
},
|
seekAndAssertBreak("seek to break end", b.EndTime, false);
|
||||||
new BreakPeriod
|
seekAndAssertBreak("seek to break after end", b.EndTime + 500, false);
|
||||||
{
|
}
|
||||||
StartTime = currentTime + 3200,
|
}
|
||||||
EndTime = currentTime + 4200,
|
|
||||||
},
|
private void seekAndAssertBreak(string seekStepDescription, double time, bool shouldBeBreak)
|
||||||
new BreakPeriod
|
{
|
||||||
{
|
AddStep(seekStepDescription, () => breakOverlay.ManualClockTime = time);
|
||||||
StartTime = currentTime + 5200,
|
AddAssert($"is{(!shouldBeBreak ? " not" : string.Empty)} break time", () =>
|
||||||
EndTime = currentTime + 7200,
|
{
|
||||||
}
|
breakOverlay.ProgressTime();
|
||||||
};
|
return breakOverlay.IsBreakTime.Value == shouldBeBreak;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TestBreakOverlay : BreakOverlay
|
||||||
|
{
|
||||||
|
private readonly FramedClock framedManualClock;
|
||||||
|
private readonly ManualClock manualClock;
|
||||||
|
private IFrameBasedClock originalClock;
|
||||||
|
|
||||||
|
public new int CurrentBreakIndex => base.CurrentBreakIndex;
|
||||||
|
|
||||||
|
public double ManualClockTime
|
||||||
|
{
|
||||||
|
get => manualClock.CurrentTime;
|
||||||
|
set => manualClock.CurrentTime = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TestBreakOverlay(bool letterboxing)
|
||||||
|
: base(letterboxing)
|
||||||
|
{
|
||||||
|
framedManualClock = new FramedClock(manualClock = new ManualClock());
|
||||||
|
ProcessCustomClock = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ProgressTime()
|
||||||
|
{
|
||||||
|
framedManualClock.ProcessFrame();
|
||||||
|
Update();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SwitchClock(bool setManual) => Clock = setManual ? framedManualClock : originalClock;
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
originalClock = Clock;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,32 +21,38 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
private readonly Container<DrawableStoryboard> storyboardContainer;
|
private readonly Container<DrawableStoryboard> storyboardContainer;
|
||||||
private DrawableStoryboard storyboard;
|
private DrawableStoryboard storyboard;
|
||||||
|
|
||||||
|
[Cached]
|
||||||
|
private MusicController musicController = new MusicController();
|
||||||
|
|
||||||
public TestSceneStoryboard()
|
public TestSceneStoryboard()
|
||||||
{
|
{
|
||||||
Clock = new FramedClock();
|
Clock = new FramedClock();
|
||||||
|
|
||||||
Add(new Container
|
AddRange(new Drawable[]
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
musicController,
|
||||||
Children = new Drawable[]
|
new Container
|
||||||
{
|
{
|
||||||
new Box
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
new Box
|
||||||
Colour = Color4.Black,
|
{
|
||||||
},
|
RelativeSizeAxes = Axes.Both,
|
||||||
storyboardContainer = new Container<DrawableStoryboard>
|
Colour = Color4.Black,
|
||||||
{
|
},
|
||||||
RelativeSizeAxes = Axes.Both,
|
storyboardContainer = new Container<DrawableStoryboard>
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
new NowPlayingOverlay
|
||||||
|
{
|
||||||
Add(new MusicController
|
Origin = Anchor.TopRight,
|
||||||
{
|
Anchor = Anchor.TopRight,
|
||||||
Origin = Anchor.TopRight,
|
State = { Value = Visibility.Visible },
|
||||||
Anchor = Anchor.TopRight,
|
}
|
||||||
State = { Value = Visibility.Visible },
|
|
||||||
});
|
});
|
||||||
|
|
||||||
AddStep("Restart", restart);
|
AddStep("Restart", restart);
|
||||||
|
15
osu.Game.Tests/Visual/Menus/TestSceneIntroTriangles.cs
Normal file
15
osu.Game.Tests/Visual/Menus/TestSceneIntroTriangles.cs
Normal file
@ -0,0 +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 NUnit.Framework;
|
||||||
|
using osu.Framework.Screens;
|
||||||
|
using osu.Game.Screens.Menu;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.Visual.Menus
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class TestSceneIntroTriangles : IntroTestScene
|
||||||
|
{
|
||||||
|
protected override IScreen CreateScreen() => new IntroTriangles();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,53 @@
|
|||||||
|
// 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.Game.Beatmaps;
|
||||||
|
using osu.Game.Online.Multiplayer;
|
||||||
|
using osu.Game.Screens.Multi.Match.Components;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.MathUtils;
|
||||||
|
using osu.Game.Audio;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.Visual.Multiplayer
|
||||||
|
{
|
||||||
|
[Cached(typeof(IPreviewTrackOwner))]
|
||||||
|
public class TestSceneMatchBeatmapPanel : MultiplayerTestScene, IPreviewTrackOwner
|
||||||
|
{
|
||||||
|
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||||
|
{
|
||||||
|
typeof(MatchBeatmapPanel)
|
||||||
|
};
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private PreviewTrackManager previewTrackManager { get; set; }
|
||||||
|
|
||||||
|
public TestSceneMatchBeatmapPanel()
|
||||||
|
{
|
||||||
|
Add(new MatchBeatmapPanel
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
});
|
||||||
|
|
||||||
|
Room.Playlist.Add(new PlaylistItem { Beatmap = new BeatmapInfo { OnlineBeatmapID = 1763072 } });
|
||||||
|
Room.Playlist.Add(new PlaylistItem { Beatmap = new BeatmapInfo { OnlineBeatmapID = 2101557 } });
|
||||||
|
Room.Playlist.Add(new PlaylistItem { Beatmap = new BeatmapInfo { OnlineBeatmapID = 1973466 } });
|
||||||
|
Room.Playlist.Add(new PlaylistItem { Beatmap = new BeatmapInfo { OnlineBeatmapID = 2109801 } });
|
||||||
|
Room.Playlist.Add(new PlaylistItem { Beatmap = new BeatmapInfo { OnlineBeatmapID = 1922035 } });
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
|
AddStep("Select random beatmap", () =>
|
||||||
|
{
|
||||||
|
Room.CurrentItem.Value = Room.Playlist[RNG.Next(Room.Playlist.Count)];
|
||||||
|
previewTrackManager.StopAnyPlaying(this);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -21,7 +21,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
typeof(Info),
|
typeof(Info),
|
||||||
typeof(HeaderButton),
|
typeof(HeaderButton),
|
||||||
typeof(ReadyButton),
|
typeof(ReadyButton),
|
||||||
typeof(ViewBeatmapButton)
|
typeof(MatchBeatmapPanel)
|
||||||
};
|
};
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
|
@ -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 osu.Game.Overlays.BeatmapSet;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Game.Screens.Select.Leaderboards;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.Visual.Online
|
||||||
|
{
|
||||||
|
public class TestSceneLeaderboardScopeSelector : OsuTestScene
|
||||||
|
{
|
||||||
|
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||||
|
{
|
||||||
|
typeof(LeaderboardScopeSelector),
|
||||||
|
};
|
||||||
|
|
||||||
|
public TestSceneLeaderboardScopeSelector()
|
||||||
|
{
|
||||||
|
Bindable<BeatmapLeaderboardScope> scope = new Bindable<BeatmapLeaderboardScope>();
|
||||||
|
|
||||||
|
Add(new LeaderboardScopeSelector
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
Current = { BindTarget = scope }
|
||||||
|
});
|
||||||
|
|
||||||
|
AddStep(@"Select global", () => scope.Value = BeatmapLeaderboardScope.Global);
|
||||||
|
AddStep(@"Select country", () => scope.Value = BeatmapLeaderboardScope.Country);
|
||||||
|
AddStep(@"Select friend", () => scope.Value = BeatmapLeaderboardScope.Friend);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -9,6 +9,8 @@ using osu.Game.Rulesets.Catch;
|
|||||||
using osu.Game.Rulesets.Mania;
|
using osu.Game.Rulesets.Mania;
|
||||||
using osu.Game.Rulesets.Osu;
|
using osu.Game.Rulesets.Osu;
|
||||||
using osu.Game.Rulesets.Taiko;
|
using osu.Game.Rulesets.Taiko;
|
||||||
|
using osu.Game.Users;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual.Online
|
namespace osu.Game.Tests.Visual.Online
|
||||||
{
|
{
|
||||||
@ -23,18 +25,25 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
public TestSceneProfileRulesetSelector()
|
public TestSceneProfileRulesetSelector()
|
||||||
{
|
{
|
||||||
ProfileRulesetSelector selector;
|
ProfileRulesetSelector selector;
|
||||||
|
Bindable<User> user = new Bindable<User>();
|
||||||
|
|
||||||
Child = selector = new ProfileRulesetSelector
|
Child = selector = new ProfileRulesetSelector
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
|
User = { BindTarget = user }
|
||||||
};
|
};
|
||||||
|
|
||||||
AddStep("set osu! as default", () => selector.SetDefaultRuleset(new OsuRuleset().RulesetInfo));
|
AddStep("set osu! as default", () => selector.SetDefaultRuleset(new OsuRuleset().RulesetInfo));
|
||||||
AddStep("set mania as default", () => selector.SetDefaultRuleset(new ManiaRuleset().RulesetInfo));
|
AddStep("set mania as default", () => selector.SetDefaultRuleset(new ManiaRuleset().RulesetInfo));
|
||||||
AddStep("set taiko as default", () => selector.SetDefaultRuleset(new TaikoRuleset().RulesetInfo));
|
AddStep("set taiko as default", () => selector.SetDefaultRuleset(new TaikoRuleset().RulesetInfo));
|
||||||
AddStep("set catch as default", () => selector.SetDefaultRuleset(new CatchRuleset().RulesetInfo));
|
AddStep("set catch as default", () => selector.SetDefaultRuleset(new CatchRuleset().RulesetInfo));
|
||||||
AddStep("select default ruleset", selector.SelectDefaultRuleset);
|
|
||||||
|
AddStep("User with osu as default", () => user.Value = new User { PlayMode = "osu" });
|
||||||
|
AddStep("User with mania as default", () => user.Value = new User { PlayMode = "mania" });
|
||||||
|
AddStep("User with taiko as default", () => user.Value = new User { PlayMode = "taiko" });
|
||||||
|
AddStep("User with catch as default", () => user.Value = new User { PlayMode = "fruits" });
|
||||||
|
AddStep("null user", () => user.Value = null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -69,28 +69,22 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
AddStep("null user", () => graph.User.Value = null);
|
AddStep("null user", () => graph.Statistics.Value = null);
|
||||||
AddStep("rank only", () =>
|
AddStep("rank only", () =>
|
||||||
{
|
{
|
||||||
graph.User.Value = new User
|
graph.Statistics.Value = new UserStatistics
|
||||||
{
|
{
|
||||||
Statistics = new UserStatistics
|
Ranks = new UserStatistics.UserRanks { Global = 123456 },
|
||||||
{
|
PP = 12345,
|
||||||
Ranks = new UserStatistics.UserRanks { Global = 123456 },
|
|
||||||
PP = 12345,
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
AddStep("with rank history", () =>
|
AddStep("with rank history", () =>
|
||||||
{
|
{
|
||||||
graph.User.Value = new User
|
graph.Statistics.Value = new UserStatistics
|
||||||
{
|
{
|
||||||
Statistics = new UserStatistics
|
Ranks = new UserStatistics.UserRanks { Global = 89000 },
|
||||||
{
|
PP = 12345,
|
||||||
Ranks = new UserStatistics.UserRanks { Global = 89000 },
|
|
||||||
PP = 12345,
|
|
||||||
},
|
|
||||||
RankHistory = new User.RankHistoryData
|
RankHistory = new User.RankHistoryData
|
||||||
{
|
{
|
||||||
Data = data,
|
Data = data,
|
||||||
@ -100,13 +94,10 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
|
|
||||||
AddStep("with zero values", () =>
|
AddStep("with zero values", () =>
|
||||||
{
|
{
|
||||||
graph.User.Value = new User
|
graph.Statistics.Value = new UserStatistics
|
||||||
{
|
{
|
||||||
Statistics = new UserStatistics
|
Ranks = new UserStatistics.UserRanks { Global = 89000 },
|
||||||
{
|
PP = 12345,
|
||||||
Ranks = new UserStatistics.UserRanks { Global = 89000 },
|
|
||||||
PP = 12345,
|
|
||||||
},
|
|
||||||
RankHistory = new User.RankHistoryData
|
RankHistory = new User.RankHistoryData
|
||||||
{
|
{
|
||||||
Data = dataWithZeros,
|
Data = dataWithZeros,
|
||||||
@ -116,13 +107,10 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
|
|
||||||
AddStep("small amount of data", () =>
|
AddStep("small amount of data", () =>
|
||||||
{
|
{
|
||||||
graph.User.Value = new User
|
graph.Statistics.Value = new UserStatistics
|
||||||
{
|
{
|
||||||
Statistics = new UserStatistics
|
Ranks = new UserStatistics.UserRanks { Global = 12000 },
|
||||||
{
|
PP = 12345,
|
||||||
Ranks = new UserStatistics.UserRanks { Global = 12000 },
|
|
||||||
PP = 12345,
|
|
||||||
},
|
|
||||||
RankHistory = new User.RankHistoryData
|
RankHistory = new User.RankHistoryData
|
||||||
{
|
{
|
||||||
Data = smallData,
|
Data = smallData,
|
||||||
@ -132,13 +120,10 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
|
|
||||||
AddStep("graph with edges", () =>
|
AddStep("graph with edges", () =>
|
||||||
{
|
{
|
||||||
graph.User.Value = new User
|
graph.Statistics.Value = new UserStatistics
|
||||||
{
|
{
|
||||||
Statistics = new UserStatistics
|
Ranks = new UserStatistics.UserRanks { Global = 12000 },
|
||||||
{
|
PP = 12345,
|
||||||
Ranks = new UserStatistics.UserRanks { Global = 12000 },
|
|
||||||
PP = 12345,
|
|
||||||
},
|
|
||||||
RankHistory = new User.RankHistoryData
|
RankHistory = new User.RankHistoryData
|
||||||
{
|
{
|
||||||
Data = edgyData,
|
Data = edgyData,
|
||||||
|
@ -50,12 +50,12 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
{
|
{
|
||||||
Current = 727,
|
Current = 727,
|
||||||
Progress = 69,
|
Progress = 69,
|
||||||
}
|
},
|
||||||
},
|
RankHistory = new User.RankHistoryData
|
||||||
RankHistory = new User.RankHistoryData
|
{
|
||||||
{
|
Mode = @"osu",
|
||||||
Mode = @"osu",
|
Data = Enumerable.Range(2345, 45).Concat(Enumerable.Range(2109, 40)).ToArray()
|
||||||
Data = Enumerable.Range(2345, 45).Concat(Enumerable.Range(2109, 40)).ToArray()
|
},
|
||||||
},
|
},
|
||||||
Badges = new[]
|
Badges = new[]
|
||||||
{
|
{
|
||||||
|
@ -0,0 +1,69 @@
|
|||||||
|
// 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 NUnit.Framework;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Game.Online.API;
|
||||||
|
using osu.Game.Online.API.Requests;
|
||||||
|
using osu.Game.Overlays.Profile.Header.Components;
|
||||||
|
using osu.Game.Users;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.Visual.Online
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class TestSceneUserProfilePreviousUsernames : OsuTestScene
|
||||||
|
{
|
||||||
|
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||||
|
{
|
||||||
|
typeof(PreviousUsernames)
|
||||||
|
};
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private IAPIProvider api { get; set; }
|
||||||
|
|
||||||
|
private readonly Bindable<User> user = new Bindable<User>();
|
||||||
|
|
||||||
|
public TestSceneUserProfilePreviousUsernames()
|
||||||
|
{
|
||||||
|
Child = new PreviousUsernames
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
User = { BindTarget = user },
|
||||||
|
};
|
||||||
|
|
||||||
|
User[] users =
|
||||||
|
{
|
||||||
|
new User { PreviousUsernames = new[] { "username1" } },
|
||||||
|
new User { PreviousUsernames = new[] { "longusername", "longerusername" } },
|
||||||
|
new User { PreviousUsernames = new[] { "test", "angelsim", "verylongusername" } },
|
||||||
|
new User { PreviousUsernames = new[] { "ihavenoidea", "howcani", "makethistext", "anylonger" } },
|
||||||
|
new User { PreviousUsernames = new string[0] },
|
||||||
|
null
|
||||||
|
};
|
||||||
|
|
||||||
|
AddStep("single username", () => user.Value = users[0]);
|
||||||
|
AddStep("two usernames", () => user.Value = users[1]);
|
||||||
|
AddStep("three usernames", () => user.Value = users[2]);
|
||||||
|
AddStep("four usernames", () => user.Value = users[3]);
|
||||||
|
AddStep("no username", () => user.Value = users[4]);
|
||||||
|
AddStep("null user", () => user.Value = users[5]);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
|
AddStep("online user (Angelsim)", () =>
|
||||||
|
{
|
||||||
|
var request = new GetUserRequest(1777162);
|
||||||
|
request.Success += user => this.user.Value = user;
|
||||||
|
api.Queue(request);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
109
osu.Game.Tests/Visual/Online/TestSceneUserRequest.cs
Normal file
109
osu.Game.Tests/Visual/Online/TestSceneUserRequest.cs
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
// 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.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Game.Online.API;
|
||||||
|
using osu.Game.Online.API.Requests;
|
||||||
|
using osu.Game.Rulesets;
|
||||||
|
using osu.Game.Rulesets.Mania;
|
||||||
|
using osu.Game.Users;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Game.Rulesets.Taiko;
|
||||||
|
using osu.Game.Graphics.UserInterface;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.Visual.Online
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class TestSceneUserRequest : OsuTestScene
|
||||||
|
{
|
||||||
|
[Resolved]
|
||||||
|
private IAPIProvider api { get; set; }
|
||||||
|
|
||||||
|
private readonly Bindable<User> user = new Bindable<User>();
|
||||||
|
private GetUserRequest request;
|
||||||
|
private readonly DimmedLoadingLayer loading;
|
||||||
|
|
||||||
|
public TestSceneUserRequest()
|
||||||
|
{
|
||||||
|
Add(new Container
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new UserTestContainer
|
||||||
|
{
|
||||||
|
User = { BindTarget = user }
|
||||||
|
},
|
||||||
|
loading = new DimmedLoadingLayer
|
||||||
|
{
|
||||||
|
Alpha = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
|
AddStep(@"local user", () => getUser());
|
||||||
|
AddStep(@"local user with taiko ruleset", () => getUser(ruleset: new TaikoRuleset().RulesetInfo));
|
||||||
|
AddStep(@"cookiezi", () => getUser(124493));
|
||||||
|
AddStep(@"cookiezi with mania ruleset", () => getUser(124493, new ManiaRuleset().RulesetInfo));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void getUser(long? userId = null, RulesetInfo ruleset = null)
|
||||||
|
{
|
||||||
|
loading.Show();
|
||||||
|
|
||||||
|
request?.Cancel();
|
||||||
|
request = new GetUserRequest(userId, ruleset);
|
||||||
|
request.Success += user =>
|
||||||
|
{
|
||||||
|
this.user.Value = user;
|
||||||
|
loading.Hide();
|
||||||
|
};
|
||||||
|
api.Queue(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
private class UserTestContainer : FillFlowContainer
|
||||||
|
{
|
||||||
|
public readonly Bindable<User> User = new Bindable<User>();
|
||||||
|
|
||||||
|
public UserTestContainer()
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Both;
|
||||||
|
Direction = FillDirection.Vertical;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
User.BindValueChanged(onUserUpdate, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onUserUpdate(ValueChangedEvent<User> user)
|
||||||
|
{
|
||||||
|
Clear();
|
||||||
|
|
||||||
|
AddRange(new Drawable[]
|
||||||
|
{
|
||||||
|
new SpriteText
|
||||||
|
{
|
||||||
|
Text = $@"Username: {user.NewValue?.Username}"
|
||||||
|
},
|
||||||
|
new SpriteText
|
||||||
|
{
|
||||||
|
Text = $@"RankedScore: {user.NewValue?.Statistics.RankedScore}"
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Audio.Track;
|
using osu.Framework.Audio.Track;
|
||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
@ -22,30 +23,36 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class TestSceneBeatSyncedContainer : OsuTestScene
|
public class TestSceneBeatSyncedContainer : OsuTestScene
|
||||||
{
|
{
|
||||||
private readonly MusicController mc;
|
private readonly NowPlayingOverlay np;
|
||||||
|
|
||||||
|
[Cached]
|
||||||
|
private MusicController musicController = new MusicController();
|
||||||
|
|
||||||
public TestSceneBeatSyncedContainer()
|
public TestSceneBeatSyncedContainer()
|
||||||
{
|
{
|
||||||
Clock = new FramedClock();
|
Clock = new FramedClock();
|
||||||
Clock.ProcessFrame();
|
Clock.ProcessFrame();
|
||||||
|
|
||||||
Add(new BeatContainer
|
AddRange(new Drawable[]
|
||||||
{
|
{
|
||||||
Anchor = Anchor.BottomCentre,
|
musicController,
|
||||||
Origin = Anchor.BottomCentre,
|
new BeatContainer
|
||||||
});
|
{
|
||||||
|
Anchor = Anchor.BottomCentre,
|
||||||
Add(mc = new MusicController
|
Origin = Anchor.BottomCentre,
|
||||||
{
|
},
|
||||||
Origin = Anchor.TopRight,
|
np = new NowPlayingOverlay
|
||||||
Anchor = Anchor.TopRight,
|
{
|
||||||
|
Origin = Anchor.TopRight,
|
||||||
|
Anchor = Anchor.TopRight,
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
mc.ToggleVisibility();
|
np.ToggleVisibility();
|
||||||
}
|
}
|
||||||
|
|
||||||
private class BeatContainer : BeatSyncedContainer
|
private class BeatContainer : BeatSyncedContainer
|
||||||
|
@ -82,14 +82,13 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
|
|
||||||
var easierMods = instance.GetModsFor(ModType.DifficultyReduction);
|
var easierMods = instance.GetModsFor(ModType.DifficultyReduction);
|
||||||
var harderMods = instance.GetModsFor(ModType.DifficultyIncrease);
|
var harderMods = instance.GetModsFor(ModType.DifficultyIncrease);
|
||||||
var assistMods = instance.GetModsFor(ModType.Automation);
|
|
||||||
|
|
||||||
var noFailMod = easierMods.FirstOrDefault(m => m is OsuModNoFail);
|
var noFailMod = easierMods.FirstOrDefault(m => m is OsuModNoFail);
|
||||||
var hiddenMod = harderMods.FirstOrDefault(m => m is OsuModHidden);
|
var hiddenMod = harderMods.FirstOrDefault(m => m is OsuModHidden);
|
||||||
|
|
||||||
var doubleTimeMod = harderMods.OfType<MultiMod>().FirstOrDefault(m => m.Mods.Any(a => a is OsuModDoubleTime));
|
var doubleTimeMod = harderMods.OfType<MultiMod>().FirstOrDefault(m => m.Mods.Any(a => a is OsuModDoubleTime));
|
||||||
|
|
||||||
var autoPilotMod = assistMods.FirstOrDefault(m => m is OsuModAutopilot);
|
var spunOutMod = easierMods.FirstOrDefault(m => m is OsuModSpunOut);
|
||||||
|
|
||||||
var easy = easierMods.FirstOrDefault(m => m is OsuModEasy);
|
var easy = easierMods.FirstOrDefault(m => m is OsuModEasy);
|
||||||
var hardRock = harderMods.FirstOrDefault(m => m is OsuModHardRock);
|
var hardRock = harderMods.FirstOrDefault(m => m is OsuModHardRock);
|
||||||
@ -101,7 +100,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
testMultiplierTextColour(noFailMod, modSelect.LowMultiplierColour);
|
testMultiplierTextColour(noFailMod, modSelect.LowMultiplierColour);
|
||||||
testMultiplierTextColour(hiddenMod, modSelect.HighMultiplierColour);
|
testMultiplierTextColour(hiddenMod, modSelect.HighMultiplierColour);
|
||||||
|
|
||||||
testUnimplementedMod(autoPilotMod);
|
testUnimplementedMod(spunOutMod);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Timing;
|
using osu.Framework.Timing;
|
||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
@ -9,22 +10,27 @@ using osu.Game.Overlays;
|
|||||||
namespace osu.Game.Tests.Visual.UserInterface
|
namespace osu.Game.Tests.Visual.UserInterface
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class TestSceneMusicController : OsuTestScene
|
public class TestSceneNowPlayingOverlay : OsuTestScene
|
||||||
{
|
{
|
||||||
public TestSceneMusicController()
|
[Cached]
|
||||||
|
private MusicController musicController = new MusicController();
|
||||||
|
|
||||||
|
public TestSceneNowPlayingOverlay()
|
||||||
{
|
{
|
||||||
Clock = new FramedClock();
|
Clock = new FramedClock();
|
||||||
|
|
||||||
var mc = new MusicController
|
var np = new NowPlayingOverlay
|
||||||
{
|
{
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Anchor = Anchor.Centre
|
Anchor = Anchor.Centre
|
||||||
};
|
};
|
||||||
Add(mc);
|
|
||||||
|
|
||||||
AddStep(@"show", () => mc.Show());
|
Add(musicController);
|
||||||
|
Add(np);
|
||||||
|
|
||||||
|
AddStep(@"show", () => np.Show());
|
||||||
AddToggleStep(@"toggle beatmap lock", state => Beatmap.Disabled = state);
|
AddToggleStep(@"toggle beatmap lock", state => Beatmap.Disabled = state);
|
||||||
AddStep(@"show", () => mc.Hide());
|
AddStep(@"show", () => np.Hide());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -7,6 +7,7 @@ using osu.Framework.Configuration;
|
|||||||
using osu.Framework.Configuration.Tracking;
|
using osu.Framework.Configuration.Tracking;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
|
using osu.Game.Overlays.OSD;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual.UserInterface
|
namespace osu.Game.Tests.Visual.UserInterface
|
||||||
{
|
{
|
||||||
@ -22,6 +23,12 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
osd.BeginTracking(this, config);
|
osd.BeginTracking(this, config);
|
||||||
Add(osd);
|
Add(osd);
|
||||||
|
|
||||||
|
AddStep("Display empty osd toast", () => osd.Display(new EmptyToast()));
|
||||||
|
AddAssert("Toast width is 240", () => osd.Child.Width == 240);
|
||||||
|
|
||||||
|
AddStep("Display toast with lengthy text", () => osd.Display(new LengthyToast()));
|
||||||
|
AddAssert("Toast width is greater than 240", () => osd.Child.Width > 240);
|
||||||
|
|
||||||
AddRepeatStep("Change toggle (no bind)", () => config.ToggleSetting(TestConfigSetting.ToggleSettingNoKeybind), 2);
|
AddRepeatStep("Change toggle (no bind)", () => config.ToggleSetting(TestConfigSetting.ToggleSettingNoKeybind), 2);
|
||||||
AddRepeatStep("Change toggle (with bind)", () => config.ToggleSetting(TestConfigSetting.ToggleSettingWithKeybind), 2);
|
AddRepeatStep("Change toggle (with bind)", () => config.ToggleSetting(TestConfigSetting.ToggleSettingWithKeybind), 2);
|
||||||
AddRepeatStep("Change enum (no bind)", () => config.IncrementEnumSetting(TestConfigSetting.EnumSettingNoKeybind), 3);
|
AddRepeatStep("Change enum (no bind)", () => config.IncrementEnumSetting(TestConfigSetting.EnumSettingNoKeybind), 3);
|
||||||
@ -86,6 +93,22 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
Setting4
|
Setting4
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class EmptyToast : Toast
|
||||||
|
{
|
||||||
|
public EmptyToast()
|
||||||
|
: base("", "", "")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class LengthyToast : Toast
|
||||||
|
{
|
||||||
|
public LengthyToast()
|
||||||
|
: base("Toast with a very very very long text", "A very very very very very very long text also", "A very very very very very long shortcut")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private class TestOnScreenDisplay : OnScreenDisplay
|
private class TestOnScreenDisplay : OnScreenDisplay
|
||||||
{
|
{
|
||||||
protected override void DisplayTemporarily(Drawable toDisplay) => toDisplay.FadeIn().ResizeHeightTo(110);
|
protected override void DisplayTemporarily(Drawable toDisplay) => toDisplay.FadeIn().ResizeHeightTo(110);
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
<PackageReference Include="DeepEqual" Version="2.0.0" />
|
<PackageReference Include="DeepEqual" Version="2.0.0" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" />
|
||||||
<PackageReference Include="NUnit" Version="3.12.0" />
|
<PackageReference Include="NUnit" Version="3.12.0" />
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="3.13.0" />
|
<PackageReference Include="NUnit3TestAdapter" Version="3.14.0" />
|
||||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<PropertyGroup Label="Project">
|
<PropertyGroup Label="Project">
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" />
|
||||||
<PackageReference Include="NUnit" Version="3.12.0" />
|
<PackageReference Include="NUnit" Version="3.12.0" />
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="3.13.0" />
|
<PackageReference Include="NUnit3TestAdapter" Version="3.14.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<PropertyGroup Label="Project">
|
<PropertyGroup Label="Project">
|
||||||
<OutputType>WinExe</OutputType>
|
<OutputType>WinExe</OutputType>
|
||||||
|
@ -88,7 +88,7 @@ namespace osu.Game.Tournament.Screens.Ladder
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private Cached layout = new Cached();
|
private readonly Cached layout = new Cached();
|
||||||
|
|
||||||
protected override void Update()
|
protected override void Update()
|
||||||
{
|
{
|
||||||
|
@ -60,5 +60,7 @@ namespace osu.Game.Beatmaps
|
|||||||
public class Beatmap : Beatmap<HitObject>
|
public class Beatmap : Beatmap<HitObject>
|
||||||
{
|
{
|
||||||
public new Beatmap Clone() => (Beatmap)base.Clone();
|
public new Beatmap Clone() => (Beatmap)base.Clone();
|
||||||
|
|
||||||
|
public override string ToString() => BeatmapInfo?.ToString() ?? base.ToString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,6 @@ using System;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.IO.File;
|
using osu.Framework.IO.File;
|
||||||
using osu.Framework.Logging;
|
|
||||||
using osu.Game.Beatmaps.Timing;
|
using osu.Game.Beatmaps.Timing;
|
||||||
using osu.Game.Rulesets.Objects.Legacy;
|
using osu.Game.Rulesets.Objects.Legacy;
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
@ -290,8 +289,9 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
string[] split = line.Split(',');
|
string[] split = line.Split(',');
|
||||||
|
|
||||||
EventType type;
|
EventType type;
|
||||||
|
|
||||||
if (!Enum.TryParse(split[0], out type))
|
if (!Enum.TryParse(split[0], out type))
|
||||||
throw new InvalidDataException($@"Unknown event type {split[0]}");
|
throw new InvalidDataException($@"Unknown event type: {split[0]}");
|
||||||
|
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
@ -319,90 +319,79 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
|
|
||||||
private void handleTimingPoint(string line)
|
private void handleTimingPoint(string line)
|
||||||
{
|
{
|
||||||
try
|
string[] split = line.Split(',');
|
||||||
|
|
||||||
|
double time = getOffsetTime(Parsing.ParseDouble(split[0].Trim()));
|
||||||
|
double beatLength = Parsing.ParseDouble(split[1].Trim());
|
||||||
|
double speedMultiplier = beatLength < 0 ? 100.0 / -beatLength : 1;
|
||||||
|
|
||||||
|
TimeSignatures timeSignature = TimeSignatures.SimpleQuadruple;
|
||||||
|
if (split.Length >= 3)
|
||||||
|
timeSignature = split[2][0] == '0' ? TimeSignatures.SimpleQuadruple : (TimeSignatures)Parsing.ParseInt(split[2]);
|
||||||
|
|
||||||
|
LegacySampleBank sampleSet = defaultSampleBank;
|
||||||
|
if (split.Length >= 4)
|
||||||
|
sampleSet = (LegacySampleBank)Parsing.ParseInt(split[3]);
|
||||||
|
|
||||||
|
int customSampleBank = 0;
|
||||||
|
if (split.Length >= 5)
|
||||||
|
customSampleBank = Parsing.ParseInt(split[4]);
|
||||||
|
|
||||||
|
int sampleVolume = defaultSampleVolume;
|
||||||
|
if (split.Length >= 6)
|
||||||
|
sampleVolume = Parsing.ParseInt(split[5]);
|
||||||
|
|
||||||
|
bool timingChange = true;
|
||||||
|
if (split.Length >= 7)
|
||||||
|
timingChange = split[6][0] == '1';
|
||||||
|
|
||||||
|
bool kiaiMode = false;
|
||||||
|
bool omitFirstBarSignature = false;
|
||||||
|
|
||||||
|
if (split.Length >= 8)
|
||||||
{
|
{
|
||||||
string[] split = line.Split(',');
|
EffectFlags effectFlags = (EffectFlags)Parsing.ParseInt(split[7]);
|
||||||
|
kiaiMode = effectFlags.HasFlag(EffectFlags.Kiai);
|
||||||
double time = getOffsetTime(Parsing.ParseDouble(split[0].Trim()));
|
omitFirstBarSignature = effectFlags.HasFlag(EffectFlags.OmitFirstBarLine);
|
||||||
double beatLength = Parsing.ParseDouble(split[1].Trim());
|
|
||||||
double speedMultiplier = beatLength < 0 ? 100.0 / -beatLength : 1;
|
|
||||||
|
|
||||||
TimeSignatures timeSignature = TimeSignatures.SimpleQuadruple;
|
|
||||||
if (split.Length >= 3)
|
|
||||||
timeSignature = split[2][0] == '0' ? TimeSignatures.SimpleQuadruple : (TimeSignatures)Parsing.ParseInt(split[2]);
|
|
||||||
|
|
||||||
LegacySampleBank sampleSet = defaultSampleBank;
|
|
||||||
if (split.Length >= 4)
|
|
||||||
sampleSet = (LegacySampleBank)Parsing.ParseInt(split[3]);
|
|
||||||
|
|
||||||
int customSampleBank = 0;
|
|
||||||
if (split.Length >= 5)
|
|
||||||
customSampleBank = Parsing.ParseInt(split[4]);
|
|
||||||
|
|
||||||
int sampleVolume = defaultSampleVolume;
|
|
||||||
if (split.Length >= 6)
|
|
||||||
sampleVolume = Parsing.ParseInt(split[5]);
|
|
||||||
|
|
||||||
bool timingChange = true;
|
|
||||||
if (split.Length >= 7)
|
|
||||||
timingChange = split[6][0] == '1';
|
|
||||||
|
|
||||||
bool kiaiMode = false;
|
|
||||||
bool omitFirstBarSignature = false;
|
|
||||||
|
|
||||||
if (split.Length >= 8)
|
|
||||||
{
|
|
||||||
EffectFlags effectFlags = (EffectFlags)Parsing.ParseInt(split[7]);
|
|
||||||
kiaiMode = effectFlags.HasFlag(EffectFlags.Kiai);
|
|
||||||
omitFirstBarSignature = effectFlags.HasFlag(EffectFlags.OmitFirstBarLine);
|
|
||||||
}
|
|
||||||
|
|
||||||
string stringSampleSet = sampleSet.ToString().ToLowerInvariant();
|
|
||||||
if (stringSampleSet == @"none")
|
|
||||||
stringSampleSet = @"normal";
|
|
||||||
|
|
||||||
if (timingChange)
|
|
||||||
{
|
|
||||||
var controlPoint = CreateTimingControlPoint();
|
|
||||||
controlPoint.Time = time;
|
|
||||||
controlPoint.BeatLength = beatLength;
|
|
||||||
controlPoint.TimeSignature = timeSignature;
|
|
||||||
|
|
||||||
handleTimingControlPoint(controlPoint);
|
|
||||||
}
|
|
||||||
|
|
||||||
handleDifficultyControlPoint(new DifficultyControlPoint
|
|
||||||
{
|
|
||||||
Time = time,
|
|
||||||
SpeedMultiplier = speedMultiplier,
|
|
||||||
AutoGenerated = timingChange
|
|
||||||
});
|
|
||||||
|
|
||||||
handleEffectControlPoint(new EffectControlPoint
|
|
||||||
{
|
|
||||||
Time = time,
|
|
||||||
KiaiMode = kiaiMode,
|
|
||||||
OmitFirstBarLine = omitFirstBarSignature,
|
|
||||||
AutoGenerated = timingChange
|
|
||||||
});
|
|
||||||
|
|
||||||
handleSampleControlPoint(new LegacySampleControlPoint
|
|
||||||
{
|
|
||||||
Time = time,
|
|
||||||
SampleBank = stringSampleSet,
|
|
||||||
SampleVolume = sampleVolume,
|
|
||||||
CustomSampleBank = customSampleBank,
|
|
||||||
AutoGenerated = timingChange
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
catch (FormatException)
|
|
||||||
|
string stringSampleSet = sampleSet.ToString().ToLowerInvariant();
|
||||||
|
if (stringSampleSet == @"none")
|
||||||
|
stringSampleSet = @"normal";
|
||||||
|
|
||||||
|
if (timingChange)
|
||||||
{
|
{
|
||||||
Logger.Log("A timing point could not be parsed correctly and will be ignored", LoggingTarget.Runtime, LogLevel.Important);
|
var controlPoint = CreateTimingControlPoint();
|
||||||
|
controlPoint.Time = time;
|
||||||
|
controlPoint.BeatLength = beatLength;
|
||||||
|
controlPoint.TimeSignature = timeSignature;
|
||||||
|
|
||||||
|
handleTimingControlPoint(controlPoint);
|
||||||
}
|
}
|
||||||
catch (OverflowException)
|
|
||||||
|
handleDifficultyControlPoint(new DifficultyControlPoint
|
||||||
{
|
{
|
||||||
Logger.Log("A timing point could not be parsed correctly and will be ignored", LoggingTarget.Runtime, LogLevel.Important);
|
Time = time,
|
||||||
}
|
SpeedMultiplier = speedMultiplier,
|
||||||
|
AutoGenerated = timingChange
|
||||||
|
});
|
||||||
|
|
||||||
|
handleEffectControlPoint(new EffectControlPoint
|
||||||
|
{
|
||||||
|
Time = time,
|
||||||
|
KiaiMode = kiaiMode,
|
||||||
|
OmitFirstBarLine = omitFirstBarSignature,
|
||||||
|
AutoGenerated = timingChange
|
||||||
|
});
|
||||||
|
|
||||||
|
handleSampleControlPoint(new LegacySampleControlPoint
|
||||||
|
{
|
||||||
|
Time = time,
|
||||||
|
SampleBank = stringSampleSet,
|
||||||
|
SampleVolume = sampleVolume,
|
||||||
|
CustomSampleBank = customSampleBank,
|
||||||
|
AutoGenerated = timingChange
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleTimingControlPoint(TimingControlPoint newPoint)
|
private void handleTimingControlPoint(TimingControlPoint newPoint)
|
||||||
|
@ -36,7 +36,7 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
{
|
{
|
||||||
if (!Enum.TryParse(line.Substring(1, line.Length - 2), out section))
|
if (!Enum.TryParse(line.Substring(1, line.Length - 2), out section))
|
||||||
{
|
{
|
||||||
Logger.Log($"Unknown section \"{line}\" in {output}");
|
Logger.Log($"Unknown section \"{line}\" in \"{output}\"");
|
||||||
section = Section.None;
|
section = Section.None;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,7 +49,7 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Logger.Error(e, $"Failed to process line \"{line}\" into {output}");
|
Logger.Log($"Failed to process line \"{line}\" into \"{output}\": {e.Message}", LoggingTarget.Runtime, LogLevel.Important);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -82,8 +82,9 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
storyboardSprite = null;
|
storyboardSprite = null;
|
||||||
|
|
||||||
EventType type;
|
EventType type;
|
||||||
|
|
||||||
if (!Enum.TryParse(split[0], out type))
|
if (!Enum.TryParse(split[0], out type))
|
||||||
throw new InvalidDataException($@"Unknown event type {split[0]}");
|
throw new InvalidDataException($@"Unknown event type: {split[0]}");
|
||||||
|
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
|
@ -9,7 +9,7 @@ namespace osu.Game.Beatmaps.Legacy
|
|||||||
public enum LegacyMods
|
public enum LegacyMods
|
||||||
{
|
{
|
||||||
None = 0,
|
None = 0,
|
||||||
NoFail = 1 << 0,
|
NoFail = 1,
|
||||||
Easy = 1 << 1,
|
Easy = 1 << 1,
|
||||||
TouchDevice = 1 << 2,
|
TouchDevice = 1 << 2,
|
||||||
Hidden = 1 << 3,
|
Hidden = 1 << 3,
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using osu.Game.Screens.Play;
|
||||||
|
|
||||||
namespace osu.Game.Beatmaps.Timing
|
namespace osu.Game.Beatmaps.Timing
|
||||||
{
|
{
|
||||||
public class BreakPeriod
|
public class BreakPeriod
|
||||||
@ -35,6 +37,6 @@ namespace osu.Game.Beatmaps.Timing
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="time">The time to check in milliseconds.</param>
|
/// <param name="time">The time to check in milliseconds.</param>
|
||||||
/// <returns>Whether the time falls within this <see cref="BreakPeriod"/>.</returns>
|
/// <returns>Whether the time falls within this <see cref="BreakPeriod"/>.</returns>
|
||||||
public bool Contains(double time) => time >= StartTime && time <= EndTime;
|
public bool Contains(double time) => time >= StartTime && time <= EndTime - BreakOverlay.BREAK_FADE_DURATION;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -89,6 +89,14 @@ namespace osu.Game.Beatmaps
|
|||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a <see cref="IBeatmapConverter"/> to convert a <see cref="IBeatmap"/> for a specified <see cref="Ruleset"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="beatmap">The <see cref="IBeatmap"/> to be converted.</param>
|
||||||
|
/// <param name="ruleset">The <see cref="Ruleset"/> for which <paramref name="beatmap"/> should be converted.</param>
|
||||||
|
/// <returns>The applicable <see cref="IBeatmapConverter"/>.</returns>
|
||||||
|
protected virtual IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap, Ruleset ruleset) => ruleset.CreateBeatmapConverter(beatmap);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Constructs a playable <see cref="IBeatmap"/> from <see cref="Beatmap"/> using the applicable converters for a specific <see cref="RulesetInfo"/>.
|
/// Constructs a playable <see cref="IBeatmap"/> from <see cref="Beatmap"/> using the applicable converters for a specific <see cref="RulesetInfo"/>.
|
||||||
/// <para>
|
/// <para>
|
||||||
@ -104,7 +112,7 @@ namespace osu.Game.Beatmaps
|
|||||||
{
|
{
|
||||||
var rulesetInstance = ruleset.CreateInstance();
|
var rulesetInstance = ruleset.CreateInstance();
|
||||||
|
|
||||||
IBeatmapConverter converter = rulesetInstance.CreateBeatmapConverter(Beatmap);
|
IBeatmapConverter converter = CreateBeatmapConverter(Beatmap, rulesetInstance);
|
||||||
|
|
||||||
// Check if the beatmap can be converted
|
// Check if the beatmap can be converted
|
||||||
if (!converter.CanConvert)
|
if (!converter.CanConvert)
|
||||||
|
11
osu.Game/Configuration/IntroSequence.cs
Normal file
11
osu.Game/Configuration/IntroSequence.cs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
namespace osu.Game.Configuration
|
||||||
|
{
|
||||||
|
public enum IntroSequence
|
||||||
|
{
|
||||||
|
Circles,
|
||||||
|
Triangles
|
||||||
|
}
|
||||||
|
}
|
@ -105,6 +105,8 @@ namespace osu.Game.Configuration
|
|||||||
Set(OsuSetting.ScalingPositionY, 0.5f, 0f, 1f);
|
Set(OsuSetting.ScalingPositionY, 0.5f, 0f, 1f);
|
||||||
|
|
||||||
Set(OsuSetting.UIScale, 1f, 0.8f, 1.6f, 0.01f);
|
Set(OsuSetting.UIScale, 1f, 0.8f, 1.6f, 0.01f);
|
||||||
|
|
||||||
|
Set(OsuSetting.IntroSequence, IntroSequence.Triangles);
|
||||||
}
|
}
|
||||||
|
|
||||||
public OsuConfigManager(Storage storage)
|
public OsuConfigManager(Storage storage)
|
||||||
@ -167,6 +169,7 @@ namespace osu.Game.Configuration
|
|||||||
ScalingPositionY,
|
ScalingPositionY,
|
||||||
ScalingSizeX,
|
ScalingSizeX,
|
||||||
ScalingSizeY,
|
ScalingSizeY,
|
||||||
UIScale
|
UIScale,
|
||||||
|
IntroSequence
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,10 +31,21 @@ namespace osu.Game.Database
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="TModel">The model type.</typeparam>
|
/// <typeparam name="TModel">The model type.</typeparam>
|
||||||
/// <typeparam name="TFileModel">The associated file join type.</typeparam>
|
/// <typeparam name="TFileModel">The associated file join type.</typeparam>
|
||||||
public abstract class ArchiveModelManager<TModel, TFileModel> : ArchiveModelManager, ICanAcceptFiles, IModelManager<TModel>
|
public abstract class ArchiveModelManager<TModel, TFileModel> : ICanAcceptFiles, IModelManager<TModel>
|
||||||
where TModel : class, IHasFiles<TFileModel>, IHasPrimaryKey, ISoftDelete
|
where TModel : class, IHasFiles<TFileModel>, IHasPrimaryKey, ISoftDelete
|
||||||
where TFileModel : INamedFileInfo, new()
|
where TFileModel : INamedFileInfo, new()
|
||||||
{
|
{
|
||||||
|
private const int import_queue_request_concurrency = 1;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A singleton scheduler shared by all <see cref="ArchiveModelManager{TModel,TFileModel}"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This scheduler generally performs IO and CPU intensive work so concurrency is limited harshly.
|
||||||
|
/// It is mainly being used as a queue mechanism for large imports.
|
||||||
|
/// </remarks>
|
||||||
|
private static readonly ThreadedTaskScheduler import_scheduler = new ThreadedTaskScheduler(import_queue_request_concurrency, nameof(ArchiveModelManager<TModel, TFileModel>));
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Set an endpoint for notifications to be posted to.
|
/// Set an endpoint for notifications to be posted to.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -336,7 +347,7 @@ namespace osu.Game.Database
|
|||||||
|
|
||||||
flushEvents(true);
|
flushEvents(true);
|
||||||
return item;
|
return item;
|
||||||
}, cancellationToken, TaskCreationOptions.HideScheduler, IMPORT_SCHEDULER).Unwrap();
|
}, cancellationToken, TaskCreationOptions.HideScheduler, import_scheduler).Unwrap();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Perform an update of the specified item.
|
/// Perform an update of the specified item.
|
||||||
@ -646,18 +657,4 @@ namespace osu.Game.Database
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract class ArchiveModelManager
|
|
||||||
{
|
|
||||||
private const int import_queue_request_concurrency = 1;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A singleton scheduler shared by all <see cref="ArchiveModelManager{TModel,TFileModel}"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// This scheduler generally performs IO and CPU intensive work so concurrency is limited harshly.
|
|
||||||
/// It is mainly being used as a queue mechanism for large imports.
|
|
||||||
/// </remarks>
|
|
||||||
protected static readonly ThreadedTaskScheduler IMPORT_SCHEDULER = new ThreadedTaskScheduler(import_queue_request_concurrency, nameof(ArchiveModelManager));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -191,7 +191,7 @@ namespace osu.Game.Graphics.Backgrounds
|
|||||||
private readonly List<TriangleParticle> parts = new List<TriangleParticle>();
|
private readonly List<TriangleParticle> parts = new List<TriangleParticle>();
|
||||||
private Vector2 size;
|
private Vector2 size;
|
||||||
|
|
||||||
private TriangleBatch<TexturedVertex2D> vertexBatch;
|
private QuadBatch<TexturedVertex2D> vertexBatch;
|
||||||
|
|
||||||
public TrianglesDrawNode(Triangles source)
|
public TrianglesDrawNode(Triangles source)
|
||||||
: base(source)
|
: base(source)
|
||||||
@ -217,7 +217,7 @@ namespace osu.Game.Graphics.Backgrounds
|
|||||||
if (Source.AimCount > 0 && (vertexBatch == null || vertexBatch.Size != Source.AimCount))
|
if (Source.AimCount > 0 && (vertexBatch == null || vertexBatch.Size != Source.AimCount))
|
||||||
{
|
{
|
||||||
vertexBatch?.Dispose();
|
vertexBatch?.Dispose();
|
||||||
vertexBatch = new TriangleBatch<TexturedVertex2D>(Source.AimCount, 1);
|
vertexBatch = new QuadBatch<TexturedVertex2D>(Source.AimCount, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
shader.Bind();
|
shader.Bind();
|
||||||
|
@ -6,7 +6,6 @@ using osu.Framework.Bindables;
|
|||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
using osuTK.Graphics;
|
|
||||||
|
|
||||||
namespace osu.Game.Graphics.Containers
|
namespace osu.Game.Graphics.Containers
|
||||||
{
|
{
|
||||||
@ -36,6 +35,8 @@ namespace osu.Game.Graphics.Containers
|
|||||||
|
|
||||||
protected Bindable<bool> ShowStoryboard { get; private set; }
|
protected Bindable<bool> ShowStoryboard { get; private set; }
|
||||||
|
|
||||||
|
protected double DimLevel => EnableUserDim.Value ? UserDimLevel.Value : 0;
|
||||||
|
|
||||||
protected override Container<Drawable> Content => dimContent;
|
protected override Container<Drawable> Content => dimContent;
|
||||||
|
|
||||||
private Container dimContent { get; }
|
private Container dimContent { get; }
|
||||||
@ -78,8 +79,8 @@ namespace osu.Game.Graphics.Containers
|
|||||||
{
|
{
|
||||||
ContentDisplayed = ShowDimContent;
|
ContentDisplayed = ShowDimContent;
|
||||||
|
|
||||||
dimContent.FadeTo((ContentDisplayed) ? 1 : 0, BACKGROUND_FADE_DURATION, Easing.OutQuint);
|
dimContent.FadeTo(ContentDisplayed ? 1 : 0, BACKGROUND_FADE_DURATION, Easing.OutQuint);
|
||||||
dimContent.FadeColour(EnableUserDim.Value ? OsuColour.Gray(1 - (float)UserDimLevel.Value) : Color4.White, BACKGROUND_FADE_DURATION, Easing.OutQuint);
|
dimContent.FadeColour(OsuColour.Gray(1 - (float)DimLevel), BACKGROUND_FADE_DURATION, Easing.OutQuint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,8 +22,8 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
|
|
||||||
Child = button = new TwoLayerButton
|
Child = button = new TwoLayerButton
|
||||||
{
|
{
|
||||||
Anchor = Anchor.CentreLeft,
|
Anchor = Anchor.TopLeft,
|
||||||
Origin = Anchor.CentreLeft,
|
Origin = Anchor.TopLeft,
|
||||||
Text = @"back",
|
Text = @"back",
|
||||||
Icon = OsuIcon.LeftCircle,
|
Icon = OsuIcon.LeftCircle,
|
||||||
Action = () => Action?.Invoke()
|
Action = () => Action?.Invoke()
|
||||||
|
@ -110,7 +110,7 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
[Flags]
|
[Flags]
|
||||||
public enum BarDirection
|
public enum BarDirection
|
||||||
{
|
{
|
||||||
LeftToRight = 1 << 0,
|
LeftToRight = 1,
|
||||||
RightToLeft = 1 << 1,
|
RightToLeft = 1 << 1,
|
||||||
TopToBottom = 1 << 2,
|
TopToBottom = 1 << 2,
|
||||||
BottomToTop = 1 << 3,
|
BottomToTop = 1 << 3,
|
||||||
|
@ -93,7 +93,7 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
return base.Invalidate(invalidation, source, shallPropagate);
|
return base.Invalidate(invalidation, source, shallPropagate);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Cached pathCached = new Cached();
|
private readonly Cached pathCached = new Cached();
|
||||||
|
|
||||||
protected override void Update()
|
protected override void Update()
|
||||||
{
|
{
|
||||||
|
@ -31,6 +31,11 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
protected virtual float StripWidth() => TabContainer.Children.Sum(c => c.IsPresent ? c.DrawWidth + TabContainer.Spacing.X : 0) - TabContainer.Spacing.X;
|
protected virtual float StripWidth() => TabContainer.Children.Sum(c => c.IsPresent ? c.DrawWidth + TabContainer.Spacing.X : 0) - TabContainer.Spacing.X;
|
||||||
protected virtual float StripHeight() => 1;
|
protected virtual float StripHeight() => 1;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether entries should be automatically populated if <see cref="T"/> is an <see cref="Enum"/> type.
|
||||||
|
/// </summary>
|
||||||
|
protected virtual bool AddEnumEntriesAutomatically => true;
|
||||||
|
|
||||||
private static bool isEnumType => typeof(T).IsEnum;
|
private static bool isEnumType => typeof(T).IsEnum;
|
||||||
|
|
||||||
public OsuTabControl()
|
public OsuTabControl()
|
||||||
@ -45,7 +50,7 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
Colour = Color4.White.Opacity(0),
|
Colour = Color4.White.Opacity(0),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (isEnumType)
|
if (isEnumType && AddEnumEntriesAutomatically)
|
||||||
foreach (var val in (T[])Enum.GetValues(typeof(T)))
|
foreach (var val in (T[])Enum.GetValues(typeof(T)))
|
||||||
AddItem(val);
|
AddItem(val);
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,13 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
Height = 30;
|
Height = 30;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class PageTabItem : TabItem<T>
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuColour colours)
|
||||||
|
{
|
||||||
|
AccentColour = colours.Yellow;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PageTabItem : TabItem<T>, IHasAccentColour
|
||||||
{
|
{
|
||||||
private const float transition_duration = 100;
|
private const float transition_duration = 100;
|
||||||
|
|
||||||
@ -32,6 +38,18 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
|
|
||||||
protected readonly SpriteText Text;
|
protected readonly SpriteText Text;
|
||||||
|
|
||||||
|
private Color4 accentColour;
|
||||||
|
|
||||||
|
public Color4 AccentColour
|
||||||
|
{
|
||||||
|
get => accentColour;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
accentColour = value;
|
||||||
|
box.Colour = accentColour;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public PageTabItem(T value)
|
public PageTabItem(T value)
|
||||||
: base(value)
|
: base(value)
|
||||||
{
|
{
|
||||||
@ -63,12 +81,6 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
Active.BindValueChanged(active => Text.Font = Text.Font.With(Typeface.Exo, weight: active.NewValue ? FontWeight.Bold : FontWeight.Medium), true);
|
Active.BindValueChanged(active => Text.Font = Text.Font.With(Typeface.Exo, weight: active.NewValue ? FontWeight.Bold : FontWeight.Medium), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
|
||||||
private void load(OsuColour colours)
|
|
||||||
{
|
|
||||||
box.Colour = colours.Yellow;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override bool OnHover(HoverEvent e)
|
protected override bool OnHover(HoverEvent e)
|
||||||
{
|
{
|
||||||
if (!Active.Value)
|
if (!Active.Value)
|
||||||
|
@ -15,7 +15,7 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
{
|
{
|
||||||
public const float ICON_WIDTH = ICON_SIZE + icon_spacing;
|
public const float ICON_WIDTH = ICON_SIZE + icon_spacing;
|
||||||
|
|
||||||
protected const float ICON_SIZE = 25;
|
public const float ICON_SIZE = 25;
|
||||||
|
|
||||||
private SpriteIcon iconSprite;
|
private SpriteIcon iconSprite;
|
||||||
private readonly OsuSpriteText titleText, pageText;
|
private readonly OsuSpriteText titleText, pageText;
|
||||||
|
64
osu.Game/Graphics/UserInterface/ScreenTitleTextureIcon.cs
Normal file
64
osu.Game/Graphics/UserInterface/ScreenTitleTextureIcon.cs
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
// 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.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Framework.Graphics.Textures;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Graphics.UserInterface
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A custom icon class for use with <see cref="ScreenTitle.CreateIcon()"/> based off a texture resource.
|
||||||
|
/// </summary>
|
||||||
|
public class ScreenTitleTextureIcon : CompositeDrawable
|
||||||
|
{
|
||||||
|
private const float circle_allowance = 0.8f;
|
||||||
|
|
||||||
|
private readonly string textureName;
|
||||||
|
|
||||||
|
public ScreenTitleTextureIcon(string textureName)
|
||||||
|
{
|
||||||
|
this.textureName = textureName;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(TextureStore textures, OsuColour colours)
|
||||||
|
{
|
||||||
|
Size = new Vector2(ScreenTitle.ICON_SIZE / circle_allowance);
|
||||||
|
|
||||||
|
InternalChildren = new Drawable[]
|
||||||
|
{
|
||||||
|
new CircularContainer
|
||||||
|
{
|
||||||
|
Masking = true,
|
||||||
|
BorderColour = colours.Violet,
|
||||||
|
BorderThickness = 3,
|
||||||
|
MaskingSmoothness = 1,
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new Sprite
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Texture = textures.Get(textureName),
|
||||||
|
Size = new Vector2(circle_allowance),
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
},
|
||||||
|
new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Colour = colours.Violet,
|
||||||
|
Alpha = 0,
|
||||||
|
AlwaysPresent = true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -15,6 +15,7 @@ using System;
|
|||||||
using osu.Framework.Graphics.Effects;
|
using osu.Framework.Graphics.Effects;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
|
using osu.Game.Screens.Select;
|
||||||
|
|
||||||
namespace osu.Game.Graphics.UserInterface
|
namespace osu.Game.Graphics.UserInterface
|
||||||
{
|
{
|
||||||
@ -28,7 +29,9 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
private const int transform_time = 600;
|
private const int transform_time = 600;
|
||||||
private const int pulse_length = 250;
|
private const int pulse_length = 250;
|
||||||
|
|
||||||
private const float shear = 0.1f;
|
private const float shear_width = 5f;
|
||||||
|
|
||||||
|
private static readonly Vector2 shear = new Vector2(shear_width / Footer.HEIGHT, 0);
|
||||||
|
|
||||||
public static readonly Vector2 SIZE_EXTENDED = new Vector2(140, 50);
|
public static readonly Vector2 SIZE_EXTENDED = new Vector2(140, 50);
|
||||||
public static readonly Vector2 SIZE_RETRACTED = new Vector2(100, 50);
|
public static readonly Vector2 SIZE_RETRACTED = new Vector2(100, 50);
|
||||||
@ -56,7 +59,7 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
c1.Origin = c1.Anchor = value.HasFlag(Anchor.x2) ? Anchor.TopLeft : Anchor.TopRight;
|
c1.Origin = c1.Anchor = value.HasFlag(Anchor.x2) ? Anchor.TopLeft : Anchor.TopRight;
|
||||||
c2.Origin = c2.Anchor = value.HasFlag(Anchor.x2) ? Anchor.TopRight : Anchor.TopLeft;
|
c2.Origin = c2.Anchor = value.HasFlag(Anchor.x2) ? Anchor.TopRight : Anchor.TopLeft;
|
||||||
|
|
||||||
X = value.HasFlag(Anchor.x2) ? SIZE_RETRACTED.X * shear * 0.5f : 0;
|
X = value.HasFlag(Anchor.x2) ? SIZE_RETRACTED.X * shear.X * 0.5f : 0;
|
||||||
|
|
||||||
Remove(c1);
|
Remove(c1);
|
||||||
Remove(c2);
|
Remove(c2);
|
||||||
@ -70,6 +73,7 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
public TwoLayerButton()
|
public TwoLayerButton()
|
||||||
{
|
{
|
||||||
Size = SIZE_RETRACTED;
|
Size = SIZE_RETRACTED;
|
||||||
|
Shear = shear;
|
||||||
|
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
@ -82,7 +86,6 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
new Container
|
new Container
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Shear = new Vector2(shear, 0),
|
|
||||||
Masking = true,
|
Masking = true,
|
||||||
MaskingSmoothness = 2,
|
MaskingSmoothness = 2,
|
||||||
EdgeEffect = new EdgeEffectParameters
|
EdgeEffect = new EdgeEffectParameters
|
||||||
@ -105,6 +108,7 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
|
Shear = -shear,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -119,7 +123,6 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
new Container
|
new Container
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Shear = new Vector2(shear, 0),
|
|
||||||
Masking = true,
|
Masking = true,
|
||||||
MaskingSmoothness = 2,
|
MaskingSmoothness = 2,
|
||||||
EdgeEffect = new EdgeEffectParameters
|
EdgeEffect = new EdgeEffectParameters
|
||||||
@ -144,6 +147,7 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
{
|
{
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
|
Shear = -shear,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -188,7 +192,6 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
var flash = new Box
|
var flash = new Box
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Shear = new Vector2(shear, 0),
|
|
||||||
Colour = Color4.White.Opacity(0.5f),
|
Colour = Color4.White.Opacity(0.5f),
|
||||||
};
|
};
|
||||||
Add(flash);
|
Add(flash);
|
||||||
|
@ -20,7 +20,7 @@ namespace osu.Game.Input.Bindings
|
|||||||
handler = game;
|
handler = game;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override IEnumerable<KeyBinding> DefaultKeyBindings => GlobalKeyBindings.Concat(InGameKeyBindings);
|
public override IEnumerable<KeyBinding> DefaultKeyBindings => GlobalKeyBindings.Concat(InGameKeyBindings).Concat(AudioControlKeyBindings);
|
||||||
|
|
||||||
public IEnumerable<KeyBinding> GlobalKeyBindings => new[]
|
public IEnumerable<KeyBinding> GlobalKeyBindings => new[]
|
||||||
{
|
{
|
||||||
@ -32,11 +32,6 @@ namespace osu.Game.Input.Bindings
|
|||||||
new KeyBinding(new[] { InputKey.Control, InputKey.Alt, InputKey.R }, GlobalAction.ResetInputSettings),
|
new KeyBinding(new[] { InputKey.Control, InputKey.Alt, InputKey.R }, GlobalAction.ResetInputSettings),
|
||||||
new KeyBinding(new[] { InputKey.Control, InputKey.T }, GlobalAction.ToggleToolbar),
|
new KeyBinding(new[] { InputKey.Control, InputKey.T }, GlobalAction.ToggleToolbar),
|
||||||
new KeyBinding(new[] { InputKey.Control, InputKey.O }, GlobalAction.ToggleSettings),
|
new KeyBinding(new[] { InputKey.Control, InputKey.O }, GlobalAction.ToggleSettings),
|
||||||
new KeyBinding(InputKey.Up, GlobalAction.IncreaseVolume),
|
|
||||||
new KeyBinding(InputKey.MouseWheelUp, GlobalAction.IncreaseVolume),
|
|
||||||
new KeyBinding(InputKey.Down, GlobalAction.DecreaseVolume),
|
|
||||||
new KeyBinding(InputKey.MouseWheelDown, GlobalAction.DecreaseVolume),
|
|
||||||
new KeyBinding(InputKey.F4, GlobalAction.ToggleMute),
|
|
||||||
|
|
||||||
new KeyBinding(InputKey.Escape, GlobalAction.Back),
|
new KeyBinding(InputKey.Escape, GlobalAction.Back),
|
||||||
new KeyBinding(InputKey.ExtraMouseButton1, GlobalAction.Back),
|
new KeyBinding(InputKey.ExtraMouseButton1, GlobalAction.Back),
|
||||||
@ -55,6 +50,22 @@ namespace osu.Game.Input.Bindings
|
|||||||
new KeyBinding(new[] { InputKey.Control, InputKey.Minus }, GlobalAction.DecreaseScrollSpeed),
|
new KeyBinding(new[] { InputKey.Control, InputKey.Minus }, GlobalAction.DecreaseScrollSpeed),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
public IEnumerable<KeyBinding> AudioControlKeyBindings => new[]
|
||||||
|
{
|
||||||
|
new KeyBinding(InputKey.Up, GlobalAction.IncreaseVolume),
|
||||||
|
new KeyBinding(InputKey.MouseWheelUp, GlobalAction.IncreaseVolume),
|
||||||
|
new KeyBinding(InputKey.Down, GlobalAction.DecreaseVolume),
|
||||||
|
new KeyBinding(InputKey.MouseWheelDown, GlobalAction.DecreaseVolume),
|
||||||
|
new KeyBinding(InputKey.F4, GlobalAction.ToggleMute),
|
||||||
|
|
||||||
|
new KeyBinding(InputKey.TrackPrevious, GlobalAction.MusicPrev),
|
||||||
|
new KeyBinding(InputKey.F1, GlobalAction.MusicPrev),
|
||||||
|
new KeyBinding(InputKey.TrackNext, GlobalAction.MusicNext),
|
||||||
|
new KeyBinding(InputKey.F5, GlobalAction.MusicNext),
|
||||||
|
new KeyBinding(InputKey.PlayPause, GlobalAction.MusicPlay),
|
||||||
|
new KeyBinding(InputKey.F3, GlobalAction.MusicPlay)
|
||||||
|
};
|
||||||
|
|
||||||
protected override IEnumerable<Drawable> KeyBindingInputQueue =>
|
protected override IEnumerable<Drawable> KeyBindingInputQueue =>
|
||||||
handler == null ? base.KeyBindingInputQueue : base.KeyBindingInputQueue.Prepend(handler);
|
handler == null ? base.KeyBindingInputQueue : base.KeyBindingInputQueue.Prepend(handler);
|
||||||
}
|
}
|
||||||
@ -115,5 +126,15 @@ namespace osu.Game.Input.Bindings
|
|||||||
|
|
||||||
[Description("Quick exit (Hold)")]
|
[Description("Quick exit (Hold)")]
|
||||||
QuickExit,
|
QuickExit,
|
||||||
|
|
||||||
|
// Game-wide beatmap msi ccotolle keybindings
|
||||||
|
[Description("Next track")]
|
||||||
|
MusicNext,
|
||||||
|
|
||||||
|
[Description("Previous track")]
|
||||||
|
MusicPrev,
|
||||||
|
|
||||||
|
[Description("Play / pause")]
|
||||||
|
MusicPlay,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,18 +2,21 @@
|
|||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using osu.Game.Users;
|
using osu.Game.Users;
|
||||||
|
using osu.Game.Rulesets;
|
||||||
|
|
||||||
namespace osu.Game.Online.API.Requests
|
namespace osu.Game.Online.API.Requests
|
||||||
{
|
{
|
||||||
public class GetUserRequest : APIRequest<User>
|
public class GetUserRequest : APIRequest<User>
|
||||||
{
|
{
|
||||||
private readonly long? userId;
|
private readonly long? userId;
|
||||||
|
private readonly RulesetInfo ruleset;
|
||||||
|
|
||||||
public GetUserRequest(long? userId = null)
|
public GetUserRequest(long? userId = null, RulesetInfo ruleset = null)
|
||||||
{
|
{
|
||||||
this.userId = userId;
|
this.userId = userId;
|
||||||
|
this.ruleset = ruleset;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override string Target => userId.HasValue ? $@"users/{userId}" : @"me";
|
protected override string Target => userId.HasValue ? $@"users/{userId}/{ruleset?.ShortName}" : $@"me/{ruleset?.ShortName}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,9 @@
|
|||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using osu.Framework.IO.Network;
|
||||||
using osu.Game.Online.API.Requests.Responses;
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
|
using osu.Game.Rulesets;
|
||||||
|
|
||||||
namespace osu.Game.Online.API.Requests
|
namespace osu.Game.Online.API.Requests
|
||||||
{
|
{
|
||||||
@ -10,12 +12,24 @@ namespace osu.Game.Online.API.Requests
|
|||||||
{
|
{
|
||||||
private readonly long userId;
|
private readonly long userId;
|
||||||
private readonly ScoreType type;
|
private readonly ScoreType type;
|
||||||
|
private readonly RulesetInfo ruleset;
|
||||||
|
|
||||||
public GetUserScoresRequest(long userId, ScoreType type, int page = 0, int itemsPerPage = 5)
|
public GetUserScoresRequest(long userId, ScoreType type, int page = 0, int itemsPerPage = 5, RulesetInfo ruleset = null)
|
||||||
: base(page, itemsPerPage)
|
: base(page, itemsPerPage)
|
||||||
{
|
{
|
||||||
this.userId = userId;
|
this.userId = userId;
|
||||||
this.type = type;
|
this.type = type;
|
||||||
|
this.ruleset = ruleset;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override WebRequest CreateWebRequest()
|
||||||
|
{
|
||||||
|
var req = base.CreateWebRequest();
|
||||||
|
|
||||||
|
if (ruleset != null)
|
||||||
|
req.AddParameter("mode", ruleset.ShortName);
|
||||||
|
|
||||||
|
return req;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override string Target => $@"users/{userId}/scores/{type.ToString().ToLowerInvariant()}";
|
protected override string Target => $@"users/{userId}/scores/{type.ToString().ToLowerInvariant()}";
|
||||||
|
@ -27,24 +27,25 @@ namespace osu.Game.Online.API.Requests
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ReSharper disable once ImpureMethodCallOnReadonlyValueField
|
// ReSharper disable once ImpureMethodCallOnReadonlyValueField
|
||||||
protected override string Target => $@"beatmapsets/search?q={query}&m={ruleset.ID ?? 0}&s={(int)searchCategory}&sort={sortCriteria.ToString().ToLowerInvariant()}_{directionString}";
|
protected override string Target => $@"beatmapsets/search?q={query}&m={ruleset.ID ?? 0}&s={searchCategory.ToString().ToLowerInvariant()}&sort={sortCriteria.ToString().ToLowerInvariant()}_{directionString}";
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum BeatmapSearchCategory
|
public enum BeatmapSearchCategory
|
||||||
{
|
{
|
||||||
Any = 7,
|
Any,
|
||||||
|
|
||||||
[Description("Ranked & Approved")]
|
[Description("Has Leaderboard")]
|
||||||
RankedApproved = 0,
|
Leaderboard,
|
||||||
Qualified = 3,
|
Ranked,
|
||||||
Loved = 8,
|
Qualified,
|
||||||
Favourites = 2,
|
Loved,
|
||||||
|
Favourites,
|
||||||
|
|
||||||
[Description("Pending & WIP")]
|
[Description("Pending & WIP")]
|
||||||
PendingWIP = 4,
|
Pending,
|
||||||
Graveyard = 5,
|
Graveyard,
|
||||||
|
|
||||||
[Description("My Maps")]
|
[Description("My Maps")]
|
||||||
MyMaps = 6,
|
Mine,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -213,8 +213,27 @@ namespace osu.Game.Online.Chat
|
|||||||
PostMessage(content, true);
|
PostMessage(content, true);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case "join":
|
||||||
|
if (string.IsNullOrWhiteSpace(content))
|
||||||
|
{
|
||||||
|
target.AddNewMessages(new ErrorMessage("Usage: /join [channel]"));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
var channel = availableChannels.Where(c => c.Name == content || c.Name == $"#{content}").FirstOrDefault();
|
||||||
|
|
||||||
|
if (channel == null)
|
||||||
|
{
|
||||||
|
target.AddNewMessages(new ErrorMessage($"Channel '{content}' not found."));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
JoinChannel(channel);
|
||||||
|
CurrentChannel.Value = channel;
|
||||||
|
break;
|
||||||
|
|
||||||
case "help":
|
case "help":
|
||||||
target.AddNewMessages(new InfoMessage("Supported commands: /help, /me [action]"));
|
target.AddNewMessages(new InfoMessage("Supported commands: /help, /me [action], /join [channel]"));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -8,7 +8,7 @@ namespace osu.Game.Online.Chat
|
|||||||
public ErrorMessage(string message)
|
public ErrorMessage(string message)
|
||||||
: base(message)
|
: base(message)
|
||||||
{
|
{
|
||||||
Sender.Colour = @"ff0000";
|
// todo: this should likely be styled differently in the future.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -48,22 +48,24 @@ namespace osu.Game.Online
|
|||||||
attachDownload(manager.GetExistingDownload(modelInfo.NewValue));
|
attachDownload(manager.GetExistingDownload(modelInfo.NewValue));
|
||||||
}, true);
|
}, true);
|
||||||
|
|
||||||
manager.DownloadBegan += download =>
|
manager.DownloadBegan += downloadBegan;
|
||||||
{
|
manager.DownloadFailed += downloadFailed;
|
||||||
if (download.Model.Equals(Model.Value))
|
|
||||||
attachDownload(download);
|
|
||||||
};
|
|
||||||
|
|
||||||
manager.DownloadFailed += download =>
|
|
||||||
{
|
|
||||||
if (download.Model.Equals(Model.Value))
|
|
||||||
attachDownload(null);
|
|
||||||
};
|
|
||||||
|
|
||||||
manager.ItemAdded += itemAdded;
|
manager.ItemAdded += itemAdded;
|
||||||
manager.ItemRemoved += itemRemoved;
|
manager.ItemRemoved += itemRemoved;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void downloadBegan(ArchiveDownloadRequest<TModel> request)
|
||||||
|
{
|
||||||
|
if (request.Model.Equals(Model.Value))
|
||||||
|
attachDownload(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void downloadFailed(ArchiveDownloadRequest<TModel> request)
|
||||||
|
{
|
||||||
|
if (request.Model.Equals(Model.Value))
|
||||||
|
attachDownload(null);
|
||||||
|
}
|
||||||
|
|
||||||
private ArchiveDownloadRequest<TModel> attachedRequest;
|
private ArchiveDownloadRequest<TModel> attachedRequest;
|
||||||
|
|
||||||
private void attachDownload(ArchiveDownloadRequest<TModel> request)
|
private void attachDownload(ArchiveDownloadRequest<TModel> request)
|
||||||
@ -126,8 +128,10 @@ namespace osu.Game.Online
|
|||||||
|
|
||||||
if (manager != null)
|
if (manager != null)
|
||||||
{
|
{
|
||||||
manager.DownloadBegan -= attachDownload;
|
manager.DownloadBegan -= downloadBegan;
|
||||||
|
manager.DownloadFailed -= downloadFailed;
|
||||||
manager.ItemAdded -= itemAdded;
|
manager.ItemAdded -= itemAdded;
|
||||||
|
manager.ItemRemoved -= itemRemoved;
|
||||||
}
|
}
|
||||||
|
|
||||||
State.UnbindAll();
|
State.UnbindAll();
|
||||||
|
@ -299,7 +299,7 @@ namespace osu.Game
|
|||||||
}, $"watch {databasedScoreInfo}", bypassScreenAllowChecks: true);
|
}, $"watch {databasedScoreInfo}", bypassScreenAllowChecks: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Beatmap jukebox progression
|
#region Beatmap progression
|
||||||
|
|
||||||
private void beatmapChanged(ValueChangedEvent<WorkingBeatmap> beatmap)
|
private void beatmapChanged(ValueChangedEvent<WorkingBeatmap> beatmap)
|
||||||
{
|
{
|
||||||
@ -469,6 +469,8 @@ namespace osu.Game
|
|||||||
loadComponentSingleFile(volume = new VolumeOverlay(), leftFloatingOverlayContent.Add);
|
loadComponentSingleFile(volume = new VolumeOverlay(), leftFloatingOverlayContent.Add);
|
||||||
loadComponentSingleFile(new OnScreenDisplay(), Add, true);
|
loadComponentSingleFile(new OnScreenDisplay(), Add, true);
|
||||||
|
|
||||||
|
loadComponentSingleFile(musicController = new MusicController(), Add, true);
|
||||||
|
|
||||||
loadComponentSingleFile(notifications = new NotificationOverlay
|
loadComponentSingleFile(notifications = new NotificationOverlay
|
||||||
{
|
{
|
||||||
GetToolbarHeight = () => ToolbarOffset,
|
GetToolbarHeight = () => ToolbarOffset,
|
||||||
@ -495,7 +497,7 @@ namespace osu.Game
|
|||||||
Origin = Anchor.TopRight,
|
Origin = Anchor.TopRight,
|
||||||
}, rightFloatingOverlayContent.Add, true);
|
}, rightFloatingOverlayContent.Add, true);
|
||||||
|
|
||||||
loadComponentSingleFile(musicController = new MusicController
|
loadComponentSingleFile(new NowPlayingOverlay
|
||||||
{
|
{
|
||||||
GetToolbarHeight = () => ToolbarOffset,
|
GetToolbarHeight = () => ToolbarOffset,
|
||||||
Anchor = Anchor.TopRight,
|
Anchor = Anchor.TopRight,
|
||||||
|
119
osu.Game/Overlays/BeatmapSet/LeaderboardScopeSelector.cs
Normal file
119
osu.Game/Overlays/BeatmapSet/LeaderboardScopeSelector.cs
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
// 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.UserInterface;
|
||||||
|
using osu.Game.Screens.Select.Leaderboards;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osuTK;
|
||||||
|
using osu.Game.Graphics.UserInterface;
|
||||||
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
using osu.Framework.Graphics.Colour;
|
||||||
|
using osu.Framework.Input.Events;
|
||||||
|
|
||||||
|
namespace osu.Game.Overlays.BeatmapSet
|
||||||
|
{
|
||||||
|
public class LeaderboardScopeSelector : PageTabControl<BeatmapLeaderboardScope>
|
||||||
|
{
|
||||||
|
protected override bool AddEnumEntriesAutomatically => false;
|
||||||
|
|
||||||
|
protected override Dropdown<BeatmapLeaderboardScope> CreateDropdown() => null;
|
||||||
|
|
||||||
|
protected override TabItem<BeatmapLeaderboardScope> CreateTabItem(BeatmapLeaderboardScope value) => new ScopeSelectorTabItem(value);
|
||||||
|
|
||||||
|
public LeaderboardScopeSelector()
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X;
|
||||||
|
|
||||||
|
AddItem(BeatmapLeaderboardScope.Global);
|
||||||
|
AddItem(BeatmapLeaderboardScope.Country);
|
||||||
|
AddItem(BeatmapLeaderboardScope.Friend);
|
||||||
|
|
||||||
|
AddInternal(new GradientLine
|
||||||
|
{
|
||||||
|
Anchor = Anchor.BottomCentre,
|
||||||
|
Origin = Anchor.BottomCentre,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuColour colours)
|
||||||
|
{
|
||||||
|
AccentColour = colours.Blue;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override TabFillFlowContainer CreateTabFlow() => new TabFillFlowContainer
|
||||||
|
{
|
||||||
|
Anchor = Anchor.BottomCentre,
|
||||||
|
Origin = Anchor.BottomCentre,
|
||||||
|
AutoSizeAxes = Axes.X,
|
||||||
|
RelativeSizeAxes = Axes.Y,
|
||||||
|
Direction = FillDirection.Horizontal,
|
||||||
|
Spacing = new Vector2(20, 0),
|
||||||
|
};
|
||||||
|
|
||||||
|
private class ScopeSelectorTabItem : PageTabItem
|
||||||
|
{
|
||||||
|
public ScopeSelectorTabItem(BeatmapLeaderboardScope value)
|
||||||
|
: base(value)
|
||||||
|
{
|
||||||
|
Text.Font = OsuFont.GetFont(size: 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool OnHover(HoverEvent e)
|
||||||
|
{
|
||||||
|
Text.FadeColour(AccentColour);
|
||||||
|
|
||||||
|
return base.OnHover(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnHoverLost(HoverLostEvent e)
|
||||||
|
{
|
||||||
|
base.OnHoverLost(e);
|
||||||
|
|
||||||
|
Text.FadeColour(Color4.White);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class GradientLine : GridContainer
|
||||||
|
{
|
||||||
|
public GradientLine()
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X;
|
||||||
|
Size = new Vector2(0.8f, 1.5f);
|
||||||
|
|
||||||
|
ColumnDimensions = new[]
|
||||||
|
{
|
||||||
|
new Dimension(),
|
||||||
|
new Dimension(mode: GridSizeMode.Relative, size: 0.4f),
|
||||||
|
new Dimension(),
|
||||||
|
};
|
||||||
|
|
||||||
|
Content = new[]
|
||||||
|
{
|
||||||
|
new Drawable[]
|
||||||
|
{
|
||||||
|
new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Colour = ColourInfo.GradientHorizontal(Color4.Transparent, Color4.Gray),
|
||||||
|
},
|
||||||
|
new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Colour = Color4.Gray,
|
||||||
|
},
|
||||||
|
new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Colour = ColourInfo.GradientHorizontal(Color4.Gray, Color4.Transparent),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -132,7 +132,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
|||||||
|
|
||||||
Scores = null;
|
Scores = null;
|
||||||
|
|
||||||
if (beatmap?.OnlineBeatmapID.HasValue != true)
|
if (beatmap?.OnlineBeatmapID.HasValue != true || beatmap.Status <= BeatmapSetOnlineStatus.Pending)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
loadingAnimation.Show();
|
loadingAnimation.Show();
|
||||||
|
@ -7,13 +7,11 @@ using osu.Framework.Allocation;
|
|||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Shapes;
|
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
using osu.Game.Online.API.Requests.Responses;
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
using osuTK;
|
|
||||||
|
|
||||||
namespace osu.Game.Overlays.Changelog
|
namespace osu.Game.Overlays.Changelog
|
||||||
{
|
{
|
||||||
@ -123,48 +121,7 @@ namespace osu.Game.Overlays.Changelog
|
|||||||
AccentColour = colours.Violet;
|
AccentColour = colours.Violet;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Drawable CreateIcon() => new ChangelogIcon();
|
protected override Drawable CreateIcon() => new ScreenTitleTextureIcon(@"Icons/changelog");
|
||||||
|
|
||||||
internal class ChangelogIcon : CompositeDrawable
|
|
||||||
{
|
|
||||||
private const float circle_allowance = 0.8f;
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
|
||||||
private void load(TextureStore textures, OsuColour colours)
|
|
||||||
{
|
|
||||||
Size = new Vector2(ICON_SIZE / circle_allowance);
|
|
||||||
|
|
||||||
InternalChildren = new Drawable[]
|
|
||||||
{
|
|
||||||
new CircularContainer
|
|
||||||
{
|
|
||||||
Masking = true,
|
|
||||||
BorderColour = colours.Violet,
|
|
||||||
BorderThickness = 3,
|
|
||||||
MaskingSmoothness = 1,
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
new Sprite
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Texture = textures.Get(@"Icons/changelog"),
|
|
||||||
Size = new Vector2(circle_allowance),
|
|
||||||
Anchor = Anchor.Centre,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
},
|
|
||||||
new Box
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Colour = colours.Violet,
|
|
||||||
Alpha = 0,
|
|
||||||
AlwaysPresent = true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,27 +30,24 @@ namespace osu.Game.Overlays.Chat
|
|||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
{
|
{
|
||||||
Children = new Drawable[]
|
Child = new OsuContextMenuContainer
|
||||||
{
|
{
|
||||||
scroll = new OsuScrollContainer
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Masking = true,
|
||||||
|
Child = scroll = new OsuScrollContainer
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
// Some chat lines have effects that slightly protrude to the bottom,
|
// Some chat lines have effects that slightly protrude to the bottom,
|
||||||
// which we do not want to mask away, hence the padding.
|
// which we do not want to mask away, hence the padding.
|
||||||
Padding = new MarginPadding { Bottom = 5 },
|
Padding = new MarginPadding { Bottom = 5 },
|
||||||
Child = new OsuContextMenuContainer
|
Child = ChatLineFlow = new ChatLineContainer
|
||||||
{
|
{
|
||||||
|
Padding = new MarginPadding { Left = 20, Right = 20 },
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
AutoSizeAxes = Axes.Y,
|
AutoSizeAxes = Axes.Y,
|
||||||
Child = ChatLineFlow = new ChatLineContainer
|
Direction = FillDirection.Vertical,
|
||||||
{
|
}
|
||||||
Padding = new MarginPadding { Left = 20, Right = 20 },
|
},
|
||||||
RelativeSizeAxes = Axes.X,
|
|
||||||
AutoSizeAxes = Axes.Y,
|
|
||||||
Direction = FillDirection.Vertical,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
newMessagesArrived(Channel.Messages);
|
newMessagesArrived(Channel.Messages);
|
||||||
|
@ -256,6 +256,9 @@ namespace osu.Game.Overlays
|
|||||||
loadedChannels.Add(loaded);
|
loadedChannels.Add(loaded);
|
||||||
LoadComponentAsync(loaded, l =>
|
LoadComponentAsync(loaded, l =>
|
||||||
{
|
{
|
||||||
|
if (currentChannel.Value != e.NewValue)
|
||||||
|
return;
|
||||||
|
|
||||||
loading.Hide();
|
loading.Hide();
|
||||||
|
|
||||||
currentChannelContainer.Clear(false);
|
currentChannelContainer.Clear(false);
|
||||||
@ -381,7 +384,18 @@ namespace osu.Game.Overlays
|
|||||||
foreach (Channel channel in channels)
|
foreach (Channel channel in channels)
|
||||||
{
|
{
|
||||||
ChannelTabControl.RemoveChannel(channel);
|
ChannelTabControl.RemoveChannel(channel);
|
||||||
loadedChannels.Remove(loadedChannels.Find(c => c.Channel == channel));
|
|
||||||
|
var loaded = loadedChannels.Find(c => c.Channel == channel);
|
||||||
|
|
||||||
|
if (loaded != null)
|
||||||
|
{
|
||||||
|
loadedChannels.Remove(loaded);
|
||||||
|
|
||||||
|
// Because the container is only cleared in the async load callback of a new channel, it is forcefully cleared
|
||||||
|
// to ensure that the previous channel doesn't get updated after it's disposed
|
||||||
|
currentChannelContainer.Remove(loaded);
|
||||||
|
loaded.Dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,6 +18,7 @@ namespace osu.Game.Overlays.Direct
|
|||||||
|
|
||||||
protected override Color4 BackgroundColour => OsuColour.FromHex(@"384552");
|
protected override Color4 BackgroundColour => OsuColour.FromHex(@"384552");
|
||||||
protected override DirectSortCriteria DefaultTab => DirectSortCriteria.Ranked;
|
protected override DirectSortCriteria DefaultTab => DirectSortCriteria.Ranked;
|
||||||
|
protected override BeatmapSearchCategory DefaultCategory => BeatmapSearchCategory.Leaderboard;
|
||||||
|
|
||||||
protected override Drawable CreateSupplementaryControls() => rulesetSelector = new DirectRulesetSelector();
|
protected override Drawable CreateSupplementaryControls() => rulesetSelector = new DirectRulesetSelector();
|
||||||
|
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user