1
0
mirror of https://github.com/ppy/osu.git synced 2026-06-04 09:03:54 +08:00

Compare commits

..

7 Commits

227 changed files with 2475 additions and 2934 deletions
+3
View File
@@ -0,0 +1,3 @@
[submodule "osu-resources"]
path = osu-resources
url = https://github.com/ppy/osu-resources
+1 -2
View File
@@ -70,8 +70,7 @@
"type": "shell",
"command": "dotnet",
"args": [
"restore",
"osu.sln"
"restore"
],
"problemMatcher": []
}
+7 -7
View File
@@ -31,14 +31,18 @@ If your platform is not listed above, there is still a chance you can manually b
Clone the repository **including submodules**:
```shell
git clone https://github.com/ppy/osu
git clone --recurse-submodules https://github.com/ppy/osu
cd osu
```
> If you forgot the `--recurse-submodules` option, run this command inside the `osu` directory:
>
> `git submodule update --init --recursive`
To update the source code to the latest commit, run the following command inside the `osu` directory:
```shell
git pull
git pull --recurse-submodules
```
## Building
@@ -69,13 +73,9 @@ For example, you can run osu! with the following command:
LD_LIBRARY_PATH="$(pwd)/osu.Desktop/bin/Debug/netcoreapp2.2" dotnet run --project osu.Desktop
```
## Testing with resource/framework modifications
Sometimes it may be necessary to cross-test changes in [osu-resources](https://github.com/ppy/osu-resources) or [osu-framework](https://github.com/ppy/osu-framework). This can be achieved by running some commands as documented on the [osu-resources](https://github.com/ppy/osu-resources/wiki/Testing-local-resources-checkout-with-other-projects) and [osu-framework](https://github.com/ppy/osu-framework/wiki/Testing-local-framework-checkout-with-other-projects) wiki pages.
## Code analysis
Code analysis can be run with `powershell ./build.ps1` or `build.sh`. This is currently only supported under windows due to [resharper cli shortcomings](https://youtrack.jetbrains.com/issue/RSRP-410004). Alternatively, you can install resharper or use rider to get inline support in your IDE of choice.
Code analysis can be run with `powershell ./build.ps1` or `build.sh`. This is currently only supported under windows due to [resharper cli shortcomings](https://youtrack.jetbrains.com/issue/RSRP-410004). Alternative, you can install resharper or use rider to get inline support in your IDE of choice.
# Contributing
Submodule
+1
Submodule osu-resources added at 694cb03f19
+3 -3
View File
@@ -16,6 +16,7 @@ using osu.Desktop.Updater;
using osu.Framework;
using osu.Framework.Platform.Windows;
using osu.Framework.Screens;
using osu.Game.Screens;
using osu.Game.Screens.Menu;
namespace osu.Desktop
@@ -62,10 +63,9 @@ namespace osu.Desktop
}
}
protected override void ScreenChanged(IScreen lastScreen, IScreen newScreen)
protected override void ScreenChanged(OsuScreen current, Screen newScreen)
{
base.ScreenChanged(lastScreen, newScreen);
base.ScreenChanged(current, newScreen);
switch (newScreen)
{
case Intro _:
+1
View File
@@ -22,6 +22,7 @@
<ProjectReference Include="..\osu.Game.Rulesets.Catch\osu.Game.Rulesets.Catch.csproj" />
<ProjectReference Include="..\osu.Game.Rulesets.Mania\osu.Game.Rulesets.Mania.csproj" />
<ProjectReference Include="..\osu.Game.Rulesets.Taiko\osu.Game.Rulesets.Taiko.csproj" />
<ProjectReference Include="..\osu-resources\osu.Game.Resources\osu.Game.Resources.csproj" />
<PackageReference Include="Microsoft.Win32.Registry" Version="4.5.0" />
</ItemGroup>
<ItemGroup Label="Package References">
@@ -1,5 +1,5 @@
// 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.
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using Foundation;
using osu.Framework.iOS;
@@ -1,5 +1,5 @@
// 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.
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using UIKit;
+1 -1
View File
@@ -13,7 +13,7 @@
<key>LSRequiresIPhoneOS</key>
<true/>
<key>MinimumOSVersion</key>
<string>10.0</string>
<string>11.0</string>
<key>UIDeviceFamily</key>
<array>
<integer>1</integer>
@@ -26,7 +26,9 @@
</LinkDescription>
<Compile Include="Application.cs" />
<Compile Include="AppDelegate.cs" />
<Compile Include="..\osu.Game.Rulesets.Catch.Tests\**\*.cs" Exclude="**\obj\**">
</ItemGroup>
<ItemGroup>
<Compile Include="..\osu.Game.Rulesets.Catch.Tests\*.cs">
<Link>%(RecursiveDir)%(Filename)%(Extension)</Link>
</Compile>
</ItemGroup>
@@ -39,6 +41,32 @@
<Project>{58F6C80C-1253-4A0E-A465-B8C85EBEADF3}</Project>
<Name>osu.Game.Rulesets.Catch</Name>
</ProjectReference>
<ProjectReference Include="..\osu-resources\osu.Game.Resources\osu.Game.Resources.csproj">
<Project>{D9A367C9-4C1A-489F-9B05-A0CEA2B53B58}</Project>
<Name>osu.Game.Resources</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Xml" />
<Reference Include="System.Core" />
<Reference Include="Xamarin.iOS" />
<Reference Include="mscorlib" />
<Reference Include="System.IO.Compression" />
<Reference Include="System.Net.Http" />
</ItemGroup>
<ItemGroup Label="Package References">
<PackageReference Include="Humanizer" Version="2.5.16" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.1" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.1" />
<PackageReference Include="ppy.osu.Framework" Version="2019.122.0" />
<PackageReference Include="ppy.osu.Framework.iOS" Version="2019.122.0" />
<PackageReference Include="SharpCompress" Version="0.22.0" />
<PackageReference Include="NUnit" Version="3.11.0" />
<PackageReference Include="SharpRaven" Version="2.4.0" />
<PackageReference Include="System.ComponentModel.Annotations" Version="4.5.0" />
<PackageReference Include="ppy.osu.Framework.NativeLibs" Version="2019.110.0" ExcludeAssets="all" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\iOS\Xamarin.iOS.CSharp.targets" />
<Import Project="..\packages\NETStandard.Library.2.0.0\build\netstandard2.0\NETStandard.Library.targets" Condition="Exists('..\packages\NETStandard.Library.2.0.0\build\netstandard2.0\NETStandard.Library.targets')" />
@@ -21,7 +21,6 @@ namespace osu.Game.Rulesets.Catch.Tests
[TestCase("basic")]
[TestCase("spinner")]
[TestCase("spinner-and-circles")]
[TestCase("slider")]
public new void Test(string name)
{
base.Test(name);
@@ -65,7 +65,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
base.SkinChanged(skin, allowFallback);
if (HitObject is IHasComboInformation combo)
AccentColour = skin.GetValue<SkinConfiguration, Color4?>(s => s.ComboColours.Count > 0 ? s.ComboColours[combo.ComboIndex % s.ComboColours.Count] : (Color4?)null) ?? Color4.White;
AccentColour = skin.GetValue<SkinConfiguration, Color4>(s => s.ComboColours.Count > 0 ? s.ComboColours[combo.ComboIndex % s.ComboColours.Count] : Color4.White);
}
private const float preempt = 1000;
+27 -36
View File
@@ -55,13 +55,6 @@ namespace osu.Game.Rulesets.Catch.Objects
var minDistanceFromEnd = Velocity * 0.01;
var tickSamples = Samples.Select(s => new SampleInfo
{
Bank = s.Bank,
Name = @"slidertick",
Volume = s.Volume
}).ToList();
AddNested(new Fruit
{
Samples = Samples,
@@ -69,22 +62,15 @@ namespace osu.Game.Rulesets.Catch.Objects
X = X
});
double lastTickTime = StartTime;
double lastDropletTime = StartTime;
for (int span = 0; span < this.SpanCount(); span++)
{
var spanStartTime = StartTime + span * spanDuration;
var reversed = span % 2 == 1;
for (double d = tickDistance;; d += tickDistance)
for (double d = 0; d <= length; d += tickDistance)
{
bool isLastTick = false;
if (d + minDistanceFromEnd >= length)
{
d = length;
isLastTick = true;
}
var timeProgress = d / length;
var distanceProgress = reversed ? 1 - timeProgress : timeProgress;
@@ -93,42 +79,47 @@ namespace osu.Game.Rulesets.Catch.Objects
if (LegacyLastTickOffset != null)
{
// If we're the last tick, apply the legacy offset
if (span == this.SpanCount() - 1 && isLastTick)
if (span == this.SpanCount() - 1 && d + tickDistance > length)
time = Math.Max(StartTime + Duration / 2, time - LegacyLastTickOffset.Value);
}
int tinyTickCount = 1;
double tinyTickInterval = time - lastTickTime;
while (tinyTickInterval > 100 && tinyTickCount < 10000)
{
double tinyTickInterval = time - lastDropletTime;
while (tinyTickInterval > 100)
tinyTickInterval /= 2;
tinyTickCount *= 2;
}
for (int tinyTickIndex = 0; tinyTickIndex < tinyTickCount - 1; tinyTickIndex++)
for (double t = lastDropletTime + tinyTickInterval; t < time; t += tinyTickInterval)
{
var t = lastTickTime + (tinyTickIndex + 1) * tinyTickInterval;
double progress = reversed ? 1 - (t - spanStartTime) / spanDuration : (t - spanStartTime) / spanDuration;
AddNested(new TinyDroplet
{
StartTime = t,
X = X + Path.PositionAt(progress).X / CatchPlayfield.BASE_WIDTH,
Samples = tickSamples
Samples = new List<SampleInfo>(Samples.Select(s => new SampleInfo
{
Bank = s.Bank,
Name = @"slidertick",
Volume = s.Volume
}))
});
}
lastTickTime = time;
if (isLastTick)
break;
AddNested(new Droplet
if (d > minDistanceFromEnd && Math.Abs(d - length) > minDistanceFromEnd)
{
StartTime = time,
X = X + Path.PositionAt(distanceProgress).X / CatchPlayfield.BASE_WIDTH,
Samples = tickSamples
});
AddNested(new Droplet
{
StartTime = time,
X = X + Path.PositionAt(distanceProgress).X / CatchPlayfield.BASE_WIDTH,
Samples = new List<SampleInfo>(Samples.Select(s => new SampleInfo
{
Bank = s.Bank,
Name = @"slidertick",
Volume = s.Volume
}))
});
}
lastDropletTime = time;
}
AddNested(new Fruit
@@ -1 +0,0 @@
{"Mappings":[{"StartTime":19184.0,"Objects":[{"StartTime":19184.0,"Position":320.0},{"StartTime":19263.0,"Position":311.730255},{"StartTime":19343.0,"Position":324.6205},{"StartTime":19423.0,"Position":343.0907},{"StartTime":19503.0,"Position":372.2917},{"StartTime":19582.0,"Position":385.194733},{"StartTime":19662.0,"Position":379.0426},{"StartTime":19742.0,"Position":385.1066},{"StartTime":19822.0,"Position":391.624664},{"StartTime":19919.0,"Position":386.27832},{"StartTime":20016.0,"Position":380.117035},{"StartTime":20113.0,"Position":381.664154},{"StartTime":20247.0,"Position":370.872864}]}]}
@@ -1,18 +0,0 @@
osu file format v14
[General]
Mode: 2
[Difficulty]
HPDrainRate:3
CircleSize:2
OverallDifficulty:4
ApproachRate:4
SliderMultiplier:0.9
SliderTickRate:1
[TimingPoints]
35.4473684210527,638.298947368422,4,2,1,60,1,0
[HitObjects]
320,176,19184,2,8,P|384:168|368:232,1,150
@@ -43,6 +43,6 @@ namespace osu.Game.Rulesets.Catch.Scoring
Health.Value += Math.Max(result.Judgement.HealthIncreaseFor(result) - hpDrainRate, 0) * harshness;
}
public override HitWindows CreateHitWindows() => new CatchHitWindows();
protected override HitWindows CreateHitWindows() => new CatchHitWindows();
}
}
@@ -1,5 +1,5 @@
// 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.
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using Foundation;
using osu.Framework.iOS;
@@ -1,5 +1,5 @@
// 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.
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using UIKit;
+1 -1
View File
@@ -13,7 +13,7 @@
<key>LSRequiresIPhoneOS</key>
<true/>
<key>MinimumOSVersion</key>
<string>10.0</string>
<string>11.0</string>
<key>UIDeviceFamily</key>
<array>
<integer>1</integer>
@@ -26,7 +26,9 @@
</LinkDescription>
<Compile Include="Application.cs" />
<Compile Include="AppDelegate.cs" />
<Compile Include="..\osu.Game.Rulesets.Mania.Tests\**\*.cs" Exclude="**\obj\**">
</ItemGroup>
<ItemGroup>
<Compile Include="..\osu.Game.Rulesets.Mania.Tests\*.cs">
<Link>%(RecursiveDir)%(Filename)%(Extension)</Link>
</Compile>
</ItemGroup>
@@ -39,6 +41,32 @@
<Project>{48F4582B-7687-4621-9CBE-5C24197CB536}</Project>
<Name>osu.Game.Rulesets.Mania</Name>
</ProjectReference>
<ProjectReference Include="..\osu-resources\osu.Game.Resources\osu.Game.Resources.csproj">
<Project>{D9A367C9-4C1A-489F-9B05-A0CEA2B53B58}</Project>
<Name>osu.Game.Resources</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Xml" />
<Reference Include="System.Core" />
<Reference Include="Xamarin.iOS" />
<Reference Include="mscorlib" />
<Reference Include="System.IO.Compression" />
<Reference Include="System.Net.Http" />
</ItemGroup>
<ItemGroup Label="Package References">
<PackageReference Include="Humanizer" Version="2.5.16" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.1" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.1" />
<PackageReference Include="ppy.osu.Framework" Version="2019.122.0" />
<PackageReference Include="ppy.osu.Framework.iOS" Version="2019.122.0" />
<PackageReference Include="SharpCompress" Version="0.22.0" />
<PackageReference Include="NUnit" Version="3.11.0" />
<PackageReference Include="SharpRaven" Version="2.4.0" />
<PackageReference Include="System.ComponentModel.Annotations" Version="4.5.0" />
<PackageReference Include="ppy.osu.Framework.NativeLibs" Version="2019.110.0" ExcludeAssets="all" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\iOS\Xamarin.iOS.CSharp.targets" />
<Import Project="..\packages\NETStandard.Library.2.0.0\build\netstandard2.0\NETStandard.Library.targets" Condition="Exists('..\packages\NETStandard.Library.2.0.0\build\netstandard2.0\NETStandard.Library.targets')" />
@@ -51,7 +51,7 @@ namespace osu.Game.Rulesets.Mania.Difficulty
difficultyHitObjects.AddRange(beatmap.HitObjects.Select(h => new ManiaHitObjectDifficulty((ManiaHitObject)h, columnCount)).OrderBy(h => h.BaseHitObject.StartTime));
if (!calculateStrainValues(difficultyHitObjects, timeRate))
return new ManiaDifficultyAttributes(mods, 0);
return new DifficultyAttributes(mods, 0);
double starRating = calculateDifficulty(difficultyHitObjects, timeRate) * star_scaling_factor;
@@ -159,6 +159,6 @@ namespace osu.Game.Rulesets.Mania.Scoring
}
}
public override HitWindows CreateHitWindows() => new ManiaHitWindows();
protected override HitWindows CreateHitWindows() => new ManiaHitWindows();
}
}
@@ -1,5 +1,5 @@
// 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.
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using Foundation;
using osu.Framework.iOS;
@@ -1,5 +1,5 @@
// 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.
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using UIKit;
+1 -1
View File
@@ -13,7 +13,7 @@
<key>LSRequiresIPhoneOS</key>
<true/>
<key>MinimumOSVersion</key>
<string>10.0</string>
<string>11.0</string>
<key>UIDeviceFamily</key>
<array>
<integer>1</integer>
@@ -26,7 +26,9 @@
</LinkDescription>
<Compile Include="Application.cs" />
<Compile Include="AppDelegate.cs" />
<Compile Include="..\osu.Game.Rulesets.Osu.Tests\**\*.cs" Exclude="**\obj\**">
</ItemGroup>
<ItemGroup>
<Compile Include="..\osu.Game.Rulesets.Osu.Tests\*.cs">
<Link>%(RecursiveDir)%(Filename)%(Extension)</Link>
</Compile>
</ItemGroup>
@@ -39,6 +41,32 @@
<Project>{C92A607B-1FDD-4954-9F92-03FF547D9080}</Project>
<Name>osu.Game.Rulesets.Osu</Name>
</ProjectReference>
<ProjectReference Include="..\osu-resources\osu.Game.Resources\osu.Game.Resources.csproj">
<Project>{D9A367C9-4C1A-489F-9B05-A0CEA2B53B58}</Project>
<Name>osu.Game.Resources</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Xml" />
<Reference Include="System.Core" />
<Reference Include="Xamarin.iOS" />
<Reference Include="mscorlib" />
<Reference Include="System.IO.Compression" />
<Reference Include="System.Net.Http" />
</ItemGroup>
<ItemGroup Label="Package References">
<PackageReference Include="Humanizer" Version="2.5.16" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.1" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.1" />
<PackageReference Include="ppy.osu.Framework" Version="2019.122.0" />
<PackageReference Include="ppy.osu.Framework.iOS" Version="2019.122.0" />
<PackageReference Include="SharpCompress" Version="0.22.0" />
<PackageReference Include="NUnit" Version="3.11.0" />
<PackageReference Include="SharpRaven" Version="2.4.0" />
<PackageReference Include="System.ComponentModel.Annotations" Version="4.5.0" />
<PackageReference Include="ppy.osu.Framework.NativeLibs" Version="2019.110.0" ExcludeAssets="all" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\iOS\Xamarin.iOS.CSharp.targets" />
<Import Project="..\packages\NETStandard.Library.2.0.0\build\netstandard2.0\NETStandard.Library.targets" Condition="Exists('..\packages\NETStandard.Library.2.0.0\build\netstandard2.0\NETStandard.Library.targets')" />
@@ -1,36 +0,0 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using NUnit.Framework;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Osu.Objects;
using osuTK;
namespace osu.Game.Rulesets.Osu.Tests
{
[TestFixture]
public class TestCaseHitCircleLongCombo : Game.Tests.Visual.TestCasePlayer
{
public TestCaseHitCircleLongCombo()
: base(new OsuRuleset())
{
}
protected override IBeatmap CreateBeatmap(Ruleset ruleset)
{
var beatmap = new Beatmap
{
BeatmapInfo = new BeatmapInfo
{
BaseDifficulty = new BeatmapDifficulty { CircleSize = 6 },
Ruleset = ruleset.RulesetInfo
}
};
for (int i = 0; i < 512; i++)
beatmap.HitObjects.Add(new HitCircle { Position = new Vector2(256, 192), StartTime = i * 100 });
return beatmap;
}
}
}
@@ -88,12 +88,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
private double computeAimValue()
{
double rawAim = Attributes.AimStrain;
if (mods.Any(m => m is OsuModTouchDevice))
rawAim = Math.Pow(rawAim, 0.8);
double aimValue = Math.Pow(5.0f * Math.Max(1.0f, rawAim / 0.0675f) - 4.0f, 3.0f) / 100000.0f;
double aimValue = Math.Pow(5.0f * Math.Max(1.0f, Attributes.AimStrain / 0.0675f) - 4.0f, 3.0f) / 100000.0f;
// Longer maps are worth more
double lengthBonus = 0.95f + 0.4f * Math.Min(1.0f, totalHits / 2000.0f) +
@@ -38,13 +38,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing
// The first jump is formed by the first two hitobjects of the map.
// If the map has less than two OsuHitObjects, the enumerator will not return anything.
for (int i = 1; i < objects.Count; i++)
{
var lastLast = i > 1 ? objects[i - 2] : null;
var last = objects[i - 1];
var current = objects[i];
yield return new OsuDifficultyHitObject(lastLast, last, current, timeRate);
}
yield return new OsuDifficultyHitObject(objects[i], objects[i - 1], timeRate);
}
}
}
@@ -40,22 +40,14 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing
/// </summary>
public double StrainTime { get; private set; }
/// <summary>
/// Angle the player has to take to hit this <see cref="OsuDifficultyHitObject"/>.
/// Calculated as the angle between the circles (current-2, current-1, current).
/// </summary>
public double? Angle { get; private set; }
private readonly OsuHitObject lastLastObject;
private readonly OsuHitObject lastObject;
private readonly double timeRate;
/// <summary>
/// Initializes the object calculating extra data required for difficulty calculation.
/// </summary>
public OsuDifficultyHitObject(OsuHitObject lastLastObject, OsuHitObject lastObject, OsuHitObject currentObject, double timeRate)
public OsuDifficultyHitObject(OsuHitObject currentObject, OsuHitObject lastObject, double timeRate)
{
this.lastLastObject = lastLastObject;
this.lastObject = lastObject;
this.timeRate = timeRate;
@@ -76,30 +68,20 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing
scalingFactor *= 1 + smallCircleBonus;
}
if (lastObject is Slider lastSlider)
Vector2 lastCursorPosition = lastObject.StackedPosition;
var lastSlider = lastObject as Slider;
if (lastSlider != null)
{
computeSliderCursorPosition(lastSlider);
lastCursorPosition = lastSlider.LazyEndPosition ?? lastCursorPosition;
TravelDistance = lastSlider.LazyTravelDistance * scalingFactor;
}
Vector2 lastCursorPosition = getEndCursorPosition(lastObject);
// Don't need to jump to reach spinners
if (!(BaseObject is Spinner))
JumpDistance = (BaseObject.StackedPosition * scalingFactor - lastCursorPosition * scalingFactor).Length;
if (lastLastObject != null)
{
Vector2 lastLastCursorPosition = getEndCursorPosition(lastLastObject);
Vector2 v1 = lastLastCursorPosition - lastObject.StackedPosition;
Vector2 v2 = BaseObject.StackedPosition - lastCursorPosition;
float dot = Vector2.Dot(v1, v2);
float det = v1.X * v2.Y - v1.Y * v2.X;
Angle = Math.Abs(Math.Atan2(det, dot));
}
}
private void setTimingValues()
@@ -143,20 +125,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing
var scoringTimes = slider.NestedHitObjects.Skip(1).Select(t => t.StartTime);
foreach (var time in scoringTimes)
computeVertex(time);
}
private Vector2 getEndCursorPosition(OsuHitObject hitObject)
{
Vector2 pos = hitObject.StackedPosition;
var slider = hitObject as Slider;
if (slider != null)
{
computeSliderCursorPosition(slider);
pos = slider.LazyEndPosition ?? pos;
}
return pos;
computeVertex(slider.EndTime);
}
}
}
+1 -30
View File
@@ -11,39 +11,10 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills
/// </summary>
public class Aim : Skill
{
private const double angle_bonus_begin = Math.PI / 3;
private const double timing_threshold = 107;
protected override double SkillMultiplier => 26.25;
protected override double StrainDecayBase => 0.15;
protected override double StrainValueOf(OsuDifficultyHitObject current)
{
double result = 0;
const double scale = 90;
double applyDiminishingExp(double val) => Math.Pow(val, 0.99);
if (Previous.Count > 0)
{
if (current.Angle != null && current.Angle.Value > angle_bonus_begin)
{
var angleBonus = Math.Sqrt(
Math.Max(Previous[0].JumpDistance - scale, 0)
* Math.Pow(Math.Sin(current.Angle.Value - angle_bonus_begin), 2)
* Math.Max(current.JumpDistance - scale, 0));
result = 1.5 * applyDiminishingExp(Math.Max(0, angleBonus)) / Math.Max(timing_threshold, Previous[0].StrainTime);
}
}
double jumpDistanceExp = applyDiminishingExp(current.JumpDistance);
double travelDistanceExp = applyDiminishingExp(current.TravelDistance);
return Math.Max(
result + (jumpDistanceExp + travelDistanceExp + Math.Sqrt(travelDistanceExp * jumpDistanceExp)) / Math.Max(current.StrainTime, timing_threshold),
(Math.Sqrt(travelDistanceExp * jumpDistanceExp) + jumpDistanceExp + travelDistanceExp) / current.StrainTime
);
}
=> (Math.Pow(current.TravelDistance, 0.99) + Math.Pow(current.JumpDistance, 0.99)) / current.StrainTime;
}
}
@@ -15,9 +15,6 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills
/// </summary>
public abstract class Skill
{
protected const double SINGLE_SPACING_THRESHOLD = 125;
protected const double STREAM_SPACING_THRESHOLD = 110;
/// <summary>
/// Strain values are multiplied by this number for the given skill. Used to balance the value of different skills between each other.
/// </summary>
@@ -1,7 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System;
using osu.Game.Rulesets.Osu.Difficulty.Preprocessing;
namespace osu.Game.Rulesets.Osu.Difficulty.Skills
@@ -11,41 +10,30 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills
/// </summary>
public class Speed : Skill
{
private const double angle_bonus_begin = 5 * Math.PI / 6;
private const double pi_over_4 = Math.PI / 4;
private const double pi_over_2 = Math.PI / 2;
protected override double SkillMultiplier => 1400;
protected override double StrainDecayBase => 0.3;
private const double min_speed_bonus = 75; // ~200BPM
private const double max_speed_bonus = 45; // ~330BPM
private const double speed_balancing_factor = 40;
private const double single_spacing_threshold = 125;
private const double stream_spacing_threshold = 110;
private const double almost_diameter = 90;
protected override double StrainValueOf(OsuDifficultyHitObject current)
{
double distance = Math.Min(SINGLE_SPACING_THRESHOLD, current.TravelDistance + current.JumpDistance);
double deltaTime = Math.Max(max_speed_bonus, current.DeltaTime);
double distance = current.TravelDistance + current.JumpDistance;
double speedBonus = 1.0;
if (deltaTime < min_speed_bonus)
speedBonus = 1 + Math.Pow((min_speed_bonus - deltaTime) / speed_balancing_factor, 2);
double speedValue;
if (distance > single_spacing_threshold)
speedValue = 2.5;
else if (distance > stream_spacing_threshold)
speedValue = 1.6 + 0.9 * (distance - stream_spacing_threshold) / (single_spacing_threshold - stream_spacing_threshold);
else if (distance > almost_diameter)
speedValue = 1.2 + 0.4 * (distance - almost_diameter) / (stream_spacing_threshold - almost_diameter);
else if (distance > almost_diameter / 2)
speedValue = 0.95 + 0.25 * (distance - almost_diameter / 2) / (almost_diameter / 2);
else
speedValue = 0.95;
double angleBonus = 1.0;
if (current.Angle != null && current.Angle.Value < angle_bonus_begin)
{
angleBonus = 1 + Math.Pow(Math.Sin(1.5 * (angle_bonus_begin - current.Angle.Value)), 2) / 3.57;
if (current.Angle.Value < pi_over_2)
{
angleBonus = 1.28;
if (distance < 90 && current.Angle.Value < pi_over_4)
angleBonus += (1 - angleBonus) * Math.Min((90 - distance) / 10, 1);
else if (distance < 90)
angleBonus += (1 - angleBonus) * Math.Min((90 - distance) / 10, 1) * Math.Sin((pi_over_2 - current.Angle.Value) / pi_over_4);
}
}
return (1 + (speedBonus - 1) * 0.75) * angleBonus * (0.95 + speedBonus * Math.Pow(distance / SINGLE_SPACING_THRESHOLD, 3.5)) / current.StrainTime;
return speedValue / current.StrainTime;
}
}
}
@@ -5,7 +5,6 @@ using osu.Framework.Input.Events;
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components;
using osu.Game.Rulesets.Osu.Objects;
using osuTK;
namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles
{
@@ -23,8 +22,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles
{
base.LoadComplete();
// Fixes a 1-frame position discrepancy due to the first mouse move event happening in the next frame
HitObject.Position = Parent?.ToLocalSpace(GetContainingInputManager().CurrentState.Mouse.Position) ?? Vector2.Zero;
// Fixes a 1-frame position discrpancy due to the first mouse move event happening in the next frame
HitObject.Position = GetContainingInputManager().CurrentState.Mouse.Position;
}
protected override bool OnClick(ClickEvent e)
@@ -47,14 +47,6 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
setState(PlacementState.Initial);
}
protected override void LoadComplete()
{
base.LoadComplete();
// Fixes a 1-frame position discrepancy due to the first mouse move event happening in the next frame
HitObject.Position = Parent?.ToLocalSpace(GetContainingInputManager().CurrentState.Mouse.Position) ?? Vector2.Zero;
}
protected override bool OnMouseMove(MouseMoveEvent e)
{
switch (state)
@@ -1,16 +0,0 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Osu.Mods
{
public class OsuModTouchDevice : Mod
{
public override string Name => "Touch Device";
public override string Acronym => "TD";
public override double ScoreMultiplier => 1;
public override bool Ranked => true;
}
}
@@ -58,7 +58,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
base.SkinChanged(skin, allowFallback);
if (HitObject is IHasComboInformation combo)
AccentColour = skin.GetValue<SkinConfiguration, Color4?>(s => s.ComboColours.Count > 0 ? s.ComboColours[combo.ComboIndex % s.ComboColours.Count] : (Color4?)null) ?? Color4.White;
AccentColour = skin.GetValue<SkinConfiguration, Color4>(s => s.ComboColours.Count > 0 ? s.ComboColours[combo.ComboIndex % s.ComboColours.Count] : Color4.White);
}
protected virtual void UpdatePreemptState() => this.FadeIn(HitObject.TimeFadeIn);
@@ -156,9 +156,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
{
base.SkinChanged(skin, allowFallback);
Body.AccentColour = skin.GetValue<SkinConfiguration, Color4?>(s => s.CustomColours.ContainsKey("SliderTrackOverride") ? s.CustomColours["SliderTrackOverride"] : (Color4?)null) ?? Body.AccentColour;
Body.BorderColour = skin.GetValue<SkinConfiguration, Color4?>(s => s.CustomColours.ContainsKey("SliderBorder") ? s.CustomColours["SliderBorder"] : (Color4?)null) ?? Body.BorderColour;
Ball.AccentColour = skin.GetValue<SkinConfiguration, Color4?>(s => s.CustomColours.ContainsKey("SliderBall") ? s.CustomColours["SliderBall"] : (Color4?)null) ?? Ball.AccentColour;
Body.AccentColour = skin.GetValue<SkinConfiguration, Color4>(s => s.CustomColours.ContainsKey("SliderTrackOverride") ? s.CustomColours["SliderTrackOverride"] : Body.AccentColour);
Body.BorderColour = skin.GetValue<SkinConfiguration, Color4>(s => s.CustomColours.ContainsKey("SliderBorder") ? s.CustomColours["SliderBorder"] : Body.BorderColour);
Ball.AccentColour = skin.GetValue<SkinConfiguration, Color4>(s => s.CustomColours.ContainsKey("SliderBall") ? s.CustomColours["SliderBall"] : Ball.AccentColour);
}
protected override void CheckForResult(bool userTriggered, double timeOffset)
-3
View File
@@ -82,9 +82,6 @@ namespace osu.Game.Rulesets.Osu
if (mods.HasFlag(LegacyMods.Target))
yield return new OsuModTarget();
if (mods.HasFlag(LegacyMods.TouchDevice))
yield return new OsuModTouchDevice();
}
public override IEnumerable<Mod> GetModsFor(ModType type)
@@ -74,6 +74,6 @@ namespace osu.Game.Rulesets.Osu.Scoring
protected override JudgementResult CreateResult(Judgement judgement) => new OsuJudgementResult(judgement);
public override HitWindows CreateHitWindows() => new OsuHitWindows();
protected override HitWindows CreateHitWindows() => new OsuHitWindows();
}
}
@@ -112,7 +112,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
}
[BackgroundDependencyLoader]
private void load(OsuConfigManager config, IBindable<WorkingBeatmap> beatmap)
private void load(OsuConfigManager config, IBindableBeatmap beatmap)
{
InternalChild = expandTarget = new Container
{
@@ -1,5 +1,5 @@
// 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.
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using Foundation;
using osu.Framework.iOS;
@@ -1,5 +1,5 @@
// 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.
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using UIKit;
+1 -1
View File
@@ -13,7 +13,7 @@
<key>LSRequiresIPhoneOS</key>
<true/>
<key>MinimumOSVersion</key>
<string>10.0</string>
<string>11.0</string>
<key>UIDeviceFamily</key>
<array>
<integer>1</integer>
@@ -26,7 +26,9 @@
</LinkDescription>
<Compile Include="Application.cs" />
<Compile Include="AppDelegate.cs" />
<Compile Include="..\osu.Game.Rulesets.Taiko.Tests\**\*.cs" Exclude="**\obj\**">
</ItemGroup>
<ItemGroup>
<Compile Include="..\osu.Game.Rulesets.Taiko.Tests\*.cs">
<Link>%(RecursiveDir)%(Filename)%(Extension)</Link>
</Compile>
</ItemGroup>
@@ -39,6 +41,32 @@
<Project>{F167E17A-7DE6-4AF5-B920-A5112296C695}</Project>
<Name>osu.Game.Rulesets.Taiko</Name>
</ProjectReference>
<ProjectReference Include="..\osu-resources\osu.Game.Resources\osu.Game.Resources.csproj">
<Project>{D9A367C9-4C1A-489F-9B05-A0CEA2B53B58}</Project>
<Name>osu.Game.Resources</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Xml" />
<Reference Include="System.Core" />
<Reference Include="Xamarin.iOS" />
<Reference Include="mscorlib" />
<Reference Include="System.IO.Compression" />
<Reference Include="System.Net.Http" />
</ItemGroup>
<ItemGroup Label="Package References">
<PackageReference Include="Humanizer" Version="2.5.16" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.1" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.1" />
<PackageReference Include="ppy.osu.Framework" Version="2019.122.0" />
<PackageReference Include="ppy.osu.Framework.iOS" Version="2019.122.0" />
<PackageReference Include="SharpCompress" Version="0.22.0" />
<PackageReference Include="NUnit" Version="3.11.0" />
<PackageReference Include="SharpRaven" Version="2.4.0" />
<PackageReference Include="System.ComponentModel.Annotations" Version="4.5.0" />
<PackageReference Include="ppy.osu.Framework.NativeLibs" Version="2019.110.0" ExcludeAssets="all" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\iOS\Xamarin.iOS.CSharp.targets" />
<Import Project="..\packages\NETStandard.Library.2.0.0\build\netstandard2.0\NETStandard.Library.targets" Condition="Exists('..\packages\NETStandard.Library.2.0.0\build\netstandard2.0\NETStandard.Library.targets')" />
@@ -47,7 +47,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
difficultyHitObjects.Sort((a, b) => a.BaseHitObject.StartTime.CompareTo(b.BaseHitObject.StartTime));
if (!calculateStrainValues(difficultyHitObjects, timeRate))
return new TaikoDifficultyAttributes(mods, 0);
return new DifficultyAttributes(mods, 0);
double starRating = calculateDifficulty(difficultyHitObjects, timeRate) * star_scaling_factor;
@@ -67,6 +67,6 @@ namespace osu.Game.Rulesets.Taiko.Scoring
Health.Value = 0;
}
public override HitWindows CreateHitWindows() => new TaikoHitWindows();
protected override HitWindows CreateHitWindows() => new TaikoHitWindows();
}
}
+2 -2
View File
@@ -1,5 +1,5 @@
// 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.
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using Foundation;
using osu.Framework.iOS;
+2 -2
View File
@@ -1,5 +1,5 @@
// 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.
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using UIKit;
+1 -1
View File
@@ -13,7 +13,7 @@
<key>LSRequiresIPhoneOS</key>
<true/>
<key>MinimumOSVersion</key>
<string>10.0</string>
<string>11.0</string>
<key>UIDeviceFamily</key>
<array>
<integer>1</integer>
+48 -1
View File
@@ -26,7 +26,30 @@
</LinkDescription>
<Compile Include="Application.cs" />
<Compile Include="AppDelegate.cs" />
<Compile Include="..\osu.Game.Tests\**\*.cs" Exclude="**\obj\**">
</ItemGroup>
<ItemGroup>
<Compile Include="..\osu.Game.Tests\**\Beatmaps\**\*.cs">
<Link>%(RecursiveDir)%(Filename)%(Extension)</Link>
</Compile>
<Compile Include="..\osu.Game.Tests\**\Chat\**\*.cs">
<Link>%(RecursiveDir)%(Filename)%(Extension)</Link>
</Compile>
<Compile Include="..\osu.Game.Tests\**\NonVisual\**\*.cs">
<Link>%(RecursiveDir)%(Filename)%(Extension)</Link>
</Compile>
<Compile Include="..\osu.Game.Tests\**\Scores\**\*.cs">
<Link>%(RecursiveDir)%(Filename)%(Extension)</Link>
</Compile>
<Compile Include="..\osu.Game.Tests\**\ScrollAlgorithms\**\*.cs">
<Link>%(RecursiveDir)%(Filename)%(Extension)</Link>
</Compile>
<Compile Include="..\osu.Game.Tests\**\Visual\**\*.cs">
<Link>%(RecursiveDir)%(Filename)%(Extension)</Link>
</Compile>
<Compile Include="..\osu.Game.Tests\**\Resources\**\*.cs">
<Link>%(RecursiveDir)%(Filename)%(Extension)</Link>
</Compile>
<Compile Include="..\osu.Game.Tests\*.cs">
<Link>%(RecursiveDir)%(Filename)%(Extension)</Link>
</Compile>
</ItemGroup>
@@ -51,9 +74,33 @@
<Project>{F167E17A-7DE6-4AF5-B920-A5112296C695}</Project>
<Name>osu.Game.Rulesets.Taiko</Name>
</ProjectReference>
<ProjectReference Include="..\osu-resources\osu.Game.Resources\osu.Game.Resources.csproj">
<Project>{D9A367C9-4C1A-489F-9B05-A0CEA2B53B58}</Project>
<Name>osu.Game.Resources</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Xml" />
<Reference Include="System.Core" />
<Reference Include="Xamarin.iOS" />
<Reference Include="mscorlib" />
<Reference Include="System.IO.Compression" />
<Reference Include="System.Net.Http" />
</ItemGroup>
<ItemGroup Label="Package References">
<PackageReference Include="Humanizer" Version="2.5.16" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.1" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.1" />
<PackageReference Include="ppy.osu.Framework" Version="2019.122.0" />
<PackageReference Include="ppy.osu.Framework.iOS" Version="2019.122.0" />
<PackageReference Include="SharpCompress" Version="0.22.0" />
<PackageReference Include="NUnit" Version="3.11.0" />
<PackageReference Include="SharpRaven" Version="2.4.0" />
<PackageReference Include="System.ComponentModel.Annotations" Version="4.5.0" />
<PackageReference Include="DeepEqual" Version="2.0.0" />
<PackageReference Include="ppy.osu.Framework.NativeLibs" Version="2019.110.0" ExcludeAssets="all" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\iOS\Xamarin.iOS.CSharp.targets" />
<Import Project="..\packages\NETStandard.Library.2.0.0\build\netstandard2.0\NETStandard.Library.targets" Condition="Exists('..\packages\NETStandard.Library.2.0.0\build\netstandard2.0\NETStandard.Library.targets')" />
@@ -27,7 +27,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
[Test]
public void TestDecodeBeatmapVersion()
{
using (var resStream = TestResources.OpenResource("beatmap-version.osu"))
using (var resStream = Resource.OpenResource("beatmap-version.osu"))
using (var stream = new StreamReader(resStream))
{
var decoder = Decoder.GetDecoder<Beatmap>(stream);
@@ -47,7 +47,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
public void TestDecodeBeatmapGeneral()
{
var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false };
using (var resStream = TestResources.OpenResource("Soleily - Renatus (Gamu) [Insane].osu"))
using (var resStream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu"))
using (var stream = new StreamReader(resStream))
{
var beatmap = decoder.Decode(stream);
@@ -70,7 +70,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
public void TestDecodeBeatmapEditor()
{
var decoder = new LegacyBeatmapDecoder();
using (var resStream = TestResources.OpenResource("Soleily - Renatus (Gamu) [Insane].osu"))
using (var resStream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu"))
using (var stream = new StreamReader(resStream))
{
var beatmapInfo = decoder.Decode(stream).BeatmapInfo;
@@ -95,7 +95,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
public void TestDecodeBeatmapMetadata()
{
var decoder = new LegacyBeatmapDecoder();
using (var resStream = TestResources.OpenResource("Soleily - Renatus (Gamu) [Insane].osu"))
using (var resStream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu"))
using (var stream = new StreamReader(resStream))
{
var beatmap = decoder.Decode(stream);
@@ -119,7 +119,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
public void TestDecodeBeatmapDifficulty()
{
var decoder = new LegacyBeatmapDecoder();
using (var resStream = TestResources.OpenResource("Soleily - Renatus (Gamu) [Insane].osu"))
using (var resStream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu"))
using (var stream = new StreamReader(resStream))
{
var difficulty = decoder.Decode(stream).BeatmapInfo.BaseDifficulty;
@@ -137,7 +137,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
public void TestDecodeBeatmapEvents()
{
var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false };
using (var resStream = TestResources.OpenResource("Soleily - Renatus (Gamu) [Insane].osu"))
using (var resStream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu"))
using (var stream = new StreamReader(resStream))
{
var beatmap = decoder.Decode(stream);
@@ -155,7 +155,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
public void TestDecodeBeatmapTimingPoints()
{
var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false };
using (var resStream = TestResources.OpenResource("Soleily - Renatus (Gamu) [Insane].osu"))
using (var resStream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu"))
using (var stream = new StreamReader(resStream))
{
var beatmap = decoder.Decode(stream);
@@ -190,7 +190,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
public void TestDecodeBeatmapColours()
{
var decoder = new LegacySkinDecoder();
using (var resStream = TestResources.OpenResource("Soleily - Renatus (Gamu) [Insane].osu"))
using (var resStream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu"))
using (var stream = new StreamReader(resStream))
{
var comboColors = decoder.Decode(stream).ComboColours;
@@ -215,7 +215,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
public void TestDecodeBeatmapComboOffsetsOsu()
{
var decoder = new LegacyBeatmapDecoder();
using (var resStream = TestResources.OpenResource("hitobject-combo-offset.osu"))
using (var resStream = Resource.OpenResource("hitobject-combo-offset.osu"))
using (var stream = new StreamReader(resStream))
{
var beatmap = decoder.Decode(stream);
@@ -237,7 +237,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
public void TestDecodeBeatmapComboOffsetsCatch()
{
var decoder = new LegacyBeatmapDecoder();
using (var resStream = TestResources.OpenResource("hitobject-combo-offset.osu"))
using (var resStream = Resource.OpenResource("hitobject-combo-offset.osu"))
using (var stream = new StreamReader(resStream))
{
var beatmap = decoder.Decode(stream);
@@ -259,7 +259,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
public void TestDecodeBeatmapHitObjects()
{
var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false };
using (var resStream = TestResources.OpenResource("Soleily - Renatus (Gamu) [Insane].osu"))
using (var resStream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu"))
using (var stream = new StreamReader(resStream))
{
var hitObjects = decoder.Decode(stream).HitObjects;
@@ -286,7 +286,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
public void TestDecodeControlPointCustomSampleBank()
{
var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false };
using (var resStream = TestResources.OpenResource("controlpoint-custom-samplebank.osu"))
using (var resStream = Resource.OpenResource("controlpoint-custom-samplebank.osu"))
using (var stream = new StreamReader(resStream))
{
var hitObjects = decoder.Decode(stream).HitObjects;
@@ -307,7 +307,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
public void TestDecodeHitObjectCustomSampleBank()
{
var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false };
using (var resStream = TestResources.OpenResource("hitobject-custom-samplebank.osu"))
using (var resStream = Resource.OpenResource("hitobject-custom-samplebank.osu"))
using (var stream = new StreamReader(resStream))
{
var hitObjects = decoder.Decode(stream).HitObjects;
@@ -324,7 +324,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
public void TestDecodeHitObjectFileSamples()
{
var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false };
using (var resStream = TestResources.OpenResource("hitobject-file-samples.osu"))
using (var resStream = Resource.OpenResource("hitobject-file-samples.osu"))
using (var stream = new StreamReader(resStream))
{
var hitObjects = decoder.Decode(stream).HitObjects;
@@ -342,7 +342,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
public void TestDecodeSliderSamples()
{
var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false };
using (var resStream = TestResources.OpenResource("slider-samples.osu"))
using (var resStream = Resource.OpenResource("slider-samples.osu"))
using (var stream = new StreamReader(resStream))
{
var hitObjects = decoder.Decode(stream).HitObjects;
@@ -385,7 +385,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
public void TestDecodeHitObjectNullAdditionBank()
{
var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false };
using (var resStream = TestResources.OpenResource("hitobject-no-addition-bank.osu"))
using (var resStream = Resource.OpenResource("hitobject-no-addition-bank.osu"))
using (var stream = new StreamReader(resStream))
{
var hitObjects = decoder.Decode(stream).HitObjects;
@@ -19,7 +19,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
public void TestDecodeStoryboardEvents()
{
var decoder = new LegacyStoryboardDecoder();
using (var resStream = TestResources.OpenResource("Himeringo - Yotsuya-san ni Yoroshiku (RLC) [Winber1's Extreme].osu"))
using (var resStream = Resource.OpenResource("Himeringo - Yotsuya-san ni Yoroshiku (RLC) [Winber1's Extreme].osu"))
using (var stream = new StreamReader(resStream))
{
var storyboard = decoder.Decode(stream);
@@ -91,7 +91,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
public void TestDecodeVariableWithSuffix()
{
var decoder = new LegacyStoryboardDecoder();
using (var resStream = TestResources.OpenResource("variable-with-suffix.osb"))
using (var resStream = Resource.OpenResource("variable-with-suffix.osb"))
using (var stream = new StreamReader(resStream))
{
var storyboard = decoder.Decode(stream);
@@ -146,7 +146,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
/// <returns>The <see cref="Beatmap"/> after being decoded by an <see cref="LegacyBeatmapDecoder"/>.</returns>
private Beatmap decode(string filename, out Beatmap jsonDecoded)
{
using (var stream = TestResources.OpenResource(filename))
using (var stream = Resource.OpenResource(filename))
using (var sr = new StreamReader(stream))
{
var legacyDecoded = new LegacyBeatmapDecoder { ApplyOffsets = false }.Decode(sr);
@@ -12,7 +12,6 @@ using osu.Framework.Platform;
using osu.Game.IPC;
using osu.Framework.Allocation;
using osu.Game.Beatmaps;
using osu.Game.Tests.Resources;
using SharpCompress.Archives.Zip;
namespace osu.Game.Tests.Beatmaps.IO
@@ -20,6 +19,8 @@ namespace osu.Game.Tests.Beatmaps.IO
[TestFixture]
public class ImportBeatmapTest
{
public const string TEST_OSZ_PATH = @"../../../../osu-resources/osu.Game.Resources/Beatmaps/241526 Soleily - Renatus.osz";
[Test]
public void TestImportWhenClosed()
{
@@ -113,7 +114,7 @@ namespace osu.Game.Tests.Beatmaps.IO
Assert.AreEqual(0, fireCount -= 2);
var breakTemp = TestResources.GetTestBeatmapForImport();
var breakTemp = createTemporaryBeatmap();
MemoryStream brokenOsu = new MemoryStream(new byte[] { 1, 3, 3, 7 });
MemoryStream brokenOsz = new MemoryStream(File.ReadAllBytes(breakTemp));
@@ -222,7 +223,7 @@ namespace osu.Game.Tests.Beatmaps.IO
var osu = loadOsu(host);
var temp = TestResources.GetTestBeatmapForImport();
var temp = createTemporaryBeatmap();
var importer = new ArchiveImportIPCChannel(client);
if (!importer.ImportAsync(temp).Wait(10000))
@@ -247,7 +248,7 @@ namespace osu.Game.Tests.Beatmaps.IO
try
{
var osu = loadOsu(host);
var temp = TestResources.GetTestBeatmapForImport();
var temp = createTemporaryBeatmap();
using (File.OpenRead(temp))
osu.Dependencies.Get<BeatmapManager>().Import(temp);
ensureLoaded(osu);
@@ -261,9 +262,17 @@ namespace osu.Game.Tests.Beatmaps.IO
}
}
private static string createTemporaryBeatmap()
{
var temp = Path.GetTempFileName() + ".osz";
File.Copy(TEST_OSZ_PATH, temp, true);
Assert.IsTrue(File.Exists(temp));
return temp;
}
public static BeatmapSetInfo LoadOszIntoOsu(OsuGameBase osu, string path = null)
{
var temp = path ?? TestResources.GetTestBeatmapForImport();
var temp = path ?? createTemporaryBeatmap();
var manager = osu.Dependencies.Get<BeatmapManager>();
@@ -17,7 +17,7 @@ namespace osu.Game.Tests.Beatmaps.IO
[Test]
public void TestReadBeatmaps()
{
using (var osz = TestResources.GetTestBeatmapStream())
using (var osz = Resource.OpenResource("Beatmaps.241526 Soleily - Renatus.osz"))
{
var reader = new ZipArchiveReader(osz);
string[] expected =
@@ -44,7 +44,7 @@ namespace osu.Game.Tests.Beatmaps.IO
[Test]
public void TestReadMetadata()
{
using (var osz = TestResources.GetTestBeatmapStream())
using (var osz = Resource.OpenResource("Beatmaps.241526 Soleily - Renatus.osz"))
{
var reader = new ZipArchiveReader(osz);
@@ -72,7 +72,7 @@ namespace osu.Game.Tests.Beatmaps.IO
[Test]
public void TestReadFile()
{
using (var osz = TestResources.GetTestBeatmapStream())
using (var osz = Resource.OpenResource("Beatmaps.241526 Soleily - Renatus.osz"))
{
var reader = new ZipArchiveReader(osz);
using (var stream = new StreamReader(
+20
View File
@@ -0,0 +1,20 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System;
using System.IO;
using System.Reflection;
namespace osu.Game.Tests.Resources
{
public static class Resource
{
public static Stream OpenResource(string name)
{
var localPath = Path.GetDirectoryName(Uri.UnescapeDataString(new UriBuilder(Assembly.GetExecutingAssembly().CodeBase).Path));
return Assembly.GetExecutingAssembly().GetManifestResourceStream($@"osu.Game.Tests.Resources.{name}") ??
Assembly.LoadFrom(Path.Combine(localPath, @"osu.Game.Resources.dll")).GetManifestResourceStream($@"osu.Game.Resources.{name}");
}
}
}
-28
View File
@@ -1,28 +0,0 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System.IO;
using NUnit.Framework;
using osu.Framework.IO.Stores;
namespace osu.Game.Tests.Resources
{
public static class TestResources
{
public static Stream OpenResource(string name) => new DllResourceStore("osu.Game.Tests.dll").GetStream($"Resources/{name}");
public static Stream GetTestBeatmapStream() => new DllResourceStore("osu.Game.Resources.dll").GetStream("Beatmaps/241526 Soleily - Renatus.osz");
public static string GetTestBeatmapForImport()
{
var temp = Path.GetTempFileName() + ".osz";
using (var stream = GetTestBeatmapStream())
using (var newFile = File.Create(temp))
stream.CopyTo(newFile);
Assert.IsTrue(File.Exists(temp));
return temp;
}
}
}
-2
View File
@@ -1,2 +0,0 @@
[General]
Name: test skin
-8
View File
@@ -1,8 +0,0 @@
[General]
Name: test skin
[Colours]
Combo1 : 142,199,255
Combo2 : 255,128,128
Combo3 : 128,255,255
Combo7 : 100,100,100,100
+12 -2
View File
@@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@@ -15,13 +16,14 @@ using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Rulesets.Scoring;
using osu.Game.Scoring;
using osu.Game.Tests.Resources;
using osu.Game.Users;
namespace osu.Game.Tests.Scores.IO
{
public class ImportScoreTest
{
public const string TEST_OSZ_PATH = @"../../../../osu-resources/osu.Game.Resources/Beatmaps/241526 Soleily - Renatus.osz";
[Test]
public void TestBasicImport()
{
@@ -130,13 +132,21 @@ namespace osu.Game.Tests.Scores.IO
return scoreManager.GetAllUsableScores().First();
}
private string createTemporaryBeatmap()
{
var temp = Path.GetTempFileName() + ".osz";
File.Copy(TEST_OSZ_PATH, temp, true);
Assert.IsTrue(File.Exists(temp));
return temp;
}
private OsuGameBase loadOsu(GameHost host)
{
var osu = new OsuGameBase();
Task.Run(() => host.Run(osu));
waitForOrAssert(() => osu.IsLoaded, @"osu! failed to start in a reasonable amount of time");
var beatmapFile = TestResources.GetTestBeatmapForImport();
var beatmapFile = createTemporaryBeatmap();
var beatmapManager = osu.Dependencies.Get<BeatmapManager>();
beatmapManager.Import(beatmapFile);
@@ -1,44 +0,0 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic;
using System.IO;
using NUnit.Framework;
using osu.Game.Skinning;
using osu.Game.Tests.Resources;
using osuTK.Graphics;
namespace osu.Game.Tests.Skins
{
[TestFixture]
public class LegacySkinDecoderTest
{
[TestCase(true)]
[TestCase(false)]
public void TestDecodeSkinColours(bool hasColours)
{
var decoder = new LegacySkinDecoder();
using (var resStream = TestResources.OpenResource(hasColours ? "skin.ini" : "skin-empty.ini"))
using (var stream = new StreamReader(resStream))
{
var comboColors = decoder.Decode(stream).ComboColours;
List<Color4> expectedColors;
if (hasColours)
expectedColors = new List<Color4>
{
new Color4(142, 199, 255, 255),
new Color4(255, 128, 128, 255),
new Color4(128, 255, 255, 255),
new Color4(100, 100, 100, 100),
};
else
expectedColors = new DefaultSkin().Configuration.ComboColours;
Assert.AreEqual(expectedColors.Count, comboColors.Count);
for (int i = 0; i < expectedColors.Count; i++)
Assert.AreEqual(expectedColors[i], comboColors[i]);
}
}
}
}
+13 -2
View File
@@ -2,16 +2,27 @@
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Shapes;
using osu.Game.Screens.Menu;
using osuTK.Graphics;
namespace osu.Game.Tests.Visual
{
public class TestCaseDisclaimer : ScreenTestCase
public class TestCaseDisclaimer : OsuTestCase
{
[BackgroundDependencyLoader]
private void load()
{
LoadScreen(new Disclaimer());
Children = new Drawable[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = Color4.Black,
},
new Disclaimer()
};
}
}
}
+2 -2
View File
@@ -9,11 +9,11 @@ using osu.Game.Screens.Tournament.Teams;
namespace osu.Game.Tests.Visual
{
[Description("for tournament use")]
public class TestCaseDrawings : ScreenTestCase
public class TestCaseDrawings : OsuTestCase
{
public TestCaseDrawings()
{
LoadScreen(new Drawings
Add(new Drawings
{
TeamList = new TestTeamList(),
});
@@ -15,6 +15,7 @@ using osu.Framework.Timing;
using osu.Game.Beatmaps;
using osu.Game.Screens.Edit.Compose.Components.Timeline;
using osuTK.Graphics;
using osu.Framework.Audio;
namespace osu.Game.Tests.Visual
{
@@ -30,7 +31,7 @@ namespace osu.Game.Tests.Visual
};
[BackgroundDependencyLoader]
private void load()
private void load(AudioManager audioManager)
{
Beatmap.Value = new WaveformTestBeatmap();
@@ -85,7 +86,7 @@ namespace osu.Game.Tests.Visual
}
[BackgroundDependencyLoader]
private void load(IAdjustableClock adjustableClock, IBindable<WorkingBeatmap> beatmap)
private void load(IAdjustableClock adjustableClock, IBindableBeatmap beatmap)
{
this.adjustableClock = adjustableClock;
this.beatmap.BindTo(beatmap);
@@ -4,7 +4,6 @@
using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Screens;
using osu.Game.Screens;
using osu.Game.Screens.Menu;
using osuTK.Graphics;
@@ -58,7 +57,7 @@ namespace osu.Game.Tests.Visual
public OsuLogo Logo;
private TestScreen screen;
public bool ScreenLoaded => screen.IsCurrentScreen();
public bool ScreenLoaded => screen.IsCurrentScreen;
public TestLoader(double delay)
{
@@ -97,7 +96,7 @@ namespace osu.Game.Tests.Visual
{
public TestScreen()
{
InternalChild = new Box
Child = new Box
{
RelativeSizeAxes = Axes.Both,
Colour = Color4.DarkSlateGray,
@@ -108,7 +107,7 @@ namespace osu.Game.Tests.Visual
protected override void LogoArriving(OsuLogo logo, bool resuming)
{
base.LogoArriving(logo, resuming);
InternalChild.FadeInFromZero(200);
Child.FadeInFromZero(200);
}
}
}
@@ -16,7 +16,7 @@ using osuTK.Graphics;
namespace osu.Game.Tests.Visual
{
public class TestCaseLoungeRoomsContainer : MultiplayerTestCase
public class TestCaseLoungeRoomsContainer : OsuTestCase
{
public override IReadOnlyList<Type> RequiredTypes => new[]
{
@@ -61,7 +61,7 @@ namespace osu.Game.Tests.Visual
AddAssert("first room removed", () => container.Rooms.All(r => r.Room.RoomID.Value != 0));
AddStep("select first room", () => container.Rooms.First().Action?.Invoke());
AddAssert("first room selected", () => Room == roomManager.Rooms.First());
AddAssert("first room selected", () => container.SelectedRoom.Value == roomManager.Rooms.First());
AddStep("join first room", () => container.Rooms.First().Action?.Invoke());
AddAssert("first room joined", () => roomManager.Rooms.First().Status.Value is JoinedRoomStatus);
@@ -71,11 +71,7 @@ namespace osu.Game.Tests.Visual
private class TestRoomManager : IRoomManager
{
public event Action RoomsUpdated
{
add { }
remove { }
}
public event Action RoomsUpdated;
public readonly BindableList<Room> Rooms = new BindableList<Room>();
IBindableList<Room> IRoomManager.Rooms => Rooms;
@@ -89,6 +85,10 @@ namespace osu.Game.Tests.Visual
public void PartRoom()
{
}
public void Filter(FilterCriteria criteria)
{
}
}
private class JoinedRoomStatus : RoomStatus
+8 -4
View File
@@ -12,7 +12,7 @@ using osu.Game.Screens.Multi.Match.Components;
namespace osu.Game.Tests.Visual
{
public class TestCaseMatchHeader : MultiplayerTestCase
public class TestCaseMatchHeader : OsuTestCase
{
public override IReadOnlyList<Type> RequiredTypes => new[]
{
@@ -21,7 +21,11 @@ namespace osu.Game.Tests.Visual
public TestCaseMatchHeader()
{
Room.Playlist.Add(new PlaylistItem
var room = new Room();
var header = new Header(room);
room.Playlist.Add(new PlaylistItem
{
Beatmap = new BeatmapInfo
{
@@ -42,9 +46,9 @@ namespace osu.Game.Tests.Visual
}
});
Room.Type.Value = new GameTypeTimeshift();
room.Type.Value = new GameTypeTimeshift();
Child = new Header();
Child = header;
}
}
}
+16 -13
View File
@@ -14,7 +14,7 @@ using osu.Game.Screens.Multi.Match.Components;
namespace osu.Game.Tests.Visual
{
[TestFixture]
public class TestCaseMatchInfo : MultiplayerTestCase
public class TestCaseMatchInfo : OsuTestCase
{
public override IReadOnlyList<Type> RequiredTypes => new[]
{
@@ -27,15 +27,18 @@ namespace osu.Game.Tests.Visual
[BackgroundDependencyLoader]
private void load(RulesetStore rulesets)
{
Add(new Info());
var room = new Room();
AddStep(@"set name", () => Room.Name.Value = @"Room Name?");
AddStep(@"set availability", () => Room.Availability.Value = RoomAvailability.FriendsOnly);
AddStep(@"set status", () => Room.Status.Value = new RoomStatusPlaying());
Info info = new Info(room);
Add(info);
AddStep(@"set name", () => room.Name.Value = @"Room Name?");
AddStep(@"set availability", () => room.Availability.Value = RoomAvailability.FriendsOnly);
AddStep(@"set status", () => room.Status.Value = new RoomStatusPlaying());
AddStep(@"set beatmap", () =>
{
Room.Playlist.Clear();
Room.Playlist.Add(new PlaylistItem
room.Playlist.Clear();
room.Playlist.Add(new PlaylistItem
{
Beatmap = new BeatmapInfo
{
@@ -51,14 +54,14 @@ namespace osu.Game.Tests.Visual
});
});
AddStep(@"change name", () => Room.Name.Value = @"Room Name!");
AddStep(@"change availability", () => Room.Availability.Value = RoomAvailability.InviteOnly);
AddStep(@"change status", () => Room.Status.Value = new RoomStatusOpen());
AddStep(@"null beatmap", () => Room.Playlist.Clear());
AddStep(@"change name", () => room.Name.Value = @"Room Name!");
AddStep(@"change availability", () => room.Availability.Value = RoomAvailability.InviteOnly);
AddStep(@"change status", () => room.Status.Value = new RoomStatusOpen());
AddStep(@"null beatmap", () => room.Playlist.Clear());
AddStep(@"change beatmap", () =>
{
Room.Playlist.Clear();
Room.Playlist.Add(new PlaylistItem
room.Playlist.Clear();
room.Playlist.Add(new PlaylistItem
{
Beatmap = new BeatmapInfo
{
@@ -6,24 +6,24 @@ using Newtonsoft.Json;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Game.Online.API;
using osu.Game.Online.Multiplayer;
using osu.Game.Screens.Multi.Match.Components;
using osu.Game.Users;
using osuTK;
namespace osu.Game.Tests.Visual
{
public class TestCaseMatchLeaderboard : MultiplayerTestCase
public class TestCaseMatchLeaderboard : OsuTestCase
{
public TestCaseMatchLeaderboard()
{
Room.RoomID.Value = 3;
Add(new MatchLeaderboard
{
Origin = Anchor.Centre,
Anchor = Anchor.Centre,
Size = new Vector2(550f, 450f),
Scope = MatchLeaderboardScope.Overall,
Room = new Room { RoomID = { Value = 3 } }
});
}
@@ -1,7 +1,9 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic;
using NUnit.Framework;
using osu.Framework.Configuration;
using osu.Framework.Graphics;
using osu.Game.Screens.Multi.Match.Components;
using osu.Game.Users;
@@ -9,14 +11,22 @@ using osu.Game.Users;
namespace osu.Game.Tests.Visual
{
[TestFixture]
public class TestCaseMatchParticipants : MultiplayerTestCase
public class TestCaseMatchParticipants : OsuTestCase
{
private readonly Bindable<int?> maxParticipants = new Bindable<int?>();
private readonly Bindable<IEnumerable<User>> users = new Bindable<IEnumerable<User>>();
public TestCaseMatchParticipants()
{
Add(new Participants { RelativeSizeAxes = Axes.Both });
Participants participants;
AddStep(@"set max to null", () => Room.MaxParticipants.Value = null);
AddStep(@"set users", () => Room.Participants.Value = new[]
Add(participants = new Participants { RelativeSizeAxes = Axes.Both });
participants.MaxParticipants.BindTo(maxParticipants);
participants.Users.BindTo(users);
AddStep(@"set max to null", () => maxParticipants.Value = null);
AddStep(@"set users", () => users.Value = new[]
{
new User
{
@@ -44,9 +54,9 @@ namespace osu.Game.Tests.Visual
},
});
AddStep(@"set max", () => Room.MaxParticipants.Value = 10);
AddStep(@"clear users", () => Room.Participants.Value = new User[] { });
AddStep(@"set max to null", () => Room.MaxParticipants.Value = null);
AddStep(@"set max", () => maxParticipants.Value = 10);
AddStep(@"clear users", () => users.Value = new User[] { });
AddStep(@"set max to null", () => maxParticipants.Value = null);
}
}
}
+31 -14
View File
@@ -8,6 +8,7 @@ using osu.Framework.Allocation;
using osu.Game.Beatmaps;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.Multiplayer;
using osu.Game.Scoring;
using osu.Game.Screens.Multi.Match.Components;
using osu.Game.Screens.Multi.Ranking;
@@ -18,7 +19,7 @@ using osu.Game.Users;
namespace osu.Game.Tests.Visual
{
public class TestCaseMatchResults : MultiplayerTestCase
public class TestCaseMatchResults : OsuTestCase
{
public override IReadOnlyList<Type> RequiredTypes => new[]
{
@@ -37,52 +38,68 @@ namespace osu.Game.Tests.Visual
if (beatmapInfo != null)
Beatmap.Value = beatmaps.GetWorkingBeatmap(beatmapInfo);
Room.RoomID.Value = 1;
Room.Name.Value = "an awesome room";
LoadScreen(new TestMatchResults(new ScoreInfo
Child = new TestMatchResults(new ScoreInfo
{
User = new User { Id = 10 },
}));
});
}
private class TestMatchResults : MatchResults
{
private readonly Room room;
public TestMatchResults(ScoreInfo score)
: base(score)
: this(score, new Room
{
RoomID = { Value = 1 },
Name = { Value = "an awesome room" }
})
{
}
protected override IEnumerable<IResultPageInfo> CreateResultPages() => new[] { new TestRoomLeaderboardPageInfo(Score, Beatmap.Value) };
public TestMatchResults(ScoreInfo score, Room room)
: base(score, room)
{
this.room = room;
}
protected override IEnumerable<IResultPageInfo> CreateResultPages() => new[] { new TestRoomLeaderboardPageInfo(Score, Beatmap, room) };
}
private class TestRoomLeaderboardPageInfo : RoomLeaderboardPageInfo
{
private readonly ScoreInfo score;
private readonly WorkingBeatmap beatmap;
private readonly Room room;
public TestRoomLeaderboardPageInfo(ScoreInfo score, WorkingBeatmap beatmap)
: base(score, beatmap)
public TestRoomLeaderboardPageInfo(ScoreInfo score, WorkingBeatmap beatmap, Room room)
: base(score, beatmap, room)
{
this.score = score;
this.beatmap = beatmap;
this.room = room;
}
public override ResultsPage CreatePage() => new TestRoomLeaderboardPage(score, beatmap);
public override ResultsPage CreatePage() => new TestRoomLeaderboardPage(score, beatmap, room);
}
private class TestRoomLeaderboardPage : RoomLeaderboardPage
{
public TestRoomLeaderboardPage(ScoreInfo score, WorkingBeatmap beatmap)
: base(score, beatmap)
public TestRoomLeaderboardPage(ScoreInfo score, WorkingBeatmap beatmap, Room room)
: base(score, beatmap, room)
{
}
protected override MatchLeaderboard CreateLeaderboard() => new TestMatchLeaderboard();
protected override MatchLeaderboard CreateLeaderboard(Room room) => new TestMatchLeaderboard(room);
}
private class TestMatchLeaderboard : RoomLeaderboardPage.ResultsMatchLeaderboard
{
public TestMatchLeaderboard(Room room)
: base(room)
{
}
protected override APIRequest FetchScores(Action<IEnumerable<APIRoomScoreInfo>> scoresCallback)
{
var scores = Enumerable.Range(0, 50).Select(createRoomScore).ToArray();
@@ -13,11 +13,12 @@ using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
using osu.Game.Online.Multiplayer;
using osu.Game.Screens.Multi;
using osu.Game.Screens.Multi.Lounge.Components;
using osu.Game.Screens.Multi.Match.Components;
namespace osu.Game.Tests.Visual
{
public class TestCaseMatchSettingsOverlay : MultiplayerTestCase
public class TestCaseMatchSettingsOverlay : OsuTestCase
{
public override IReadOnlyList<Type> RequiredTypes => new[]
{
@@ -27,14 +28,14 @@ namespace osu.Game.Tests.Visual
[Cached(Type = typeof(IRoomManager))]
private TestRoomManager roomManager = new TestRoomManager();
private Room room;
private TestRoomSettings settings;
[SetUp]
public void Setup() => Schedule(() =>
{
Room = new Room();
settings = new TestRoomSettings
room = new Room();
settings = new TestRoomSettings(room)
{
RelativeSizeAxes = Axes.Both,
State = Visibility.Visible
@@ -48,19 +49,19 @@ namespace osu.Game.Tests.Visual
{
AddStep("clear name and beatmap", () =>
{
Room.Name.Value = "";
Room.Playlist.Clear();
room.Name.Value = "";
room.Playlist.Clear();
});
AddAssert("button disabled", () => !settings.ApplyButton.Enabled);
AddStep("set name", () => Room.Name.Value = "Room name");
AddStep("set name", () => room.Name.Value = "Room name");
AddAssert("button disabled", () => !settings.ApplyButton.Enabled);
AddStep("set beatmap", () => Room.Playlist.Add(new PlaylistItem { Beatmap = new DummyWorkingBeatmap().BeatmapInfo }));
AddStep("set beatmap", () => room.Playlist.Add(new PlaylistItem { Beatmap = new DummyWorkingBeatmap().BeatmapInfo }));
AddAssert("button enabled", () => settings.ApplyButton.Enabled);
AddStep("clear name", () => Room.Name.Value = "");
AddStep("clear name", () => room.Name.Value = "");
AddAssert("button disabled", () => !settings.ApplyButton.Enabled);
}
@@ -116,12 +117,17 @@ namespace osu.Game.Tests.Visual
private class TestRoomSettings : MatchSettingsOverlay
{
public TriangleButton ApplyButton => Settings.ApplyButton;
public new TriangleButton ApplyButton => base.ApplyButton;
public OsuTextBox NameField => Settings.NameField;
public OsuDropdown<TimeSpan> DurationField => Settings.DurationField;
public new OsuTextBox NameField => base.NameField;
public new OsuDropdown<TimeSpan> DurationField => base.DurationField;
public OsuSpriteText ErrorText => Settings.ErrorText;
public new OsuSpriteText ErrorText => base.ErrorText;
public TestRoomSettings(Room room)
: base(room)
{
}
}
private class TestRoomManager : IRoomManager
@@ -130,11 +136,7 @@ namespace osu.Game.Tests.Visual
public Func<Room, bool> CreateRequested;
public event Action RoomsUpdated
{
add { }
remove { }
}
public event Action RoomsUpdated;
public IBindableList<Room> Rooms { get; } = null;
@@ -152,6 +154,8 @@ namespace osu.Game.Tests.Visual
public void JoinRoom(Room room, Action<Room> onSuccess = null, Action<string> onError = null) => throw new NotImplementedException();
public void PartRoom() => throw new NotImplementedException();
public void Filter(FilterCriteria criteria) => throw new NotImplementedException();
}
}
}
+4 -5
View File
@@ -3,7 +3,6 @@
using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Framework.Screens;
using osu.Game.Screens;
using osu.Game.Screens.Multi;
@@ -16,15 +15,15 @@ namespace osu.Game.Tests.Visual
{
int index = 0;
ScreenStack screenStack = new ScreenStack(new TestMultiplayerSubScreen(index)) { RelativeSizeAxes = Axes.Both };
OsuScreen currentScreen = new TestMultiplayerSubScreen(index);
Children = new Drawable[]
{
screenStack,
new Header(screenStack)
currentScreen,
new Header(currentScreen)
};
AddStep("push multi screen", () => screenStack.CurrentScreen.Push(new TestMultiplayerSubScreen(++index)));
AddStep("push multi screen", () => currentScreen.Push(currentScreen = new TestMultiplayerSubScreen(++index)));
}
private class TestMultiplayerSubScreen : OsuScreen, IMultiplayerSubScreen
+2 -3
View File
@@ -4,7 +4,6 @@
using System;
using System.Collections.Generic;
using NUnit.Framework;
using osu.Framework.Screens;
using osu.Game.Screens.Multi;
using osu.Game.Screens.Multi.Lounge;
using osu.Game.Screens.Multi.Lounge.Components;
@@ -12,7 +11,7 @@ using osu.Game.Screens.Multi.Lounge.Components;
namespace osu.Game.Tests.Visual
{
[TestFixture]
public class TestCaseMultiScreen : ScreenTestCase
public class TestCaseMultiScreen : OsuTestCase
{
public override IReadOnlyList<Type> RequiredTypes => new[]
{
@@ -25,7 +24,7 @@ namespace osu.Game.Tests.Visual
{
Multiplayer multi = new Multiplayer();
AddStep(@"show", () => LoadScreen(multi));
AddStep(@"show", () => Add(multi));
AddWaitStep(5);
AddStep(@"exit", multi.Exit);
}
+1 -5
View File
@@ -6,7 +6,6 @@ using System.Collections.Generic;
using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Screens;
using osu.Game.Screens;
using osu.Game.Screens.Menu;
using osuTK.Graphics;
@@ -30,10 +29,7 @@ namespace osu.Game.Tests.Visual
RelativeSizeAxes = Axes.Both,
Colour = Color4.Black,
},
new ScreenStack(new Loader())
{
RelativeSizeAxes = Axes.Both,
}
new Loader()
};
}
}
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Graphics;
using osu.Framework.Screens;
using osu.Game.Graphics.Containers;
using osu.Game.Screens.Backgrounds;
@@ -16,10 +14,7 @@ namespace osu.Game.Tests.Visual
Add(parallax = new ParallaxContainer
{
Child = new ScreenStack(new BackgroundScreenDefault { Alpha = 0.8f })
{
RelativeSizeAxes = Axes.Both,
}
Child = new BackgroundScreenDefault { Alpha = 0.8f }
});
AddStep("default parallax", () => parallax.ParallaxAmount = ParallaxContainer.DEFAULT_PARALLAX_AMOUNT);
+10 -17
View File
@@ -12,7 +12,6 @@ using osu.Framework.Configuration;
using osu.Framework.Extensions;
using osu.Framework.MathUtils;
using osu.Framework.Platform;
using osu.Framework.Screens;
using osu.Game.Beatmaps;
using osu.Game.Database;
using osu.Game.Rulesets;
@@ -26,7 +25,7 @@ using osu.Game.Screens.Select.Filter;
namespace osu.Game.Tests.Visual
{
[TestFixture]
public class TestCasePlaySongSelect : ScreenTestCase
public class TestCasePlaySongSelect : OsuTestCase
{
private BeatmapManager manager;
@@ -103,16 +102,21 @@ namespace osu.Game.Tests.Visual
}
[SetUp]
public virtual void SetUp() =>
Schedule(() => { manager?.Delete(manager.GetAllUsableBeatmapSets()); });
public virtual void SetUp()
{
Schedule(() =>
{
manager?.Delete(manager.GetAllUsableBeatmapSets());
Child = songSelect = new TestSongSelect();
});
}
[Test]
public void TestDummy()
{
createSongSelect();
AddAssert("dummy selected", () => songSelect.CurrentBeatmap == defaultBeatmap);
AddUntilStep(() => songSelect.CurrentBeatmapDetailsBeatmap == defaultBeatmap, "dummy shown on wedge");
AddAssert("dummy shown on wedge", () => songSelect.CurrentBeatmapDetailsBeatmap == defaultBeatmap);
addManyTestMaps();
AddWaitStep(3);
@@ -123,7 +127,6 @@ namespace osu.Game.Tests.Visual
[Test]
public void TestSorting()
{
createSongSelect();
addManyTestMaps();
AddWaitStep(3);
@@ -139,7 +142,6 @@ namespace osu.Game.Tests.Visual
[Ignore("needs fixing")]
public void TestImportUnderDifferentRuleset()
{
createSongSelect();
changeRuleset(2);
importForRuleset(0);
AddUntilStep(() => songSelect.Carousel.SelectedBeatmap == null, "no selection");
@@ -148,7 +150,6 @@ namespace osu.Game.Tests.Visual
[Test]
public void TestImportUnderCurrentRuleset()
{
createSongSelect();
changeRuleset(2);
importForRuleset(2);
importForRuleset(1);
@@ -164,7 +165,6 @@ namespace osu.Game.Tests.Visual
[Test]
public void TestRulesetChangeResetsMods()
{
createSongSelect();
changeRuleset(0);
changeMods(new OsuModHardRock());
@@ -194,7 +194,6 @@ namespace osu.Game.Tests.Visual
[Test]
public void TestStartAfterUnMatchingFilterDoesNotStart()
{
createSongSelect();
addManyTestMaps();
AddUntilStep(() => songSelect.Carousel.SelectedBeatmap != null, "has selection");
@@ -222,12 +221,6 @@ namespace osu.Game.Tests.Visual
private void changeRuleset(int id) => AddStep($"change ruleset to {id}", () => Ruleset.Value = rulesets.AvailableRulesets.First(r => r.ID == id));
private void createSongSelect()
{
AddStep("create song select", () => LoadScreen(songSelect = new TestSongSelect()));
AddUntilStep(() => songSelect.IsCurrentScreen(), "wait for present");
}
private void addManyTestMaps()
{
AddStep("import test maps", () =>
+4 -15
View File
@@ -3,8 +3,6 @@
using System.Threading;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Screens;
using osu.Game.Beatmaps;
using osu.Game.Screens.Play;
@@ -13,37 +11,28 @@ namespace osu.Game.Tests.Visual
public class TestCasePlayerLoader : ManualInputManagerTestCase
{
private PlayerLoader loader;
private ScreenStack stack;
[BackgroundDependencyLoader]
private void load(OsuGameBase game)
{
Beatmap.Value = new DummyWorkingBeatmap(game);
InputManager.Add(stack = new ScreenStack { RelativeSizeAxes = Axes.Both });
AddStep("load dummy beatmap", () => stack.Push(loader = new PlayerLoader(() => new Player
AddStep("load dummy beatmap", () => Add(loader = new PlayerLoader(() => new Player
{
AllowPause = false,
AllowLeadIn = false,
AllowResults = false,
})));
AddUntilStep(() => loader.IsCurrentScreen(), "wait for current");
AddStep("mouse in centre", () => InputManager.MoveMouseTo(loader.ScreenSpaceDrawQuad.Centre));
AddUntilStep(() => !loader.IsCurrentScreen(), "wait for no longer current");
AddStep("exit loader", () => loader.Exit());
AddUntilStep(() => !loader.IsAlive, "wait for no longer alive");
AddUntilStep(() => !loader.IsCurrentScreen, "wait for no longer current");
AddStep("load slow dummy beatmap", () =>
{
SlowLoadPlayer slow = null;
stack.Push(loader = new PlayerLoader(() => slow = new SlowLoadPlayer
Add(loader = new PlayerLoader(() => slow = new SlowLoadPlayer
{
AllowPause = false,
AllowLeadIn = false,
@@ -53,7 +42,7 @@ namespace osu.Game.Tests.Visual
Scheduler.AddDelayed(() => slow.Ready = true, 5000);
});
AddUntilStep(() => !loader.IsCurrentScreen(), "wait for no longer current");
AddUntilStep(() => !loader.IsCurrentScreen, "wait for no longer current");
}
protected class SlowLoadPlayer : Player
+2 -2
View File
@@ -16,7 +16,7 @@ using osu.Game.Users;
namespace osu.Game.Tests.Visual
{
[TestFixture]
public class TestCaseResults : ScreenTestCase
public class TestCaseResults : OsuTestCase
{
private BeatmapManager beatmaps;
@@ -43,7 +43,7 @@ namespace osu.Game.Tests.Visual
if (beatmapInfo != null)
Beatmap.Value = beatmaps.GetWorkingBeatmap(beatmapInfo);
LoadScreen(new SoloResults(new ScoreInfo
Add(new SoloResults(new ScoreInfo
{
TotalScore = 2845370,
Accuracy = 0.98,
@@ -19,18 +19,16 @@ namespace osu.Game.Tests.Visual
public class TestCaseScreenBreadcrumbControl : OsuTestCase
{
private readonly ScreenBreadcrumbControl breadcrumbs;
private readonly ScreenStack screenStack;
private Screen currentScreen, changedScreen;
public TestCaseScreenBreadcrumbControl()
{
TestScreen startScreen;
OsuSpriteText titleText;
IScreen startScreen = new TestScreenOne();
screenStack = new ScreenStack(startScreen) { RelativeSizeAxes = Axes.Both };
Children = new Drawable[]
{
screenStack,
currentScreen = startScreen = new TestScreenOne(),
new FillFlowContainer
{
RelativeSizeAxes = Axes.X,
@@ -39,7 +37,7 @@ namespace osu.Game.Tests.Visual
Spacing = new Vector2(10),
Children = new Drawable[]
{
breadcrumbs = new ScreenBreadcrumbControl(screenStack)
breadcrumbs = new ScreenBreadcrumbControl(startScreen)
{
RelativeSizeAxes = Axes.X,
},
@@ -48,7 +46,12 @@ namespace osu.Game.Tests.Visual
},
};
breadcrumbs.Current.ValueChanged += s => titleText.Text = $"Changed to {s.ToString()}";
breadcrumbs.Current.ValueChanged += s =>
{
titleText.Text = $"Changed to {s.ToString()}";
changedScreen = s;
};
breadcrumbs.Current.TriggerChange();
waitForCurrent();
@@ -57,14 +60,18 @@ namespace osu.Game.Tests.Visual
pushNext();
waitForCurrent();
AddStep(@"make start current", () => startScreen.MakeCurrent());
AddStep(@"make start current", () =>
{
startScreen.MakeCurrent();
currentScreen = startScreen;
});
waitForCurrent();
pushNext();
waitForCurrent();
AddAssert(@"only 2 items", () => breadcrumbs.Items.Count() == 2);
AddStep(@"exit current", () => screenStack.CurrentScreen.Exit());
AddAssert(@"current screen is first", () => startScreen == screenStack.CurrentScreen);
AddStep(@"exit current", () => changedScreen.Exit());
AddAssert(@"current screen is first", () => startScreen == changedScreen);
}
[BackgroundDependencyLoader]
@@ -73,8 +80,8 @@ namespace osu.Game.Tests.Visual
breadcrumbs.StripColour = colours.Blue;
}
private void pushNext() => AddStep(@"push next screen", () => ((TestScreen)screenStack.CurrentScreen).PushNext());
private void waitForCurrent() => AddUntilStep(() => screenStack.CurrentScreen.IsCurrentScreen(), "current screen");
private void pushNext() => AddStep(@"push next screen", () => currentScreen = ((TestScreen)currentScreen).PushNext());
private void waitForCurrent() => AddUntilStep(() => currentScreen.IsCurrentScreen, "current screen");
private abstract class TestScreen : OsuScreen
{
@@ -84,14 +91,14 @@ namespace osu.Game.Tests.Visual
public TestScreen PushNext()
{
TestScreen screen = CreateNextScreen();
this.Push(screen);
Push(screen);
return screen;
}
protected TestScreen()
{
InternalChild = new FillFlowContainer
Child = new FillFlowContainer
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
+2 -1
View File
@@ -10,6 +10,7 @@ using osu.Framework.Graphics.Audio;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics.Sprites;
using osu.Framework.Audio;
namespace osu.Game.Tests.Visual
{
@@ -17,7 +18,7 @@ namespace osu.Game.Tests.Visual
public class TestCaseWaveform : OsuTestCase
{
[BackgroundDependencyLoader]
private void load()
private void load(AudioManager audioManager)
{
Beatmap.Value = new WaveformTestBeatmap();
+3 -3
View File
@@ -8,7 +8,7 @@ using osu.Framework.Graphics.Textures;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Formats;
using osu.Game.IO.Archives;
using osu.Game.Tests.Resources;
using osu.Game.Tests.Beatmaps.IO;
namespace osu.Game.Tests
{
@@ -18,12 +18,12 @@ namespace osu.Game.Tests
public class WaveformTestBeatmap : WorkingBeatmap
{
private readonly ZipArchiveReader reader;
private readonly Stream stream;
private readonly FileStream stream;
public WaveformTestBeatmap()
: base(new BeatmapInfo())
{
stream = TestResources.GetTestBeatmapStream();
stream = File.OpenRead(ImportBeatmapTest.TEST_OSZ_PATH);
reader = new ZipArchiveReader(stream);
}
+9 -5
View File
@@ -78,14 +78,14 @@ namespace osu.Game.Beatmaps
private readonly List<DownloadBeatmapSetRequest> currentDownloads = new List<DownloadBeatmapSetRequest>();
public BeatmapManager(Storage storage, IDatabaseContextFactory contextFactory, RulesetStore rulesets, APIAccess api, AudioManager audioManager, GameHost host = null,
public BeatmapManager(Storage storage, IDatabaseContextFactory contextFactory, RulesetStore rulesets, APIAccess api, AudioManager audioManager, GameHost importHost = null,
WorkingBeatmap defaultBeatmap = null)
: base(storage, contextFactory, new BeatmapStore(contextFactory), host)
: base(storage, contextFactory, new BeatmapStore(contextFactory), importHost)
{
this.rulesets = rulesets;
this.api = api;
this.audioManager = audioManager;
this.host = host;
host = importHost;
DefaultBeatmap = defaultBeatmap;
@@ -163,14 +163,18 @@ namespace osu.Game.Beatmaps
downloadNotification.Progress = progress;
};
request.Success += filename =>
request.Success += data =>
{
downloadNotification.Text = $"Importing {beatmapSetInfo.Metadata.Artist} - {beatmapSetInfo.Metadata.Title}";
Task.Factory.StartNew(() =>
{
BeatmapSetInfo importedBeatmap;
// This gets scheduled back to the update thread, but we want the import to run in the background.
var importedBeatmap = Import(filename);
using (var stream = new MemoryStream(data))
using (var archive = new ZipArchiveReader(stream, beatmapSetInfo.ToString()))
importedBeatmap = Import(archive);
downloadNotification.CompletionClickAction = () =>
{
+5 -2
View File
@@ -12,9 +12,9 @@ namespace osu.Game.Beatmaps
{
/// <summary>
/// A <see cref="Bindable{WorkingBeatmap}"/> for the <see cref="OsuGame"/> beatmap.
/// This should be used sparingly in-favour of <see cref="IBindable<WorkingBeatmap>"/>.
/// This should be used sparingly in-favour of <see cref="IBindableBeatmap"/>.
/// </summary>
public abstract class BindableBeatmap : NonNullableBindable<WorkingBeatmap>
public abstract class BindableBeatmap : NonNullableBindable<WorkingBeatmap>, IBindableBeatmap
{
private AudioManager audioManager;
private WorkingBeatmap lastBeatmap;
@@ -62,6 +62,9 @@ namespace osu.Game.Beatmaps
lastBeatmap = beatmap;
}
[NotNull]
IBindableBeatmap IBindableBeatmap.GetBoundCopy() => GetBoundCopy();
/// <summary>
/// Retrieve a new <see cref="BindableBeatmap"/> instance weakly bound to this <see cref="BindableBeatmap"/>.
/// If you are further binding to events of the retrieved <see cref="BindableBeatmap"/>, ensure a local reference is held.
@@ -0,0 +1,112 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Configuration;
using osu.Framework.Graphics;
using osu.Game.Online.API.Requests;
namespace osu.Game.Beatmaps.Drawables
{
/// <summary>
/// A component to allow downloading of a beatmap set. Automatically handles state syncing between other instances.
/// </summary>
public class BeatmapSetDownloader : Component
{
private readonly BeatmapSetInfo set;
private readonly bool noVideo;
private BeatmapManager beatmaps;
/// <summary>
/// Holds the current download state of the beatmap, whether is has already been downloaded, is in progress, or is not downloaded.
/// </summary>
public readonly Bindable<DownloadStatus> DownloadState = new Bindable<DownloadStatus>();
public BeatmapSetDownloader(BeatmapSetInfo set, bool noVideo = false)
{
this.set = set;
this.noVideo = noVideo;
}
[BackgroundDependencyLoader]
private void load(BeatmapManager beatmaps)
{
this.beatmaps = beatmaps;
beatmaps.ItemAdded += setAdded;
beatmaps.ItemRemoved += setRemoved;
beatmaps.BeatmapDownloadBegan += downloadBegan;
beatmaps.BeatmapDownloadFailed += downloadFailed;
// initial value
if (set.OnlineBeatmapSetID != null && beatmaps.QueryBeatmapSets(s => s.OnlineBeatmapSetID == set.OnlineBeatmapSetID && !s.DeletePending).Any())
DownloadState.Value = DownloadStatus.Downloaded;
else if (beatmaps.GetExistingDownload(set) != null)
DownloadState.Value = DownloadStatus.Downloading;
else
DownloadState.Value = DownloadStatus.NotDownloaded;
}
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
if (beatmaps != null)
{
beatmaps.ItemAdded -= setAdded;
beatmaps.ItemRemoved -= setRemoved;
beatmaps.BeatmapDownloadBegan -= downloadBegan;
beatmaps.BeatmapDownloadFailed -= downloadFailed;
}
}
/// <summary>
/// Begin downloading the associated beatmap set.
/// </summary>
/// <returns>True if downloading began. False if an existing download is active or completed.</returns>
public void Download()
{
if (DownloadState.Value > DownloadStatus.NotDownloaded)
return;
if (beatmaps.Download(set, noVideo))
{
// Only change state if download can happen
DownloadState.Value = DownloadStatus.Downloading;
}
}
private void setAdded(BeatmapSetInfo s, bool existing, bool silent) => Schedule(() =>
{
if (s.OnlineBeatmapSetID == set.OnlineBeatmapSetID)
DownloadState.Value = DownloadStatus.Downloaded;
});
private void setRemoved(BeatmapSetInfo s) => Schedule(() =>
{
if (s.OnlineBeatmapSetID == set.OnlineBeatmapSetID)
DownloadState.Value = DownloadStatus.NotDownloaded;
});
private void downloadBegan(DownloadBeatmapSetRequest d)
{
if (d.BeatmapSet.OnlineBeatmapSetID == set.OnlineBeatmapSetID)
DownloadState.Value = DownloadStatus.Downloading;
}
private void downloadFailed(DownloadBeatmapSetRequest d)
{
if (d.BeatmapSet.OnlineBeatmapSetID == set.OnlineBeatmapSetID)
DownloadState.Value = DownloadStatus.NotDownloaded;
}
public enum DownloadStatus
{
NotDownloaded,
Downloading,
Downloaded,
}
}
}
@@ -13,7 +13,7 @@ namespace osu.Game.Beatmaps.Drawables
/// </summary>
public class UpdateableBeatmapBackgroundSprite : ModelBackedDrawable<BeatmapInfo>
{
public readonly Bindable<BeatmapInfo> Beatmap = new Bindable<BeatmapInfo>();
public readonly IBindable<BeatmapInfo> Beatmap = new Bindable<BeatmapInfo>();
[Resolved]
private BeatmapManager beatmaps { get; set; }
+19
View File
@@ -0,0 +1,19 @@
// 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.Configuration;
namespace osu.Game.Beatmaps
{
/// <summary>
/// Read-only interface for the <see cref="OsuGame"/> beatmap.
/// </summary>
public interface IBindableBeatmap : IBindable<WorkingBeatmap>
{
/// <summary>
/// Retrieve a new <see cref="IBindableBeatmap"/> instance weakly bound to this <see cref="IBindableBeatmap"/>.
/// If you are further binding to events of the retrieved <see cref="IBindableBeatmap"/>, ensure a local reference is held.
/// </summary>
IBindableBeatmap GetBoundCopy();
}
}
+17 -29
View File
@@ -150,9 +150,25 @@ namespace osu.Game.Database
{
notification.Text = $"Importing ({++current} of {paths.Length})\n{Path.GetFileName(path)}";
imported.Add(Import(path));
TModel import;
using (ArchiveReader reader = getReaderFrom(path))
imported.Add(import = Import(reader));
notification.Progress = (float)current / paths.Length;
// We may or may not want to delete the file depending on where it is stored.
// e.g. reconstructing/repairing database with items from default storage.
// Also, not always a single file, i.e. for LegacyFilesystemReader
// TODO: Add a check to prevent files from storage to be deleted.
try
{
if (import != null && File.Exists(path))
File.Delete(path);
}
catch (Exception e)
{
Logger.Error(e, $@"Could not delete original file after import ({Path.GetFileName(path)})");
}
}
catch (Exception e)
{
@@ -179,34 +195,6 @@ namespace osu.Game.Database
}
}
/// <summary>
/// Import one <see cref="TModel"/> from the filesystem and delete the file on success.
/// </summary>
/// <param name="path">The archive location on disk.</param>
/// <returns>The imported model, if successful.</returns>
public TModel Import(string path)
{
TModel import;
using (ArchiveReader reader = getReaderFrom(path))
import = Import(reader);
// We may or may not want to delete the file depending on where it is stored.
// e.g. reconstructing/repairing database with items from default storage.
// Also, not always a single file, i.e. for LegacyFilesystemReader
// TODO: Add a check to prevent files from storage to be deleted.
try
{
if (import != null && File.Exists(path))
File.Delete(path);
}
catch (Exception e)
{
Logger.Error(e, $@"Could not delete original file after import ({Path.GetFileName(path)})");
}
return import;
}
protected virtual void PresentCompletedImport(IEnumerable<TModel> imported)
{
}
@@ -74,7 +74,7 @@ namespace osu.Game.Graphics.Containers
}
[BackgroundDependencyLoader]
private void load(IBindable<WorkingBeatmap> beatmap)
private void load(IBindableBeatmap beatmap)
{
Beatmap.BindTo(beatmap);
}
@@ -50,7 +50,6 @@ namespace osu.Game.Graphics.Cursor
if (!CanShowCursor)
{
currentTarget?.Cursor?.Hide();
currentTarget = null;
return;
}
@@ -3,9 +3,7 @@
using osuTK.Graphics;
using System;
using osu.Framework.Allocation;
using osu.Framework.Input.Events;
using osu.Framework.Platform;
using osu.Game.Input.Bindings;
using osuTK.Input;
@@ -23,16 +21,9 @@ namespace osu.Game.Graphics.UserInterface
private bool focus;
private bool allowImmediateFocus => host?.OnScreenKeyboardOverlapsGameWindow != true;
public void TakeFocus()
{
if (allowImmediateFocus) GetContainingInputManager().ChangeFocus(this);
}
public bool HoldFocus
{
get => allowImmediateFocus && focus;
get => false;
set
{
focus = value;
@@ -41,14 +32,6 @@ namespace osu.Game.Graphics.UserInterface
}
}
private GameHost host;
[BackgroundDependencyLoader]
private void load(GameHost host)
{
this.host = host;
}
// We may not be focused yet, but we need to handle keyboard input to be able to request focus
public override bool HandleNonPositionalInput => HoldFocus || base.HandleNonPositionalInput;
@@ -88,6 +71,6 @@ namespace osu.Game.Graphics.UserInterface
Exit?.Invoke();
}
public override bool RequestsFocus => HoldFocus;
public override bool RequestsFocus => false;
}
}
@@ -9,13 +9,12 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Input;
using osu.Framework.Input.Events;
using osu.Framework.Platform;
namespace osu.Game.Graphics.UserInterface
{
public class OsuPasswordTextBox : OsuTextBox, ISuppressKeyEventLogging
public class OsuPasswordTextBox : OsuTextBox
{
protected override Drawable GetDrawableCharacter(char c) => new PasswordMaskChar(CalculatedTextSize);
@@ -10,30 +10,45 @@ namespace osu.Game.Graphics.UserInterface
/// <summary>
/// A <see cref="BreadcrumbControl"/> which follows the active screen (and allows navigation) in a <see cref="Screen"/> stack.
/// </summary>
public class ScreenBreadcrumbControl : BreadcrumbControl<IScreen>
public class ScreenBreadcrumbControl : BreadcrumbControl<Screen>
{
public ScreenBreadcrumbControl(ScreenStack stack)
private Screen last;
public ScreenBreadcrumbControl(Screen initialScreen)
{
stack.ScreenPushed += onPushed;
stack.ScreenExited += onExited;
Current.ValueChanged += newScreen =>
{
if (last != newScreen && !newScreen.IsCurrentScreen)
newScreen.MakeCurrent();
};
onPushed(null, stack.CurrentScreen);
Current.ValueChanged += newScreen => newScreen.MakeCurrent();
onPushed(initialScreen);
}
private void onPushed(IScreen lastScreen, IScreen newScreen)
private void screenChanged(Screen newScreen)
{
AddItem(newScreen);
if (newScreen == null) return;
if (last != null)
{
last.Exited -= screenChanged;
last.ModePushed -= onPushed;
}
last = newScreen;
newScreen.Exited += screenChanged;
newScreen.ModePushed += onPushed;
Current.Value = newScreen;
}
private void onExited(IScreen lastScreen, IScreen newScreen)
private void onPushed(Screen screen)
{
if (newScreen != null)
Current.Value = newScreen;
Items.ToList().SkipWhile(i => i != Current.Value).Skip(1).ForEach(RemoveItem);
AddItem(screen);
Items.ToList().SkipWhile(s => s != Current.Value).Skip(1).ForEach(RemoveItem);
screenChanged(screen);
}
}
}
@@ -17,6 +17,7 @@ namespace osu.Game.Graphics.UserInterface
public SearchTextBox()
{
Height = 35;
AddRange(new Drawable[]
{
new SpriteIcon
+7 -12
View File
@@ -190,8 +190,8 @@ namespace osu.Game.Online.API
{
Debug.Assert(State == APIState.Offline);
ProvidedUsername = username;
this.password = password;
ProvidedUsername = username.Trim();
this.password = password.Trim();
}
public RegistrationRequest.RegistrationRequestErrors CreateAccount(string email, string username, string password)
@@ -355,7 +355,11 @@ namespace osu.Game.Online.API
State = APIState.Offline;
}
private static User createGuestUser() => new GuestUser();
private static User createGuestUser() => new User
{
Username = @"Guest",
Id = 1,
};
protected override void Dispose(bool isDisposing)
{
@@ -366,15 +370,6 @@ namespace osu.Game.Online.API
}
}
internal class GuestUser : User
{
public GuestUser()
{
Username = @"Guest";
Id = 1;
}
}
public enum APIState
{
/// <summary>
+5 -8
View File
@@ -1,23 +1,20 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System.IO;
using osu.Framework.IO.Network;
namespace osu.Game.Online.API
{
public abstract class APIDownloadRequest : APIRequest
{
private string filename;
protected override WebRequest CreateWebRequest()
{
var request = new FileWebRequest(filename = Path.GetTempFileName(), Uri);
var request = new WebRequest(Uri);
request.DownloadProgress += request_Progress;
return request;
}
private void request_Progress(long current, long total) => API.Schedule(() => Progressed?.Invoke(current, total));
private void request_Progress(long current, long total) => API.Schedule(() => Progress?.Invoke(current, total));
protected APIDownloadRequest()
{
@@ -26,11 +23,11 @@ namespace osu.Game.Online.API
private void onSuccess()
{
Success?.Invoke(filename);
Success?.Invoke(WebRequest.ResponseData);
}
public event APIProgressHandler Progressed;
public event APIProgressHandler Progress;
public new event APISuccessHandler<string> Success;
public new event APISuccessHandler<byte[]> Success;
}
}
@@ -10,9 +10,7 @@ namespace osu.Game.Online.API.Requests
{
public readonly BeatmapSetInfo BeatmapSet;
public float Progress;
public event Action<float> DownloadProgressed;
public Action<float> DownloadProgressed;
private readonly bool noVideo;
@@ -21,7 +19,7 @@ namespace osu.Game.Online.API.Requests
this.noVideo = noVideo;
BeatmapSet = set;
Progressed += (current, total) => DownloadProgressed?.Invoke(Progress = (float)current / total);
Progress += (current, total) => DownloadProgressed?.Invoke((float) current / total);
}
protected override string Target => $@"beatmapsets/{BeatmapSet.OnlineBeatmapSetID}/download{(noVideo ? "?noVideo=1" : "")}";
+3 -3
View File
@@ -1,9 +1,9 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using osu.Framework.Configuration;
using osu.Game.Beatmaps;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Rulesets;
@@ -37,10 +37,10 @@ namespace osu.Game.Online.Multiplayer
public RulesetInfo Ruleset { get; set; }
[JsonIgnore]
public readonly List<Mod> AllowedMods = new List<Mod>();
public readonly BindableList<Mod> AllowedMods = new BindableList<Mod>();
[JsonIgnore]
public readonly List<Mod> RequiredMods = new List<Mod>();
public readonly BindableList<Mod> RequiredMods = new BindableList<Mod>();
[JsonProperty("beatmap")]
private APIBeatmap apiBeatmap { get; set; }

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