mirror of
https://github.com/ppy/osu.git
synced 2024-11-11 17:47:29 +08:00
Merge https://github.com/ppy/osu into multiplayer-match
This commit is contained in:
commit
9989517ff0
12
.vscode/launch.json
vendored
12
.vscode/launch.json
vendored
@ -22,7 +22,7 @@
|
|||||||
},
|
},
|
||||||
"type": "mono",
|
"type": "mono",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"program": "${workspaceRoot}/osu.Game.Tests/bin/Debug/net471/osu.Game.Tests.exe",
|
"program": "${workspaceRoot}/osu.Game.Tests/bin/Release/net471/osu.Game.Tests.exe",
|
||||||
"cwd": "${workspaceRoot}",
|
"cwd": "${workspaceRoot}",
|
||||||
"preLaunchTask": "Build (Release, msbuild)",
|
"preLaunchTask": "Build (Release, msbuild)",
|
||||||
"runtimeExecutable": null,
|
"runtimeExecutable": null,
|
||||||
@ -66,7 +66,7 @@
|
|||||||
"${workspaceRoot}/osu.Game.Tests/bin/Debug/netcoreapp2.0/osu.Game.Tests.dll"
|
"${workspaceRoot}/osu.Game.Tests/bin/Debug/netcoreapp2.0/osu.Game.Tests.dll"
|
||||||
],
|
],
|
||||||
"cwd": "${workspaceRoot}",
|
"cwd": "${workspaceRoot}",
|
||||||
"preLaunchTask": "Build (Debug, dotnet)",
|
"preLaunchTask": "Build tests (Debug, dotnet)",
|
||||||
"env": {},
|
"env": {},
|
||||||
"console": "internalConsole"
|
"console": "internalConsole"
|
||||||
},
|
},
|
||||||
@ -76,10 +76,10 @@
|
|||||||
"request": "launch",
|
"request": "launch",
|
||||||
"program": "dotnet",
|
"program": "dotnet",
|
||||||
"args": [
|
"args": [
|
||||||
"${workspaceRoot}/osu.Game.Tests/bin/Debug/netcoreapp2.0/osu.Game.Tests.dll"
|
"${workspaceRoot}/osu.Game.Tests/bin/Release/netcoreapp2.0/osu.Game.Tests.dll"
|
||||||
],
|
],
|
||||||
"cwd": "${workspaceRoot}",
|
"cwd": "${workspaceRoot}",
|
||||||
"preLaunchTask": "Build (Release, dotnet)",
|
"preLaunchTask": "Build tests (Release, dotnet)",
|
||||||
"env": {},
|
"env": {},
|
||||||
"console": "internalConsole"
|
"console": "internalConsole"
|
||||||
},
|
},
|
||||||
@ -92,7 +92,7 @@
|
|||||||
"${workspaceRoot}/osu.Desktop/bin/Debug/netcoreapp2.0/osu!.dll",
|
"${workspaceRoot}/osu.Desktop/bin/Debug/netcoreapp2.0/osu!.dll",
|
||||||
],
|
],
|
||||||
"cwd": "${workspaceRoot}",
|
"cwd": "${workspaceRoot}",
|
||||||
"preLaunchTask": "Build (Debug, dotnet)",
|
"preLaunchTask": "Build osu! (Debug, dotnet)",
|
||||||
"env": {},
|
"env": {},
|
||||||
"console": "internalConsole"
|
"console": "internalConsole"
|
||||||
},
|
},
|
||||||
@ -105,7 +105,7 @@
|
|||||||
"${workspaceRoot}/osu.Desktop/bin/Release/netcoreapp2.0/osu!.dll",
|
"${workspaceRoot}/osu.Desktop/bin/Release/netcoreapp2.0/osu!.dll",
|
||||||
],
|
],
|
||||||
"cwd": "${workspaceRoot}",
|
"cwd": "${workspaceRoot}",
|
||||||
"preLaunchTask": "Build (Release, dotnet)",
|
"preLaunchTask": "Build osu! (Release, dotnet)",
|
||||||
"env": {},
|
"env": {},
|
||||||
"console": "internalConsole"
|
"console": "internalConsole"
|
||||||
}
|
}
|
||||||
|
37
.vscode/tasks.json
vendored
37
.vscode/tasks.json
vendored
@ -31,7 +31,7 @@
|
|||||||
"problemMatcher": "$msCompile"
|
"problemMatcher": "$msCompile"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": "Build (Debug, dotnet)",
|
"label": "Build osu! (Debug, dotnet)",
|
||||||
"type": "shell",
|
"type": "shell",
|
||||||
"command": "dotnet",
|
"command": "dotnet",
|
||||||
"args": [
|
"args": [
|
||||||
@ -47,7 +47,7 @@
|
|||||||
"problemMatcher": "$msCompile"
|
"problemMatcher": "$msCompile"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": "Build (Release, dotnet)",
|
"label": "Build osu! (Release, dotnet)",
|
||||||
"type": "shell",
|
"type": "shell",
|
||||||
"command": "dotnet",
|
"command": "dotnet",
|
||||||
"args": [
|
"args": [
|
||||||
@ -63,6 +63,39 @@
|
|||||||
"group": "build",
|
"group": "build",
|
||||||
"problemMatcher": "$msCompile"
|
"problemMatcher": "$msCompile"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"label": "Build tests (Debug, dotnet)",
|
||||||
|
"type": "shell",
|
||||||
|
"command": "dotnet",
|
||||||
|
"args": [
|
||||||
|
"build",
|
||||||
|
"--no-restore",
|
||||||
|
"osu.Game.Tests",
|
||||||
|
"/p:TargetFramework=netcoreapp2.0",
|
||||||
|
"/p:GenerateFullPaths=true",
|
||||||
|
"/m",
|
||||||
|
"/verbosity:m"
|
||||||
|
],
|
||||||
|
"group": "build",
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Build tests (Release, dotnet)",
|
||||||
|
"type": "shell",
|
||||||
|
"command": "dotnet",
|
||||||
|
"args": [
|
||||||
|
"build",
|
||||||
|
"--no-restore",
|
||||||
|
"osu.Game.Tests",
|
||||||
|
"/p:TargetFramework=netcoreapp2.0",
|
||||||
|
"/p:Configuration=Release",
|
||||||
|
"/p:GenerateFullPaths=true",
|
||||||
|
"/m",
|
||||||
|
"/verbosity:m"
|
||||||
|
],
|
||||||
|
"group": "build",
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"label": "Restore (net471)",
|
"label": "Restore (net471)",
|
||||||
"type": "shell",
|
"type": "shell",
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit 84fdfc77a86d581638e69f5e8061c118de4b30f9
|
Subproject commit aebfa5bc5c634c1fd0c103e0c17518e5111a67c7
|
@ -12,6 +12,7 @@ using osu.Framework.Platform;
|
|||||||
using osu.Game;
|
using osu.Game;
|
||||||
using OpenTK.Input;
|
using OpenTK.Input;
|
||||||
using Microsoft.Win32;
|
using Microsoft.Win32;
|
||||||
|
using osu.Framework.Platform.Windows;
|
||||||
|
|
||||||
namespace osu.Desktop
|
namespace osu.Desktop
|
||||||
{
|
{
|
||||||
@ -40,7 +41,7 @@ namespace osu.Desktop
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// A method of accessing an osu-stable install in a controlled fashion.
|
/// A method of accessing an osu-stable install in a controlled fashion.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private class StableStorage : DesktopStorage
|
private class StableStorage : WindowsStorage
|
||||||
{
|
{
|
||||||
protected override string LocateBasePath()
|
protected override string LocateBasePath()
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<Import Project="..\osu.Game.props" />
|
<Import Project="..\osu.Game.props" />
|
||||||
<PropertyGroup Label="Project">
|
<PropertyGroup Label="Project">
|
||||||
<TargetFrameworks>net471;netcoreapp2.0</TargetFrameworks>
|
<TargetFrameworks>net471;netcoreapp2.0</TargetFrameworks>
|
||||||
@ -20,6 +20,8 @@
|
|||||||
<StartupObject>osu.Desktop.Program</StartupObject>
|
<StartupObject>osu.Desktop.Program</StartupObject>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup Label="Project References">
|
<ItemGroup Label="Project References">
|
||||||
|
<!-- This can be removed after .NET Core SDK version 2.1.300; see https://docs.microsoft.com/en-us/ef/core/miscellaneous/cli/dotnet -->
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="2.0.3" />
|
||||||
<ProjectReference Include="..\osu-framework\osu.Framework\osu.Framework.csproj" />
|
<ProjectReference Include="..\osu-framework\osu.Framework\osu.Framework.csproj" />
|
||||||
<ProjectReference Include="..\osu.Game\osu.Game.csproj" />
|
<ProjectReference Include="..\osu.Game\osu.Game.csproj" />
|
||||||
<ProjectReference Include="..\osu.Game.Rulesets.Osu\osu.Game.Rulesets.Osu.csproj" />
|
<ProjectReference Include="..\osu.Game.Rulesets.Osu\osu.Game.Rulesets.Osu.csproj" />
|
||||||
@ -30,10 +32,14 @@
|
|||||||
<PackageReference Include="Microsoft.Win32.Registry" Version="4.4.0" />
|
<PackageReference Include="Microsoft.Win32.Registry" Version="4.4.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup Label="Package References">
|
<ItemGroup Label="Package References">
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.0.1" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.0.3" />
|
||||||
<PackageReference Include="squirrel.windows" Version="1.8.0" Condition="'$(TargetFramework)' == 'net471'" />
|
<PackageReference Include="squirrel.windows" Version="1.8.0" Condition="'$(TargetFramework)' == 'net471'" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup Label="Resources">
|
<ItemGroup Label="Resources">
|
||||||
<EmbeddedResource Include="lazer.ico" />
|
<EmbeddedResource Include="lazer.ico" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
<ItemGroup>
|
||||||
|
<!-- This can be removed after .NET Core SDK version 2.1.300; see https://docs.microsoft.com/en-us/ef/core/miscellaneous/cli/dotnet -->
|
||||||
|
<DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="2.0.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
@ -37,7 +37,7 @@ namespace osu.Game.Rulesets.Catch.Tests
|
|||||||
Child = catcherArea = new TestCatcherArea(new BeatmapDifficulty { CircleSize = size })
|
Child = catcherArea = new TestCatcherArea(new BeatmapDifficulty { CircleSize = size })
|
||||||
{
|
{
|
||||||
Anchor = Anchor.CentreLeft,
|
Anchor = Anchor.CentreLeft,
|
||||||
Origin = Anchor.BottomLeft
|
Origin = Anchor.TopLeft
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@ namespace osu.Game.Rulesets.Catch.Tests
|
|||||||
typeof(DrawableCatchHitObject),
|
typeof(DrawableCatchHitObject),
|
||||||
typeof(DrawableFruit),
|
typeof(DrawableFruit),
|
||||||
typeof(DrawableDroplet),
|
typeof(DrawableDroplet),
|
||||||
|
typeof(BananaShower),
|
||||||
typeof(Pulp),
|
typeof(Pulp),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -53,12 +54,19 @@ namespace osu.Game.Rulesets.Catch.Tests
|
|||||||
|
|
||||||
private DrawableFruit createDrawable(int index)
|
private DrawableFruit createDrawable(int index)
|
||||||
{
|
{
|
||||||
var fruit = new Fruit
|
Fruit fruit = index == 5
|
||||||
{
|
? new BananaShower.Banana
|
||||||
StartTime = 1000000000000,
|
{
|
||||||
IndexInBeatmap = index,
|
StartTime = 1000000000000,
|
||||||
Scale = 1.5f,
|
IndexInBeatmap = index,
|
||||||
};
|
Scale = 1.5f,
|
||||||
|
}
|
||||||
|
: new Fruit
|
||||||
|
{
|
||||||
|
StartTime = 1000000000000,
|
||||||
|
IndexInBeatmap = index,
|
||||||
|
Scale = 1.5f,
|
||||||
|
};
|
||||||
|
|
||||||
return new DrawableFruit(fruit)
|
return new DrawableFruit(fruit)
|
||||||
{
|
{
|
||||||
|
@ -18,12 +18,19 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
|||||||
{
|
{
|
||||||
private Circle border;
|
private Circle border;
|
||||||
|
|
||||||
|
private const float drawable_radius = (float)CatchHitObject.OBJECT_RADIUS * radius_adjust;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Because we're adding a border around the fruit, we need to scale down some.
|
||||||
|
/// </summary>
|
||||||
|
private const float radius_adjust = 1.1f;
|
||||||
|
|
||||||
public DrawableFruit(Fruit h)
|
public DrawableFruit(Fruit h)
|
||||||
: base(h)
|
: base(h)
|
||||||
{
|
{
|
||||||
Origin = Anchor.Centre;
|
Origin = Anchor.Centre;
|
||||||
|
|
||||||
Size = new Vector2((float)CatchHitObject.OBJECT_RADIUS);
|
Size = new Vector2(drawable_radius);
|
||||||
Masking = false;
|
Masking = false;
|
||||||
|
|
||||||
Rotation = (float)(RNG.NextDouble() - 0.5f) * 40;
|
Rotation = (float)(RNG.NextDouble() - 0.5f) * 40;
|
||||||
@ -44,14 +51,14 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
|||||||
{
|
{
|
||||||
Hollow = !HitObject.HyperDash,
|
Hollow = !HitObject.HyperDash,
|
||||||
Type = EdgeEffectType.Glow,
|
Type = EdgeEffectType.Glow,
|
||||||
Radius = 4,
|
Radius = 4 * radius_adjust,
|
||||||
Colour = HitObject.HyperDash ? Color4.Red : AccentColour.Darken(1).Opacity(0.6f)
|
Colour = HitObject.HyperDash ? Color4.Red : AccentColour.Darken(1).Opacity(0.6f)
|
||||||
},
|
},
|
||||||
Size = new Vector2(Height * 1.5f),
|
Size = new Vector2(Height),
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
BorderColour = Color4.White,
|
BorderColour = Color4.White,
|
||||||
BorderThickness = 4f,
|
BorderThickness = 3f * radius_adjust,
|
||||||
Children = new Framework.Graphics.Drawable[]
|
Children = new Framework.Graphics.Drawable[]
|
||||||
{
|
{
|
||||||
new Box
|
new Box
|
||||||
@ -82,8 +89,8 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
|||||||
|
|
||||||
private Framework.Graphics.Drawable createPulp(FruitVisualRepresentation representation)
|
private Framework.Graphics.Drawable createPulp(FruitVisualRepresentation representation)
|
||||||
{
|
{
|
||||||
const float large_pulp_3 = 13f;
|
const float large_pulp_3 = 8f * radius_adjust;
|
||||||
const float distance_from_centre_3 = 0.23f;
|
const float distance_from_centre_3 = 0.15f;
|
||||||
|
|
||||||
const float large_pulp_4 = large_pulp_3 * 0.925f;
|
const float large_pulp_4 = large_pulp_3 * 0.925f;
|
||||||
const float distance_from_centre_4 = distance_from_centre_3 / 0.925f;
|
const float distance_from_centre_4 = distance_from_centre_3 / 0.925f;
|
||||||
@ -106,11 +113,9 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
|||||||
{
|
{
|
||||||
new Pulp
|
new Pulp
|
||||||
{
|
{
|
||||||
Anchor = Anchor.TopCentre,
|
|
||||||
Origin = Anchor.BottomCentre,
|
|
||||||
AccentColour = AccentColour,
|
AccentColour = AccentColour,
|
||||||
Size = new Vector2(small_pulp),
|
Size = new Vector2(small_pulp),
|
||||||
Y = 0.05f,
|
Y = -0.34f,
|
||||||
},
|
},
|
||||||
new Pulp
|
new Pulp
|
||||||
{
|
{
|
||||||
@ -146,11 +151,9 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
|||||||
{
|
{
|
||||||
new Pulp
|
new Pulp
|
||||||
{
|
{
|
||||||
Anchor = Anchor.TopCentre,
|
|
||||||
Origin = Anchor.BottomCentre,
|
|
||||||
AccentColour = AccentColour,
|
AccentColour = AccentColour,
|
||||||
Size = new Vector2(small_pulp),
|
Size = new Vector2(small_pulp),
|
||||||
Y = 0.1f,
|
Y = -0.3f,
|
||||||
},
|
},
|
||||||
new Pulp
|
new Pulp
|
||||||
{
|
{
|
||||||
@ -186,11 +189,9 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
|||||||
{
|
{
|
||||||
new Pulp
|
new Pulp
|
||||||
{
|
{
|
||||||
Anchor = Anchor.TopCentre,
|
|
||||||
Origin = Anchor.TopCentre,
|
|
||||||
AccentColour = AccentColour,
|
AccentColour = AccentColour,
|
||||||
Size = new Vector2(small_pulp),
|
Size = new Vector2(small_pulp),
|
||||||
Y = -0.1f,
|
Y = -0.33f,
|
||||||
},
|
},
|
||||||
new Pulp
|
new Pulp
|
||||||
{
|
{
|
||||||
@ -220,10 +221,9 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
|||||||
{
|
{
|
||||||
new Pulp
|
new Pulp
|
||||||
{
|
{
|
||||||
Anchor = Anchor.TopCentre,
|
|
||||||
Origin = Anchor.TopCentre,
|
|
||||||
AccentColour = AccentColour,
|
AccentColour = AccentColour,
|
||||||
Size = new Vector2(small_pulp),
|
Size = new Vector2(small_pulp),
|
||||||
|
Y = -0.25f,
|
||||||
},
|
},
|
||||||
new Pulp
|
new Pulp
|
||||||
{
|
{
|
||||||
@ -253,16 +253,15 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
|||||||
{
|
{
|
||||||
new Pulp
|
new Pulp
|
||||||
{
|
{
|
||||||
Anchor = Anchor.TopCentre,
|
|
||||||
Origin = Anchor.TopCentre,
|
|
||||||
AccentColour = AccentColour,
|
AccentColour = AccentColour,
|
||||||
Size = new Vector2(small_pulp),
|
Size = new Vector2(small_pulp),
|
||||||
Y = -0.15f
|
Y = -0.3f
|
||||||
},
|
},
|
||||||
new Pulp
|
new Pulp
|
||||||
{
|
{
|
||||||
AccentColour = AccentColour,
|
AccentColour = AccentColour,
|
||||||
Size = new Vector2(large_pulp_4 * 1.2f, large_pulp_4 * 3),
|
Size = new Vector2(large_pulp_4 * 0.8f, large_pulp_4 * 2.5f),
|
||||||
|
Y = 0.05f,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -29,14 +29,24 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable.Pieces
|
|||||||
set
|
set
|
||||||
{
|
{
|
||||||
accentColour = value;
|
accentColour = value;
|
||||||
|
if (IsLoaded) updateAccentColour();
|
||||||
EdgeEffect = new EdgeEffectParameters
|
|
||||||
{
|
|
||||||
Type = EdgeEffectType.Glow,
|
|
||||||
Radius = 8,
|
|
||||||
Colour = accentColour.Darken(0.2f).Opacity(0.75f)
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateAccentColour()
|
||||||
|
{
|
||||||
|
EdgeEffect = new EdgeEffectParameters
|
||||||
|
{
|
||||||
|
Type = EdgeEffectType.Glow,
|
||||||
|
Radius = Size.X / 2,
|
||||||
|
Colour = accentColour.Darken(0.2f).Opacity(0.75f)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
updateAccentColour();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,8 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
|
|
||||||
public override PassThroughInputManager CreateInputManager() => new CatchInputManager(Ruleset.RulesetInfo);
|
public override PassThroughInputManager CreateInputManager() => new CatchInputManager(Ruleset.RulesetInfo);
|
||||||
|
|
||||||
|
protected override Vector2 PlayfieldArea => new Vector2(0.86f); // matches stable's vertical offset for catcher plate
|
||||||
|
|
||||||
protected override DrawableHitObject<CatchHitObject> GetVisualRepresentation(CatchHitObject h)
|
protected override DrawableHitObject<CatchHitObject> GetVisualRepresentation(CatchHitObject h)
|
||||||
{
|
{
|
||||||
switch (h)
|
switch (h)
|
||||||
|
@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
{
|
{
|
||||||
public class CatcherArea : Container
|
public class CatcherArea : Container
|
||||||
{
|
{
|
||||||
public const float CATCHER_SIZE = 172;
|
public const float CATCHER_SIZE = 84;
|
||||||
|
|
||||||
protected readonly Catcher MovableCatcher;
|
protected readonly Catcher MovableCatcher;
|
||||||
|
|
||||||
@ -99,8 +99,6 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
|
|
||||||
public class Catcher : Container, IKeyBindingHandler<CatchAction>
|
public class Catcher : Container, IKeyBindingHandler<CatchAction>
|
||||||
{
|
{
|
||||||
private Texture texture;
|
|
||||||
|
|
||||||
private Container<DrawableHitObject> caughtFruit;
|
private Container<DrawableHitObject> caughtFruit;
|
||||||
|
|
||||||
public Container ExplodingFruitTarget;
|
public Container ExplodingFruitTarget;
|
||||||
@ -121,10 +119,8 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(TextureStore textures)
|
private void load()
|
||||||
{
|
{
|
||||||
texture = textures.Get(@"Play/Catch/fruit-catcher-idle");
|
|
||||||
|
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
caughtFruit = new Container<DrawableHitObject>
|
caughtFruit = new Container<DrawableHitObject>
|
||||||
@ -196,13 +192,7 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
Scheduler.AddDelayed(beginTrail, HyperDashing ? 25 : 50);
|
Scheduler.AddDelayed(beginTrail, HyperDashing ? 25 : 50);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Sprite createCatcherSprite() => new Sprite
|
private Sprite createCatcherSprite() => new CatcherSprite();
|
||||||
{
|
|
||||||
Size = new Vector2(CATCHER_SIZE),
|
|
||||||
FillMode = FillMode.Fill,
|
|
||||||
Texture = texture,
|
|
||||||
OriginPosition = new Vector2(-3, 10) // temporary until the sprite is aligned correctly.
|
|
||||||
};
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Add a caught fruit to the catcher's stack.
|
/// Add a caught fruit to the catcher's stack.
|
||||||
@ -411,6 +401,23 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
f.Expire();
|
f.Expire();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class CatcherSprite : Sprite
|
||||||
|
{
|
||||||
|
public CatcherSprite()
|
||||||
|
{
|
||||||
|
Size = new Vector2(CATCHER_SIZE);
|
||||||
|
|
||||||
|
// Sets the origin roughly to the centre of the catcher's plate to allow for correct scaling.
|
||||||
|
OriginPosition = new Vector2(-0.02f, 0.06f) * CATCHER_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(TextureStore textures)
|
||||||
|
{
|
||||||
|
Texture = textures.Get(@"Play/Catch/fruit-catcher-idle");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ namespace osu.Game.Rulesets.Mania.Mods
|
|||||||
public override string Name => "Dual Stages";
|
public override string Name => "Dual Stages";
|
||||||
public override string ShortenedName => "DS";
|
public override string ShortenedName => "DS";
|
||||||
public override string Description => @"Double the stages, double the fun!";
|
public override string Description => @"Double the stages, double the fun!";
|
||||||
public override double ScoreMultiplier => 0;
|
public override double ScoreMultiplier => 1;
|
||||||
|
|
||||||
private bool isForCurrentRuleset;
|
private bool isForCurrentRuleset;
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ namespace osu.Game.Rulesets.Mania.Mods
|
|||||||
public override string ShortenedName => "RD";
|
public override string ShortenedName => "RD";
|
||||||
public override FontAwesome Icon => FontAwesome.fa_osu_dice;
|
public override FontAwesome Icon => FontAwesome.fa_osu_dice;
|
||||||
public override string Description => @"Shuffle around the keys!";
|
public override string Description => @"Shuffle around the keys!";
|
||||||
public override double ScoreMultiplier => 0;
|
public override double ScoreMultiplier => 1;
|
||||||
|
|
||||||
public void ApplyToRulesetContainer(RulesetContainer<ManiaHitObject> rulesetContainer)
|
public void ApplyToRulesetContainer(RulesetContainer<ManiaHitObject> rulesetContainer)
|
||||||
{
|
{
|
||||||
|
@ -13,8 +13,7 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
public override string ShortenedName => "AP";
|
public override string ShortenedName => "AP";
|
||||||
public override FontAwesome Icon => FontAwesome.fa_osu_mod_autopilot;
|
public override FontAwesome Icon => FontAwesome.fa_osu_mod_autopilot;
|
||||||
public override string Description => @"Automatic cursor movement - just follow the rhythm.";
|
public override string Description => @"Automatic cursor movement - just follow the rhythm.";
|
||||||
public override double ScoreMultiplier => 0;
|
public override double ScoreMultiplier => 1;
|
||||||
public override bool Ranked => false;
|
|
||||||
public override Type[] IncompatibleMods => new[] { typeof(OsuModSpunOut), typeof(ModRelax), typeof(ModSuddenDeath), typeof(ModNoFail), typeof(ModAutoplay) };
|
public override Type[] IncompatibleMods => new[] { typeof(OsuModSpunOut), typeof(ModRelax), typeof(ModSuddenDeath), typeof(ModNoFail), typeof(ModAutoplay) };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@ using osu.Framework.Platform;
|
|||||||
using osu.Game.IPC;
|
using osu.Game.IPC;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
|
using SharpCompress.Archives.Zip;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Beatmaps.IO
|
namespace osu.Game.Tests.Beatmaps.IO
|
||||||
{
|
{
|
||||||
@ -77,8 +78,69 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
|
|
||||||
var manager = osu.Dependencies.Get<BeatmapManager>();
|
var manager = osu.Dependencies.Get<BeatmapManager>();
|
||||||
|
|
||||||
Assert.IsTrue(manager.GetAllUsableBeatmapSets().Count == 1);
|
Assert.AreEqual(1, manager.GetAllUsableBeatmapSets().Count);
|
||||||
Assert.IsTrue(manager.QueryBeatmapSets(_ => true).ToList().Count == 1);
|
Assert.AreEqual(1, manager.QueryBeatmapSets(_ => true).ToList().Count);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
host.Exit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestRollbackOnFailure()
|
||||||
|
{
|
||||||
|
//unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
|
||||||
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost("TestRollbackOnFailure"))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var osu = loadOsu(host);
|
||||||
|
var manager = osu.Dependencies.Get<BeatmapManager>();
|
||||||
|
|
||||||
|
int fireCount = 0;
|
||||||
|
|
||||||
|
// ReSharper disable once AccessToModifiedClosure
|
||||||
|
manager.ItemAdded += _ => fireCount++;
|
||||||
|
manager.ItemRemoved += _ => fireCount++;
|
||||||
|
|
||||||
|
var imported = loadOszIntoOsu(osu);
|
||||||
|
|
||||||
|
Assert.AreEqual(0, fireCount -= 1);
|
||||||
|
|
||||||
|
imported.Hash += "-changed";
|
||||||
|
manager.Update(imported);
|
||||||
|
|
||||||
|
Assert.AreEqual(0, fireCount -= 2);
|
||||||
|
|
||||||
|
var breakTemp = createTemporaryBeatmap();
|
||||||
|
|
||||||
|
MemoryStream brokenOsu = new MemoryStream(new byte[] { 1, 3, 3, 7 });
|
||||||
|
MemoryStream brokenOsz = new MemoryStream(File.ReadAllBytes(breakTemp));
|
||||||
|
|
||||||
|
File.Delete(breakTemp);
|
||||||
|
|
||||||
|
using (var outStream = File.Open(breakTemp, FileMode.CreateNew))
|
||||||
|
using (var zip = ZipArchive.Open(brokenOsz))
|
||||||
|
{
|
||||||
|
zip.AddEntry("broken.osu", brokenOsu, false);
|
||||||
|
zip.SaveTo(outStream, SharpCompress.Common.CompressionType.Deflate);
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.AreEqual(1, manager.GetAllUsableBeatmapSets().Count);
|
||||||
|
Assert.AreEqual(1, manager.QueryBeatmapSets(_ => true).ToList().Count);
|
||||||
|
Assert.AreEqual(12, manager.QueryBeatmaps(_ => true).ToList().Count);
|
||||||
|
|
||||||
|
// this will trigger purging of the existing beatmap (online set id match) but should rollback due to broken osu.
|
||||||
|
manager.Import(breakTemp);
|
||||||
|
|
||||||
|
// no events should be fired in the case of a rollback.
|
||||||
|
Assert.AreEqual(0, fireCount);
|
||||||
|
|
||||||
|
Assert.AreEqual(1, manager.GetAllUsableBeatmapSets().Count);
|
||||||
|
Assert.AreEqual(1, manager.QueryBeatmapSets(_ => true).ToList().Count);
|
||||||
|
Assert.AreEqual(12, manager.QueryBeatmaps(_ => true).ToList().Count);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
@ -100,18 +162,17 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
|
|
||||||
var imported = loadOszIntoOsu(osu);
|
var imported = loadOszIntoOsu(osu);
|
||||||
|
|
||||||
//var change = manager.QueryBeatmapSets(_ => true).First();
|
|
||||||
imported.Hash += "-changed";
|
imported.Hash += "-changed";
|
||||||
manager.Update(imported);
|
manager.Update(imported);
|
||||||
|
|
||||||
var importedSecondTime = loadOszIntoOsu(osu);
|
var importedSecondTime = loadOszIntoOsu(osu);
|
||||||
|
|
||||||
// check the newly "imported" beatmap is actually just the restored previous import. since it matches hash.
|
|
||||||
Assert.IsTrue(imported.ID != importedSecondTime.ID);
|
Assert.IsTrue(imported.ID != importedSecondTime.ID);
|
||||||
Assert.IsTrue(imported.Beatmaps.First().ID < importedSecondTime.Beatmaps.First().ID);
|
Assert.IsTrue(imported.Beatmaps.First().ID < importedSecondTime.Beatmaps.First().ID);
|
||||||
|
|
||||||
Assert.IsTrue(manager.GetAllUsableBeatmapSets().Count == 1);
|
// only one beatmap will exist as the online set ID matched, causing purging of the first import.
|
||||||
Assert.IsTrue(manager.QueryBeatmapSets(_ => true).ToList().Count == 1);
|
Assert.AreEqual(1, manager.GetAllUsableBeatmapSets().Count);
|
||||||
|
Assert.AreEqual(1, manager.QueryBeatmapSets(_ => true).ToList().Count);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
@ -162,8 +223,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
|
|
||||||
var osu = loadOsu(host);
|
var osu = loadOsu(host);
|
||||||
|
|
||||||
var temp = prepareTempCopy(osz_path);
|
var temp = createTemporaryBeatmap();
|
||||||
Assert.IsTrue(File.Exists(temp));
|
|
||||||
|
|
||||||
var importer = new ArchiveImportIPCChannel(client);
|
var importer = new ArchiveImportIPCChannel(client);
|
||||||
if (!importer.ImportAsync(temp).Wait(10000))
|
if (!importer.ImportAsync(temp).Wait(10000))
|
||||||
@ -188,8 +248,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var osu = loadOsu(host);
|
var osu = loadOsu(host);
|
||||||
var temp = prepareTempCopy(osz_path);
|
var temp = createTemporaryBeatmap();
|
||||||
Assert.IsTrue(File.Exists(temp), "Temporary file copy never substantiated");
|
|
||||||
using (File.OpenRead(temp))
|
using (File.OpenRead(temp))
|
||||||
osu.Dependencies.Get<BeatmapManager>().Import(temp);
|
osu.Dependencies.Get<BeatmapManager>().Import(temp);
|
||||||
ensureLoaded(osu);
|
ensureLoaded(osu);
|
||||||
@ -203,11 +262,16 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private BeatmapSetInfo loadOszIntoOsu(OsuGameBase osu)
|
private string createTemporaryBeatmap()
|
||||||
{
|
{
|
||||||
var temp = prepareTempCopy(osz_path);
|
var temp = new FileInfo(osz_path).CopyTo(Path.GetTempFileName(), true).FullName;
|
||||||
|
|
||||||
Assert.IsTrue(File.Exists(temp));
|
Assert.IsTrue(File.Exists(temp));
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
private BeatmapSetInfo loadOszIntoOsu(OsuGameBase osu, string path = null)
|
||||||
|
{
|
||||||
|
var temp = path ?? createTemporaryBeatmap();
|
||||||
|
|
||||||
var manager = osu.Dependencies.Get<BeatmapManager>();
|
var manager = osu.Dependencies.Get<BeatmapManager>();
|
||||||
|
|
||||||
@ -219,7 +283,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
|
|
||||||
waitForOrAssert(() => !File.Exists(temp), "Temporary file still exists after standard import", 5000);
|
waitForOrAssert(() => !File.Exists(temp), "Temporary file still exists after standard import", 5000);
|
||||||
|
|
||||||
return imported.FirstOrDefault();
|
return imported.LastOrDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void deleteBeatmapSet(BeatmapSetInfo imported, OsuGameBase osu)
|
private void deleteBeatmapSet(BeatmapSetInfo imported, OsuGameBase osu)
|
||||||
@ -228,16 +292,10 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
manager.Delete(imported);
|
manager.Delete(imported);
|
||||||
|
|
||||||
Assert.IsTrue(manager.GetAllUsableBeatmapSets().Count == 0);
|
Assert.IsTrue(manager.GetAllUsableBeatmapSets().Count == 0);
|
||||||
Assert.IsTrue(manager.QueryBeatmapSets(_ => true).ToList().Count == 1);
|
Assert.AreEqual(1, manager.QueryBeatmapSets(_ => true).ToList().Count);
|
||||||
Assert.IsTrue(manager.QueryBeatmapSets(_ => true).First().DeletePending);
|
Assert.IsTrue(manager.QueryBeatmapSets(_ => true).First().DeletePending);
|
||||||
}
|
}
|
||||||
|
|
||||||
private string prepareTempCopy(string path)
|
|
||||||
{
|
|
||||||
var temp = Path.GetTempFileName();
|
|
||||||
return new FileInfo(path).CopyTo(temp, true).FullName;
|
|
||||||
}
|
|
||||||
|
|
||||||
private OsuGameBase loadOsu(GameHost host)
|
private OsuGameBase loadOsu(GameHost host)
|
||||||
{
|
{
|
||||||
var osu = new OsuGameBase();
|
var osu = new OsuGameBase();
|
||||||
|
@ -39,8 +39,6 @@ namespace osu.Game.Tests.Visual
|
|||||||
typeof(SpecialSection),
|
typeof(SpecialSection),
|
||||||
};
|
};
|
||||||
|
|
||||||
private const string unranked_suffix = " (Unranked)";
|
|
||||||
|
|
||||||
private RulesetStore rulesets;
|
private RulesetStore rulesets;
|
||||||
private ModDisplay modDisplay;
|
private ModDisplay modDisplay;
|
||||||
private TestModSelectOverlay modSelect;
|
private TestModSelectOverlay modSelect;
|
||||||
@ -121,7 +119,7 @@ namespace osu.Game.Tests.Visual
|
|||||||
|
|
||||||
private void testManiaMods(ManiaRuleset ruleset)
|
private void testManiaMods(ManiaRuleset ruleset)
|
||||||
{
|
{
|
||||||
testMultiplierTextUnranked(ruleset.GetModsFor(ModType.Special).First(m => m is ManiaModRandom));
|
testRankedText(ruleset.GetModsFor(ModType.Special).First(m => m is ManiaModRandom));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void testSingleMod(Mod mod)
|
private void testSingleMod(Mod mod)
|
||||||
@ -198,13 +196,16 @@ namespace osu.Game.Tests.Visual
|
|||||||
checkLabelColor(Color4.White);
|
checkLabelColor(Color4.White);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void testMultiplierTextUnranked(Mod mod)
|
private void testRankedText(Mod mod)
|
||||||
{
|
{
|
||||||
AddAssert("check for ranked", () => !modSelect.MultiplierLabel.Text.EndsWith(unranked_suffix));
|
AddWaitStep(1, "wait for fade");
|
||||||
|
AddAssert("check for ranked", () => modSelect.UnrankedLabel.Alpha == 0);
|
||||||
selectNext(mod);
|
selectNext(mod);
|
||||||
AddAssert("check for unranked", () => modSelect.MultiplierLabel.Text.EndsWith(unranked_suffix));
|
AddWaitStep(1, "wait for fade");
|
||||||
|
AddAssert("check for unranked", () => modSelect.UnrankedLabel.Alpha != 0);
|
||||||
selectPrevious(mod);
|
selectPrevious(mod);
|
||||||
AddAssert("check for ranked", () => !modSelect.MultiplierLabel.Text.EndsWith(unranked_suffix));
|
AddWaitStep(1, "wait for fade");
|
||||||
|
AddAssert("check for ranked", () => modSelect.UnrankedLabel.Alpha == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void selectNext(Mod mod) => AddStep($"left click {mod.Name}", () => modSelect.GetModButton(mod)?.SelectNext(1));
|
private void selectNext(Mod mod) => AddStep($"left click {mod.Name}", () => modSelect.GetModButton(mod)?.SelectNext(1));
|
||||||
@ -240,6 +241,7 @@ namespace osu.Game.Tests.Visual
|
|||||||
}
|
}
|
||||||
|
|
||||||
public new OsuSpriteText MultiplierLabel => base.MultiplierLabel;
|
public new OsuSpriteText MultiplierLabel => base.MultiplierLabel;
|
||||||
|
public new OsuSpriteText UnrankedLabel => base.UnrankedLabel;
|
||||||
public new TriangleButton DeselectAllButton => base.DeselectAllButton;
|
public new TriangleButton DeselectAllButton => base.DeselectAllButton;
|
||||||
|
|
||||||
public new Color4 LowMultiplierColour => base.LowMultiplierColour;
|
public new Color4 LowMultiplierColour => base.LowMultiplierColour;
|
||||||
|
@ -81,7 +81,7 @@ namespace osu.Game.Beatmaps
|
|||||||
|
|
||||||
protected override void Populate(BeatmapSetInfo model, ArchiveReader archive)
|
protected override void Populate(BeatmapSetInfo model, ArchiveReader archive)
|
||||||
{
|
{
|
||||||
model.Beatmaps = createBeatmapDifficulties(archive);
|
model.Beatmaps = createBeatmapDifficulties(model, archive);
|
||||||
|
|
||||||
// remove metadata from difficulties where it matches the set
|
// remove metadata from difficulties where it matches the set
|
||||||
foreach (BeatmapInfo b in model.Beatmaps)
|
foreach (BeatmapInfo b in model.Beatmaps)
|
||||||
@ -107,6 +107,7 @@ namespace osu.Game.Beatmaps
|
|||||||
{
|
{
|
||||||
Delete(existingOnlineId);
|
Delete(existingOnlineId);
|
||||||
beatmaps.PurgeDeletable(s => s.ID == existingOnlineId.ID);
|
beatmaps.PurgeDeletable(s => s.ID == existingOnlineId.ID);
|
||||||
|
Logger.Log($"Found existing beatmap set with same OnlineBeatmapSetID ({model.OnlineBeatmapSetID}). It has been purged.", LoggingTarget.Database);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -241,7 +242,13 @@ namespace osu.Game.Beatmaps
|
|||||||
/// Returns a list of all usable <see cref="BeatmapSetInfo"/>s.
|
/// Returns a list of all usable <see cref="BeatmapSetInfo"/>s.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>A list of available <see cref="BeatmapSetInfo"/>.</returns>
|
/// <returns>A list of available <see cref="BeatmapSetInfo"/>.</returns>
|
||||||
public List<BeatmapSetInfo> GetAllUsableBeatmapSets() => beatmaps.ConsumableItems.Where(s => !s.DeletePending && !s.Protected).ToList();
|
public List<BeatmapSetInfo> GetAllUsableBeatmapSets() => GetAllUsableBeatmapSetsEnumerable().ToList();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a list of all usable <see cref="BeatmapSetInfo"/>s.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A list of available <see cref="BeatmapSetInfo"/>.</returns>
|
||||||
|
public IQueryable<BeatmapSetInfo> GetAllUsableBeatmapSetsEnumerable() => beatmaps.ConsumableItems.Where(s => !s.DeletePending && !s.Protected);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Perform a lookup query on available <see cref="BeatmapSetInfo"/>s.
|
/// Perform a lookup query on available <see cref="BeatmapSetInfo"/>s.
|
||||||
@ -303,7 +310,7 @@ namespace osu.Game.Beatmaps
|
|||||||
{
|
{
|
||||||
// let's make sure there are actually .osu files to import.
|
// let's make sure there are actually .osu files to import.
|
||||||
string mapName = reader.Filenames.FirstOrDefault(f => f.EndsWith(".osu"));
|
string mapName = reader.Filenames.FirstOrDefault(f => f.EndsWith(".osu"));
|
||||||
if (string.IsNullOrEmpty(mapName)) throw new InvalidOperationException("No beatmap files found in the map folder.");
|
if (string.IsNullOrEmpty(mapName)) throw new InvalidOperationException("No beatmap files found in this beatmap archive.");
|
||||||
|
|
||||||
BeatmapMetadata metadata;
|
BeatmapMetadata metadata;
|
||||||
using (var stream = new StreamReader(reader.GetStream(mapName)))
|
using (var stream = new StreamReader(reader.GetStream(mapName)))
|
||||||
@ -321,7 +328,7 @@ namespace osu.Game.Beatmaps
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create all required <see cref="BeatmapInfo"/>s for the provided archive.
|
/// Create all required <see cref="BeatmapInfo"/>s for the provided archive.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private List<BeatmapInfo> createBeatmapDifficulties(ArchiveReader reader)
|
private List<BeatmapInfo> createBeatmapDifficulties(BeatmapSetInfo model, ArchiveReader reader)
|
||||||
{
|
{
|
||||||
var beatmapInfos = new List<BeatmapInfo>();
|
var beatmapInfos = new List<BeatmapInfo>();
|
||||||
|
|
||||||
@ -341,6 +348,14 @@ namespace osu.Game.Beatmaps
|
|||||||
beatmap.BeatmapInfo.Hash = ms.ComputeSHA2Hash();
|
beatmap.BeatmapInfo.Hash = ms.ComputeSHA2Hash();
|
||||||
beatmap.BeatmapInfo.MD5Hash = ms.ComputeMD5Hash();
|
beatmap.BeatmapInfo.MD5Hash = ms.ComputeMD5Hash();
|
||||||
|
|
||||||
|
// ensure we have the same online set ID as the set itself.
|
||||||
|
beatmap.BeatmapInfo.OnlineBeatmapSetID = model.OnlineBeatmapSetID;
|
||||||
|
beatmap.BeatmapInfo.Metadata.OnlineBeatmapSetID = model.OnlineBeatmapSetID;
|
||||||
|
|
||||||
|
// check that no existing beatmap exists that is imported with the same online beatmap ID. if so, give it precedence.
|
||||||
|
if (beatmap.BeatmapInfo.OnlineBeatmapID.HasValue && QueryBeatmap(b => b.OnlineBeatmapID.Value == beatmap.BeatmapInfo.OnlineBeatmapID.Value) != null)
|
||||||
|
beatmap.BeatmapInfo.OnlineBeatmapID = null;
|
||||||
|
|
||||||
RulesetInfo ruleset = rulesets.GetRuleset(beatmap.BeatmapInfo.RulesetID);
|
RulesetInfo ruleset = rulesets.GetRuleset(beatmap.BeatmapInfo.RulesetID);
|
||||||
|
|
||||||
beatmap.BeatmapInfo.Ruleset = ruleset;
|
beatmap.BeatmapInfo.Ruleset = ruleset;
|
||||||
|
@ -59,6 +59,7 @@ namespace osu.Game.Beatmaps.Drawables
|
|||||||
{
|
{
|
||||||
displayedCover?.FadeOut(400);
|
displayedCover?.FadeOut(400);
|
||||||
displayedCover?.Expire();
|
displayedCover?.Expire();
|
||||||
|
displayedCover = null;
|
||||||
|
|
||||||
if (beatmapSet != null)
|
if (beatmapSet != null)
|
||||||
{
|
{
|
||||||
|
@ -56,13 +56,49 @@ namespace osu.Game.Database
|
|||||||
// ReSharper disable once NotAccessedField.Local (we should keep a reference to this so it is not finalised)
|
// ReSharper disable once NotAccessedField.Local (we should keep a reference to this so it is not finalised)
|
||||||
private ArchiveImportIPCChannel ipc;
|
private ArchiveImportIPCChannel ipc;
|
||||||
|
|
||||||
|
private readonly List<Action> cachedEvents = new List<Action>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Allows delaying of outwards events until an operation is confirmed (at a database level).
|
||||||
|
/// </summary>
|
||||||
|
private bool delayingEvents;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Begin delaying outwards events.
|
||||||
|
/// </summary>
|
||||||
|
private void delayEvents() => delayingEvents = true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Flush delayed events and disable delaying.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="perform">Whether the flushed events should be performed.</param>
|
||||||
|
private void flushEvents(bool perform)
|
||||||
|
{
|
||||||
|
if (perform)
|
||||||
|
{
|
||||||
|
foreach (var a in cachedEvents)
|
||||||
|
a.Invoke();
|
||||||
|
}
|
||||||
|
|
||||||
|
cachedEvents.Clear();
|
||||||
|
delayingEvents = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleEvent(Action a)
|
||||||
|
{
|
||||||
|
if (delayingEvents)
|
||||||
|
cachedEvents.Add(a);
|
||||||
|
else
|
||||||
|
a.Invoke();
|
||||||
|
}
|
||||||
|
|
||||||
protected ArchiveModelManager(Storage storage, IDatabaseContextFactory contextFactory, MutableDatabaseBackedStore<TModel> modelStore, IIpcHost importHost = null)
|
protected ArchiveModelManager(Storage storage, IDatabaseContextFactory contextFactory, MutableDatabaseBackedStore<TModel> modelStore, IIpcHost importHost = null)
|
||||||
{
|
{
|
||||||
ContextFactory = contextFactory;
|
ContextFactory = contextFactory;
|
||||||
|
|
||||||
ModelStore = modelStore;
|
ModelStore = modelStore;
|
||||||
ModelStore.ItemAdded += s => ItemAdded?.Invoke(s);
|
ModelStore.ItemAdded += s => handleEvent(() => ItemAdded?.Invoke(s));
|
||||||
ModelStore.ItemRemoved += s => ItemRemoved?.Invoke(s);
|
ModelStore.ItemRemoved += s => handleEvent(() => ItemRemoved?.Invoke(s));
|
||||||
|
|
||||||
Files = new FileStore(contextFactory, storage);
|
Files = new FileStore(contextFactory, storage);
|
||||||
|
|
||||||
@ -138,24 +174,56 @@ namespace osu.Game.Database
|
|||||||
/// <param name="archive">The archive to be imported.</param>
|
/// <param name="archive">The archive to be imported.</param>
|
||||||
public TModel Import(ArchiveReader archive)
|
public TModel Import(ArchiveReader archive)
|
||||||
{
|
{
|
||||||
using (ContextFactory.GetForWrite()) // used to share a context for full import. keep in mind this will block all writes.
|
TModel item = null;
|
||||||
|
delayEvents();
|
||||||
|
|
||||||
|
try
|
||||||
{
|
{
|
||||||
// create a new model (don't yet add to database)
|
using (var write = ContextFactory.GetForWrite()) // used to share a context for full import. keep in mind this will block all writes.
|
||||||
var item = CreateModel(archive);
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!write.IsTransactionLeader) throw new InvalidOperationException($"Ensure there is no parent transaction so errors can correctly be handled by {this}");
|
||||||
|
|
||||||
var existing = CheckForExisting(item);
|
// create a new model (don't yet add to database)
|
||||||
|
item = CreateModel(archive);
|
||||||
|
|
||||||
if (existing != null) return existing;
|
var existing = CheckForExisting(item);
|
||||||
|
|
||||||
item.Files = createFileInfos(archive, Files);
|
if (existing != null)
|
||||||
|
{
|
||||||
|
Logger.Log($"Found existing {typeof(TModel)} for {archive.Name} (ID {existing.ID}). Skipping import.", LoggingTarget.Database);
|
||||||
|
return existing;
|
||||||
|
}
|
||||||
|
|
||||||
Populate(item, archive);
|
item.Files = createFileInfos(archive, Files);
|
||||||
|
|
||||||
// import to store
|
Populate(item, archive);
|
||||||
ModelStore.Add(item);
|
|
||||||
|
|
||||||
return item;
|
// import to store
|
||||||
|
ModelStore.Add(item);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
write.Errors.Add(e);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger.Log($"Import of {archive.Name} successfully completed!", LoggingTarget.Database);
|
||||||
}
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Logger.Error(e, $"Import of {archive.Name} failed and has been rolled back.", LoggingTarget.Database);
|
||||||
|
item = null;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
// we only want to flush events after we've confirmed the write context didn't have any errors.
|
||||||
|
flushEvents(item != null);
|
||||||
|
}
|
||||||
|
|
||||||
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -178,12 +246,8 @@ namespace osu.Game.Database
|
|||||||
/// <param name="item">The item to delete.</param>
|
/// <param name="item">The item to delete.</param>
|
||||||
public void Delete(TModel item)
|
public void Delete(TModel item)
|
||||||
{
|
{
|
||||||
using (var usage = ContextFactory.GetForWrite())
|
using (ContextFactory.GetForWrite())
|
||||||
{
|
{
|
||||||
var context = usage.Context;
|
|
||||||
|
|
||||||
context.ChangeTracker.AutoDetectChangesEnabled = false;
|
|
||||||
|
|
||||||
// re-fetch the model on the import context.
|
// re-fetch the model on the import context.
|
||||||
var foundModel = queryModel().Include(s => s.Files).ThenInclude(f => f.FileInfo).First(s => s.ID == item.ID);
|
var foundModel = queryModel().Include(s => s.Files).ThenInclude(f => f.FileInfo).First(s => s.ID == item.ID);
|
||||||
|
|
||||||
@ -191,8 +255,6 @@ namespace osu.Game.Database
|
|||||||
|
|
||||||
if (ModelStore.Delete(foundModel))
|
if (ModelStore.Delete(foundModel))
|
||||||
Files.Dereference(foundModel.Files.Select(f => f.FileInfo).ToArray());
|
Files.Dereference(foundModel.Files.Select(f => f.FileInfo).ToArray());
|
||||||
|
|
||||||
context.ChangeTracker.AutoDetectChangesEnabled = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage;
|
||||||
using osu.Framework.Platform;
|
using osu.Framework.Platform;
|
||||||
|
|
||||||
namespace osu.Game.Database
|
namespace osu.Game.Database
|
||||||
@ -17,8 +19,12 @@ namespace osu.Game.Database
|
|||||||
private readonly object writeLock = new object();
|
private readonly object writeLock = new object();
|
||||||
|
|
||||||
private bool currentWriteDidWrite;
|
private bool currentWriteDidWrite;
|
||||||
|
private bool currentWriteDidError;
|
||||||
|
|
||||||
private int currentWriteUsages;
|
private int currentWriteUsages;
|
||||||
|
|
||||||
|
private IDbContextTransaction currentWriteTransaction;
|
||||||
|
|
||||||
public DatabaseContextFactory(GameHost host)
|
public DatabaseContextFactory(GameHost host)
|
||||||
{
|
{
|
||||||
this.host = host;
|
this.host = host;
|
||||||
@ -35,14 +41,25 @@ namespace osu.Game.Database
|
|||||||
/// Request a context for write usage. Can be consumed in a nested fashion (and will return the same underlying context).
|
/// Request a context for write usage. Can be consumed in a nested fashion (and will return the same underlying context).
|
||||||
/// This method may block if a write is already active on a different thread.
|
/// This method may block if a write is already active on a different thread.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="withTransaction">Whether to start a transaction for this write.</param>
|
||||||
/// <returns>A usage containing a usable context.</returns>
|
/// <returns>A usage containing a usable context.</returns>
|
||||||
public DatabaseWriteUsage GetForWrite()
|
public DatabaseWriteUsage GetForWrite(bool withTransaction = true)
|
||||||
{
|
{
|
||||||
Monitor.Enter(writeLock);
|
Monitor.Enter(writeLock);
|
||||||
|
|
||||||
|
if (currentWriteTransaction == null && withTransaction)
|
||||||
|
{
|
||||||
|
// this mitigates the fact that changes on tracked entities will not be rolled back with the transaction by ensuring write operations are always executed in isolated contexts.
|
||||||
|
// if this results in sub-optimal efficiency, we may need to look into removing Database-level transactions in favour of running SaveChanges where we currently commit the transaction.
|
||||||
|
if (threadContexts.IsValueCreated)
|
||||||
|
recycleThreadContexts();
|
||||||
|
|
||||||
|
currentWriteTransaction = threadContexts.Value.Database.BeginTransaction();
|
||||||
|
}
|
||||||
|
|
||||||
Interlocked.Increment(ref currentWriteUsages);
|
Interlocked.Increment(ref currentWriteUsages);
|
||||||
|
|
||||||
return new DatabaseWriteUsage(threadContexts.Value, usageCompleted);
|
return new DatabaseWriteUsage(threadContexts.Value, usageCompleted) { IsTransactionLeader = currentWriteTransaction != null && currentWriteUsages == 1 };
|
||||||
}
|
}
|
||||||
|
|
||||||
private void usageCompleted(DatabaseWriteUsage usage)
|
private void usageCompleted(DatabaseWriteUsage usage)
|
||||||
@ -52,18 +69,27 @@ namespace osu.Game.Database
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
currentWriteDidWrite |= usage.PerformedWrite;
|
currentWriteDidWrite |= usage.PerformedWrite;
|
||||||
|
currentWriteDidError |= usage.Errors.Any();
|
||||||
|
|
||||||
if (usages > 0) return;
|
if (usages == 0)
|
||||||
|
|
||||||
if (currentWriteDidWrite)
|
|
||||||
{
|
{
|
||||||
// explicitly dispose to ensure any outstanding flushes happen as soon as possible (and underlying resources are purged).
|
if (currentWriteDidError)
|
||||||
usage.Context.Dispose();
|
currentWriteTransaction?.Rollback();
|
||||||
|
else
|
||||||
|
currentWriteTransaction?.Commit();
|
||||||
|
|
||||||
|
if (currentWriteDidWrite || currentWriteDidError)
|
||||||
|
{
|
||||||
|
// explicitly dispose to ensure any outstanding flushes happen as soon as possible (and underlying resources are purged).
|
||||||
|
usage.Context.Dispose();
|
||||||
|
|
||||||
|
// once all writes are complete, we want to refresh thread-specific contexts to make sure they don't have stale local caches.
|
||||||
|
recycleThreadContexts();
|
||||||
|
}
|
||||||
|
|
||||||
|
currentWriteTransaction = null;
|
||||||
currentWriteDidWrite = false;
|
currentWriteDidWrite = false;
|
||||||
|
currentWriteDidError = false;
|
||||||
// once all writes are complete, we want to refresh thread-specific contexts to make sure they don't have stale local caches.
|
|
||||||
recycleThreadContexts();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
|
@ -2,34 +2,50 @@
|
|||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using Microsoft.EntityFrameworkCore.Storage;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace osu.Game.Database
|
namespace osu.Game.Database
|
||||||
{
|
{
|
||||||
public class DatabaseWriteUsage : IDisposable
|
public class DatabaseWriteUsage : IDisposable
|
||||||
{
|
{
|
||||||
public readonly OsuDbContext Context;
|
public readonly OsuDbContext Context;
|
||||||
private readonly IDbContextTransaction transaction;
|
|
||||||
private readonly Action<DatabaseWriteUsage> usageCompleted;
|
private readonly Action<DatabaseWriteUsage> usageCompleted;
|
||||||
|
|
||||||
public DatabaseWriteUsage(OsuDbContext context, Action<DatabaseWriteUsage> onCompleted)
|
public DatabaseWriteUsage(OsuDbContext context, Action<DatabaseWriteUsage> onCompleted)
|
||||||
{
|
{
|
||||||
Context = context;
|
Context = context;
|
||||||
transaction = Context.BeginTransaction();
|
|
||||||
usageCompleted = onCompleted;
|
usageCompleted = onCompleted;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool PerformedWrite { get; private set; }
|
public bool PerformedWrite { get; private set; }
|
||||||
|
|
||||||
private bool isDisposed;
|
private bool isDisposed;
|
||||||
|
public List<Exception> Errors = new List<Exception>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether this write usage will commit a transaction on completion.
|
||||||
|
/// If false, there is a parent usage responsible for transaction commit.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsTransactionLeader = false;
|
||||||
|
|
||||||
protected void Dispose(bool disposing)
|
protected void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
if (isDisposed) return;
|
if (isDisposed) return;
|
||||||
isDisposed = true;
|
isDisposed = true;
|
||||||
|
|
||||||
PerformedWrite |= Context.SaveChanges(transaction) > 0;
|
try
|
||||||
usageCompleted?.Invoke(this);
|
{
|
||||||
|
PerformedWrite |= Context.SaveChanges() > 0;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Errors.Add(e);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
usageCompleted?.Invoke(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
|
@ -14,7 +14,8 @@ namespace osu.Game.Database
|
|||||||
/// Request a context for write usage. Can be consumed in a nested fashion (and will return the same underlying context).
|
/// Request a context for write usage. Can be consumed in a nested fashion (and will return the same underlying context).
|
||||||
/// This method may block if a write is already active on a different thread.
|
/// This method may block if a write is already active on a different thread.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="withTransaction">Whether to start a transaction for this write.</param>
|
||||||
/// <returns>A usage containing a usable context.</returns>
|
/// <returns>A usage containing a usable context.</returns>
|
||||||
DatabaseWriteUsage GetForWrite();
|
DatabaseWriteUsage GetForWrite(bool withTransaction = true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -50,11 +50,10 @@ namespace osu.Game.Database
|
|||||||
/// <param name="item">The item to update.</param>
|
/// <param name="item">The item to update.</param>
|
||||||
public void Update(T item)
|
public void Update(T item)
|
||||||
{
|
{
|
||||||
ItemRemoved?.Invoke(item);
|
|
||||||
|
|
||||||
using (var usage = ContextFactory.GetForWrite())
|
using (var usage = ContextFactory.GetForWrite())
|
||||||
usage.Context.Update(item);
|
usage.Context.Update(item);
|
||||||
|
|
||||||
|
ItemRemoved?.Invoke(item);
|
||||||
ItemAdded?.Invoke(item);
|
ItemAdded?.Invoke(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.EntityFrameworkCore.Storage;
|
|
||||||
using Microsoft.EntityFrameworkCore.Diagnostics;
|
using Microsoft.EntityFrameworkCore.Diagnostics;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using osu.Framework.Logging;
|
using osu.Framework.Logging;
|
||||||
@ -83,8 +82,8 @@ namespace osu.Game.Database
|
|||||||
base.OnModelCreating(modelBuilder);
|
base.OnModelCreating(modelBuilder);
|
||||||
|
|
||||||
modelBuilder.Entity<BeatmapInfo>().HasIndex(b => b.OnlineBeatmapID).IsUnique();
|
modelBuilder.Entity<BeatmapInfo>().HasIndex(b => b.OnlineBeatmapID).IsUnique();
|
||||||
modelBuilder.Entity<BeatmapInfo>().HasIndex(b => b.MD5Hash).IsUnique();
|
modelBuilder.Entity<BeatmapInfo>().HasIndex(b => b.MD5Hash);
|
||||||
modelBuilder.Entity<BeatmapInfo>().HasIndex(b => b.Hash).IsUnique();
|
modelBuilder.Entity<BeatmapInfo>().HasIndex(b => b.Hash);
|
||||||
|
|
||||||
modelBuilder.Entity<BeatmapSetInfo>().HasIndex(b => b.OnlineBeatmapSetID).IsUnique();
|
modelBuilder.Entity<BeatmapSetInfo>().HasIndex(b => b.OnlineBeatmapSetID).IsUnique();
|
||||||
modelBuilder.Entity<BeatmapSetInfo>().HasIndex(b => b.DeletePending);
|
modelBuilder.Entity<BeatmapSetInfo>().HasIndex(b => b.DeletePending);
|
||||||
@ -104,19 +103,6 @@ namespace osu.Game.Database
|
|||||||
modelBuilder.Entity<BeatmapInfo>().HasOne(b => b.BaseDifficulty);
|
modelBuilder.Entity<BeatmapInfo>().HasOne(b => b.BaseDifficulty);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IDbContextTransaction BeginTransaction()
|
|
||||||
{
|
|
||||||
// return Database.BeginTransaction();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int SaveChanges(IDbContextTransaction transaction = null)
|
|
||||||
{
|
|
||||||
var ret = base.SaveChanges();
|
|
||||||
if (ret > 0) transaction?.Commit();
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
private class OsuDbLoggerFactory : ILoggerFactory
|
private class OsuDbLoggerFactory : ILoggerFactory
|
||||||
{
|
{
|
||||||
#region Disposal
|
#region Disposal
|
||||||
|
@ -14,6 +14,6 @@ namespace osu.Game.Database
|
|||||||
|
|
||||||
public OsuDbContext Get() => context;
|
public OsuDbContext Get() => context;
|
||||||
|
|
||||||
public DatabaseWriteUsage GetForWrite() => new DatabaseWriteUsage(context, null);
|
public DatabaseWriteUsage GetForWrite(bool withTransaction = true) => new DatabaseWriteUsage(context, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
377
osu.Game/Migrations/20180529055154_RemoveUniqueHashConstraints.Designer.cs
generated
Normal file
377
osu.Game/Migrations/20180529055154_RemoveUniqueHashConstraints.Designer.cs
generated
Normal file
@ -0,0 +1,377 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Metadata;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage;
|
||||||
|
using osu.Game.Database;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace osu.Game.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(OsuDbContext))]
|
||||||
|
[Migration("20180529055154_RemoveUniqueHashConstraints")]
|
||||||
|
partial class RemoveUniqueHashConstraints
|
||||||
|
{
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("ProductVersion", "2.0.3-rtm-10026");
|
||||||
|
|
||||||
|
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapDifficulty", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("ID")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<float>("ApproachRate");
|
||||||
|
|
||||||
|
b.Property<float>("CircleSize");
|
||||||
|
|
||||||
|
b.Property<float>("DrainRate");
|
||||||
|
|
||||||
|
b.Property<float>("OverallDifficulty");
|
||||||
|
|
||||||
|
b.Property<double>("SliderMultiplier");
|
||||||
|
|
||||||
|
b.Property<double>("SliderTickRate");
|
||||||
|
|
||||||
|
b.HasKey("ID");
|
||||||
|
|
||||||
|
b.ToTable("BeatmapDifficulty");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("ID")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<int>("AudioLeadIn");
|
||||||
|
|
||||||
|
b.Property<int>("BaseDifficultyID");
|
||||||
|
|
||||||
|
b.Property<int>("BeatDivisor");
|
||||||
|
|
||||||
|
b.Property<int>("BeatmapSetInfoID");
|
||||||
|
|
||||||
|
b.Property<bool>("Countdown");
|
||||||
|
|
||||||
|
b.Property<double>("DistanceSpacing");
|
||||||
|
|
||||||
|
b.Property<int>("GridSize");
|
||||||
|
|
||||||
|
b.Property<string>("Hash");
|
||||||
|
|
||||||
|
b.Property<bool>("Hidden");
|
||||||
|
|
||||||
|
b.Property<bool>("LetterboxInBreaks");
|
||||||
|
|
||||||
|
b.Property<string>("MD5Hash");
|
||||||
|
|
||||||
|
b.Property<int?>("MetadataID");
|
||||||
|
|
||||||
|
b.Property<int?>("OnlineBeatmapID");
|
||||||
|
|
||||||
|
b.Property<string>("Path");
|
||||||
|
|
||||||
|
b.Property<int>("RulesetID");
|
||||||
|
|
||||||
|
b.Property<bool>("SpecialStyle");
|
||||||
|
|
||||||
|
b.Property<float>("StackLeniency");
|
||||||
|
|
||||||
|
b.Property<double>("StarDifficulty");
|
||||||
|
|
||||||
|
b.Property<string>("StoredBookmarks");
|
||||||
|
|
||||||
|
b.Property<double>("TimelineZoom");
|
||||||
|
|
||||||
|
b.Property<string>("Version");
|
||||||
|
|
||||||
|
b.Property<bool>("WidescreenStoryboard");
|
||||||
|
|
||||||
|
b.HasKey("ID");
|
||||||
|
|
||||||
|
b.HasIndex("BaseDifficultyID");
|
||||||
|
|
||||||
|
b.HasIndex("BeatmapSetInfoID");
|
||||||
|
|
||||||
|
b.HasIndex("Hash");
|
||||||
|
|
||||||
|
b.HasIndex("MD5Hash");
|
||||||
|
|
||||||
|
b.HasIndex("MetadataID");
|
||||||
|
|
||||||
|
b.HasIndex("OnlineBeatmapID")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.HasIndex("RulesetID");
|
||||||
|
|
||||||
|
b.ToTable("BeatmapInfo");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapMetadata", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("ID")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<string>("Artist");
|
||||||
|
|
||||||
|
b.Property<string>("ArtistUnicode");
|
||||||
|
|
||||||
|
b.Property<string>("AudioFile");
|
||||||
|
|
||||||
|
b.Property<string>("AuthorString")
|
||||||
|
.HasColumnName("Author");
|
||||||
|
|
||||||
|
b.Property<string>("BackgroundFile");
|
||||||
|
|
||||||
|
b.Property<int>("PreviewTime");
|
||||||
|
|
||||||
|
b.Property<string>("Source");
|
||||||
|
|
||||||
|
b.Property<string>("Tags");
|
||||||
|
|
||||||
|
b.Property<string>("Title");
|
||||||
|
|
||||||
|
b.Property<string>("TitleUnicode");
|
||||||
|
|
||||||
|
b.HasKey("ID");
|
||||||
|
|
||||||
|
b.ToTable("BeatmapMetadata");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("ID")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<int>("BeatmapSetInfoID");
|
||||||
|
|
||||||
|
b.Property<int>("FileInfoID");
|
||||||
|
|
||||||
|
b.Property<string>("Filename")
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasKey("ID");
|
||||||
|
|
||||||
|
b.HasIndex("BeatmapSetInfoID");
|
||||||
|
|
||||||
|
b.HasIndex("FileInfoID");
|
||||||
|
|
||||||
|
b.ToTable("BeatmapSetFileInfo");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("ID")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<bool>("DeletePending");
|
||||||
|
|
||||||
|
b.Property<string>("Hash");
|
||||||
|
|
||||||
|
b.Property<int?>("MetadataID");
|
||||||
|
|
||||||
|
b.Property<int?>("OnlineBeatmapSetID");
|
||||||
|
|
||||||
|
b.Property<bool>("Protected");
|
||||||
|
|
||||||
|
b.HasKey("ID");
|
||||||
|
|
||||||
|
b.HasIndex("DeletePending");
|
||||||
|
|
||||||
|
b.HasIndex("Hash")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.HasIndex("MetadataID");
|
||||||
|
|
||||||
|
b.HasIndex("OnlineBeatmapSetID")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("BeatmapSetInfo");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("osu.Game.Configuration.DatabasedSetting", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("ID")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<int>("IntKey")
|
||||||
|
.HasColumnName("Key");
|
||||||
|
|
||||||
|
b.Property<int?>("RulesetID");
|
||||||
|
|
||||||
|
b.Property<string>("StringValue")
|
||||||
|
.HasColumnName("Value");
|
||||||
|
|
||||||
|
b.Property<int?>("Variant");
|
||||||
|
|
||||||
|
b.HasKey("ID");
|
||||||
|
|
||||||
|
b.HasIndex("RulesetID", "Variant");
|
||||||
|
|
||||||
|
b.ToTable("Settings");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("osu.Game.Input.Bindings.DatabasedKeyBinding", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("ID")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<int>("IntAction")
|
||||||
|
.HasColumnName("Action");
|
||||||
|
|
||||||
|
b.Property<string>("KeysString")
|
||||||
|
.HasColumnName("Keys");
|
||||||
|
|
||||||
|
b.Property<int?>("RulesetID");
|
||||||
|
|
||||||
|
b.Property<int?>("Variant");
|
||||||
|
|
||||||
|
b.HasKey("ID");
|
||||||
|
|
||||||
|
b.HasIndex("IntAction");
|
||||||
|
|
||||||
|
b.HasIndex("RulesetID", "Variant");
|
||||||
|
|
||||||
|
b.ToTable("KeyBinding");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("osu.Game.IO.FileInfo", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("ID")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<string>("Hash");
|
||||||
|
|
||||||
|
b.Property<int>("ReferenceCount");
|
||||||
|
|
||||||
|
b.HasKey("ID");
|
||||||
|
|
||||||
|
b.HasIndex("Hash")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.HasIndex("ReferenceCount");
|
||||||
|
|
||||||
|
b.ToTable("FileInfo");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("osu.Game.Rulesets.RulesetInfo", b =>
|
||||||
|
{
|
||||||
|
b.Property<int?>("ID")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<bool>("Available");
|
||||||
|
|
||||||
|
b.Property<string>("InstantiationInfo");
|
||||||
|
|
||||||
|
b.Property<string>("Name");
|
||||||
|
|
||||||
|
b.Property<string>("ShortName");
|
||||||
|
|
||||||
|
b.HasKey("ID");
|
||||||
|
|
||||||
|
b.HasIndex("Available");
|
||||||
|
|
||||||
|
b.HasIndex("ShortName")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("RulesetInfo");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("osu.Game.Skinning.SkinFileInfo", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("ID")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<int>("FileInfoID");
|
||||||
|
|
||||||
|
b.Property<string>("Filename")
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Property<int>("SkinInfoID");
|
||||||
|
|
||||||
|
b.HasKey("ID");
|
||||||
|
|
||||||
|
b.HasIndex("FileInfoID");
|
||||||
|
|
||||||
|
b.HasIndex("SkinInfoID");
|
||||||
|
|
||||||
|
b.ToTable("SkinFileInfo");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("osu.Game.Skinning.SkinInfo", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("ID")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<string>("Creator");
|
||||||
|
|
||||||
|
b.Property<bool>("DeletePending");
|
||||||
|
|
||||||
|
b.Property<string>("Name");
|
||||||
|
|
||||||
|
b.HasKey("ID");
|
||||||
|
|
||||||
|
b.ToTable("SkinInfo");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("osu.Game.Beatmaps.BeatmapDifficulty", "BaseDifficulty")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("BaseDifficultyID")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo", "BeatmapSet")
|
||||||
|
.WithMany("Beatmaps")
|
||||||
|
.HasForeignKey("BeatmapSetInfoID")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata")
|
||||||
|
.WithMany("Beatmaps")
|
||||||
|
.HasForeignKey("MetadataID");
|
||||||
|
|
||||||
|
b.HasOne("osu.Game.Rulesets.RulesetInfo", "Ruleset")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("RulesetID")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo")
|
||||||
|
.WithMany("Files")
|
||||||
|
.HasForeignKey("BeatmapSetInfoID")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("osu.Game.IO.FileInfo", "FileInfo")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("FileInfoID")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata")
|
||||||
|
.WithMany("BeatmapSets")
|
||||||
|
.HasForeignKey("MetadataID");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("osu.Game.Skinning.SkinFileInfo", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("osu.Game.IO.FileInfo", "FileInfo")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("FileInfoID")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("osu.Game.Skinning.SkinInfo")
|
||||||
|
.WithMany("Files")
|
||||||
|
.HasForeignKey("SkinInfoID")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,53 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace osu.Game.Migrations
|
||||||
|
{
|
||||||
|
public partial class RemoveUniqueHashConstraints : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropIndex(
|
||||||
|
name: "IX_BeatmapInfo_Hash",
|
||||||
|
table: "BeatmapInfo");
|
||||||
|
|
||||||
|
migrationBuilder.DropIndex(
|
||||||
|
name: "IX_BeatmapInfo_MD5Hash",
|
||||||
|
table: "BeatmapInfo");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_BeatmapInfo_Hash",
|
||||||
|
table: "BeatmapInfo",
|
||||||
|
column: "Hash");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_BeatmapInfo_MD5Hash",
|
||||||
|
table: "BeatmapInfo",
|
||||||
|
column: "MD5Hash");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropIndex(
|
||||||
|
name: "IX_BeatmapInfo_Hash",
|
||||||
|
table: "BeatmapInfo");
|
||||||
|
|
||||||
|
migrationBuilder.DropIndex(
|
||||||
|
name: "IX_BeatmapInfo_MD5Hash",
|
||||||
|
table: "BeatmapInfo");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_BeatmapInfo_Hash",
|
||||||
|
table: "BeatmapInfo",
|
||||||
|
column: "Hash",
|
||||||
|
unique: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_BeatmapInfo_MD5Hash",
|
||||||
|
table: "BeatmapInfo",
|
||||||
|
column: "MD5Hash",
|
||||||
|
unique: true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,11 @@
|
|||||||
// <auto-generated />
|
// <auto-generated />
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Metadata;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage;
|
||||||
using osu.Game.Database;
|
using osu.Game.Database;
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace osu.Game.Migrations
|
namespace osu.Game.Migrations
|
||||||
{
|
{
|
||||||
@ -12,7 +16,7 @@ namespace osu.Game.Migrations
|
|||||||
{
|
{
|
||||||
#pragma warning disable 612, 618
|
#pragma warning disable 612, 618
|
||||||
modelBuilder
|
modelBuilder
|
||||||
.HasAnnotation("ProductVersion", "2.0.0-rtm-26452");
|
.HasAnnotation("ProductVersion", "2.0.3-rtm-10026");
|
||||||
|
|
||||||
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapDifficulty", b =>
|
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapDifficulty", b =>
|
||||||
{
|
{
|
||||||
@ -27,9 +31,9 @@ namespace osu.Game.Migrations
|
|||||||
|
|
||||||
b.Property<float>("OverallDifficulty");
|
b.Property<float>("OverallDifficulty");
|
||||||
|
|
||||||
b.Property<float>("SliderMultiplier");
|
b.Property<double>("SliderMultiplier");
|
||||||
|
|
||||||
b.Property<float>("SliderTickRate");
|
b.Property<double>("SliderTickRate");
|
||||||
|
|
||||||
b.HasKey("ID");
|
b.HasKey("ID");
|
||||||
|
|
||||||
@ -91,11 +95,9 @@ namespace osu.Game.Migrations
|
|||||||
|
|
||||||
b.HasIndex("BeatmapSetInfoID");
|
b.HasIndex("BeatmapSetInfoID");
|
||||||
|
|
||||||
b.HasIndex("Hash")
|
b.HasIndex("Hash");
|
||||||
.IsUnique();
|
|
||||||
|
|
||||||
b.HasIndex("MD5Hash")
|
b.HasIndex("MD5Hash");
|
||||||
.IsUnique();
|
|
||||||
|
|
||||||
b.HasIndex("MetadataID");
|
b.HasIndex("MetadataID");
|
||||||
|
|
||||||
|
@ -208,7 +208,7 @@ namespace osu.Game
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using (var db = contextFactory.GetForWrite())
|
using (var db = contextFactory.GetForWrite(false))
|
||||||
db.Context.Migrate();
|
db.Context.Migrate();
|
||||||
}
|
}
|
||||||
catch (MigrationFailedException e)
|
catch (MigrationFailedException e)
|
||||||
@ -220,7 +220,7 @@ namespace osu.Game
|
|||||||
contextFactory.ResetDatabase();
|
contextFactory.ResetDatabase();
|
||||||
Logger.Log("Database purged successfully.", LoggingTarget.Database, LogLevel.Important);
|
Logger.Log("Database purged successfully.", LoggingTarget.Database, LogLevel.Important);
|
||||||
|
|
||||||
using (var db = contextFactory.GetForWrite())
|
using (var db = contextFactory.GetForWrite(false))
|
||||||
db.Context.Migrate();
|
db.Context.Migrate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,8 +49,8 @@ namespace osu.Game.Overlays.BeatmapSet
|
|||||||
|
|
||||||
fields.Children = new Drawable[]
|
fields.Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new Field("made by", BeatmapSet.Metadata.Author.Username, @"Exo2.0-RegularItalic"),
|
new Field("mapped by", BeatmapSet.Metadata.Author.Username, @"Exo2.0-RegularItalic"),
|
||||||
new Field("submitted on", online.Submitted.ToString(@"MMM d, yyyy"), @"Exo2.0-Bold")
|
new Field("submitted on", online.Submitted.ToString(@"MMMM d, yyyy"), @"Exo2.0-Bold")
|
||||||
{
|
{
|
||||||
Margin = new MarginPadding { Top = 5 },
|
Margin = new MarginPadding { Top = 5 },
|
||||||
},
|
},
|
||||||
@ -58,11 +58,11 @@ namespace osu.Game.Overlays.BeatmapSet
|
|||||||
|
|
||||||
if (online.Ranked.HasValue)
|
if (online.Ranked.HasValue)
|
||||||
{
|
{
|
||||||
fields.Add(new Field("ranked on ", online.Ranked.Value.ToString(@"MMM d, yyyy"), @"Exo2.0-Bold"));
|
fields.Add(new Field("ranked on", online.Ranked.Value.ToString(@"MMMM d, yyyy"), @"Exo2.0-Bold"));
|
||||||
}
|
}
|
||||||
else if (online.LastUpdated.HasValue)
|
else if (online.LastUpdated.HasValue)
|
||||||
{
|
{
|
||||||
fields.Add(new Field("last updated on ", online.LastUpdated.Value.ToString(@"MMM d, yyyy"), @"Exo2.0-Bold"));
|
fields.Add(new Field("last updated on", online.LastUpdated.Value.ToString(@"MMMM d, yyyy"), @"Exo2.0-Bold"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,8 +61,8 @@ namespace osu.Game.Overlays.BeatmapSet
|
|||||||
title.Text = BeatmapSet?.Metadata.Title ?? string.Empty;
|
title.Text = BeatmapSet?.Metadata.Title ?? string.Empty;
|
||||||
artist.Text = BeatmapSet?.Metadata.Artist ?? string.Empty;
|
artist.Text = BeatmapSet?.Metadata.Artist ?? string.Empty;
|
||||||
onlineStatusPill.Status = BeatmapSet?.OnlineInfo.Status ?? BeatmapSetOnlineStatus.None;
|
onlineStatusPill.Status = BeatmapSet?.OnlineInfo.Status ?? BeatmapSetOnlineStatus.None;
|
||||||
|
cover.BeatmapSet = BeatmapSet;
|
||||||
|
|
||||||
cover.BeatmapSet = null;
|
|
||||||
if (BeatmapSet != null)
|
if (BeatmapSet != null)
|
||||||
{
|
{
|
||||||
downloadButtonsContainer.FadeIn(transition_duration);
|
downloadButtonsContainer.FadeIn(transition_duration);
|
||||||
@ -70,8 +70,6 @@ namespace osu.Game.Overlays.BeatmapSet
|
|||||||
|
|
||||||
noVideoButtons.FadeTo(BeatmapSet.OnlineInfo.HasVideo ? 0 : 1, transition_duration);
|
noVideoButtons.FadeTo(BeatmapSet.OnlineInfo.HasVideo ? 0 : 1, transition_duration);
|
||||||
videoButtons.FadeTo(BeatmapSet.OnlineInfo.HasVideo ? 1 : 0, transition_duration);
|
videoButtons.FadeTo(BeatmapSet.OnlineInfo.HasVideo ? 1 : 0, transition_duration);
|
||||||
|
|
||||||
cover.BeatmapSet = BeatmapSet;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -31,7 +31,7 @@ namespace osu.Game.Overlays.Mods
|
|||||||
protected Color4 LowMultiplierColour, HighMultiplierColour;
|
protected Color4 LowMultiplierColour, HighMultiplierColour;
|
||||||
|
|
||||||
protected readonly TriangleButton DeselectAllButton;
|
protected readonly TriangleButton DeselectAllButton;
|
||||||
protected readonly OsuSpriteText MultiplierLabel;
|
protected readonly OsuSpriteText MultiplierLabel, UnrankedLabel;
|
||||||
private readonly FillFlowContainer footerContainer;
|
private readonly FillFlowContainer footerContainer;
|
||||||
|
|
||||||
protected override bool BlockPassThroughKeyboard => false;
|
protected override bool BlockPassThroughKeyboard => false;
|
||||||
@ -58,6 +58,7 @@ namespace osu.Game.Overlays.Mods
|
|||||||
|
|
||||||
LowMultiplierColour = colours.Red;
|
LowMultiplierColour = colours.Red;
|
||||||
HighMultiplierColour = colours.Green;
|
HighMultiplierColour = colours.Green;
|
||||||
|
UnrankedLabel.Colour = colours.Blue;
|
||||||
|
|
||||||
if (osu != null)
|
if (osu != null)
|
||||||
Ruleset.BindTo(osu.Ruleset);
|
Ruleset.BindTo(osu.Ruleset);
|
||||||
@ -99,15 +100,14 @@ namespace osu.Game.Overlays.Mods
|
|||||||
}
|
}
|
||||||
|
|
||||||
MultiplierLabel.Text = $"{multiplier:N2}x";
|
MultiplierLabel.Text = $"{multiplier:N2}x";
|
||||||
if (!ranked)
|
|
||||||
MultiplierLabel.Text += " (Unranked)";
|
|
||||||
|
|
||||||
if (multiplier > 1.0)
|
if (multiplier > 1.0)
|
||||||
MultiplierLabel.FadeColour(HighMultiplierColour, 200);
|
MultiplierLabel.FadeColour(HighMultiplierColour, 200);
|
||||||
else if (multiplier < 1.0)
|
else if (multiplier < 1.0)
|
||||||
MultiplierLabel.FadeColour(LowMultiplierColour, 200);
|
MultiplierLabel.FadeColour(LowMultiplierColour, 200);
|
||||||
else
|
else
|
||||||
MultiplierLabel.FadeColour(Color4.White, 200);
|
MultiplierLabel.FadeColour(Color4.White, 200);
|
||||||
|
|
||||||
|
UnrankedLabel.FadeTo(ranked ? 0 : 1, 200);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void PopOut()
|
protected override void PopOut()
|
||||||
@ -352,23 +352,33 @@ namespace osu.Game.Overlays.Mods
|
|||||||
},
|
},
|
||||||
new OsuSpriteText
|
new OsuSpriteText
|
||||||
{
|
{
|
||||||
Text = @"Score Multiplier: ",
|
Text = @"Score Multiplier:",
|
||||||
TextSize = 30,
|
TextSize = 30,
|
||||||
Shadow = true,
|
|
||||||
Margin = new MarginPadding
|
Margin = new MarginPadding
|
||||||
{
|
{
|
||||||
Top = 5
|
Top = 5,
|
||||||
|
Right = 10
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
MultiplierLabel = new OsuSpriteText
|
MultiplierLabel = new OsuSpriteText
|
||||||
{
|
{
|
||||||
Font = @"Exo2.0-Bold",
|
Font = @"Exo2.0-Bold",
|
||||||
TextSize = 30,
|
TextSize = 30,
|
||||||
Shadow = true,
|
|
||||||
Margin = new MarginPadding
|
Margin = new MarginPadding
|
||||||
{
|
{
|
||||||
Top = 5
|
Top = 5
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
UnrankedLabel = new OsuSpriteText
|
||||||
|
{
|
||||||
|
Font = @"Exo2.0-Bold",
|
||||||
|
Text = @"(Unranked)",
|
||||||
|
TextSize = 30,
|
||||||
|
Margin = new MarginPadding
|
||||||
|
{
|
||||||
|
Top = 5,
|
||||||
|
Left = 10
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,7 @@ namespace osu.Game.Rulesets.Mods
|
|||||||
public override string ShortenedName => "AT";
|
public override string ShortenedName => "AT";
|
||||||
public override FontAwesome Icon => FontAwesome.fa_osu_mod_auto;
|
public override FontAwesome Icon => FontAwesome.fa_osu_mod_auto;
|
||||||
public override string Description => "Watch a perfect automated play through the song.";
|
public override string Description => "Watch a perfect automated play through the song.";
|
||||||
public override double ScoreMultiplier => 0;
|
public override double ScoreMultiplier => 1;
|
||||||
public bool AllowFail => false;
|
public bool AllowFail => false;
|
||||||
public override Type[] IncompatibleMods => new[] { typeof(ModRelax), typeof(ModSuddenDeath), typeof(ModNoFail) };
|
public override Type[] IncompatibleMods => new[] { typeof(ModRelax), typeof(ModSuddenDeath), typeof(ModNoFail) };
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ namespace osu.Game.Rulesets.Mods
|
|||||||
public override string Name => "Relax";
|
public override string Name => "Relax";
|
||||||
public override string ShortenedName => "RX";
|
public override string ShortenedName => "RX";
|
||||||
public override FontAwesome Icon => FontAwesome.fa_osu_mod_relax;
|
public override FontAwesome Icon => FontAwesome.fa_osu_mod_relax;
|
||||||
public override double ScoreMultiplier => 0;
|
public override double ScoreMultiplier => 1;
|
||||||
public override Type[] IncompatibleMods => new[] { typeof(ModAutoplay), typeof(ModNoFail), typeof(ModSuddenDeath) };
|
public override Type[] IncompatibleMods => new[] { typeof(ModAutoplay), typeof(ModNoFail), typeof(ModSuddenDeath) };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -254,9 +254,6 @@ namespace osu.Game.Screens.Menu
|
|||||||
backButton.ContractStyle = 0;
|
backButton.ContractStyle = 0;
|
||||||
settingsButton.ContractStyle = 0;
|
settingsButton.ContractStyle = 0;
|
||||||
|
|
||||||
if (state == MenuState.TopLevel)
|
|
||||||
buttonArea.FinishTransforms(true);
|
|
||||||
|
|
||||||
updateLogoState(lastState);
|
updateLogoState(lastState);
|
||||||
|
|
||||||
using (buttonArea.BeginDelayedSequence(lastState == MenuState.Initial ? 150 : 0, true))
|
using (buttonArea.BeginDelayedSequence(lastState == MenuState.Initial ? 150 : 0, true))
|
||||||
@ -325,16 +322,15 @@ namespace osu.Game.Screens.Menu
|
|||||||
{
|
{
|
||||||
if (logo == null) return;
|
if (logo == null) return;
|
||||||
|
|
||||||
logoDelayedAction?.Cancel();
|
|
||||||
|
|
||||||
switch (state)
|
switch (state)
|
||||||
{
|
{
|
||||||
case MenuState.Exit:
|
case MenuState.Exit:
|
||||||
case MenuState.Initial:
|
case MenuState.Initial:
|
||||||
logoTracking = false;
|
logoDelayedAction?.Cancel();
|
||||||
|
|
||||||
logoDelayedAction = Scheduler.AddDelayed(() =>
|
logoDelayedAction = Scheduler.AddDelayed(() =>
|
||||||
{
|
{
|
||||||
|
logoTracking = false;
|
||||||
|
|
||||||
hideOverlaysOnEnter.Value = true;
|
hideOverlaysOnEnter.Value = true;
|
||||||
allowOpeningOverlays.Value = false;
|
allowOpeningOverlays.Value = false;
|
||||||
|
|
||||||
@ -343,34 +339,40 @@ namespace osu.Game.Screens.Menu
|
|||||||
|
|
||||||
logo.MoveTo(new Vector2(0.5f), 800, Easing.OutExpo);
|
logo.MoveTo(new Vector2(0.5f), 800, Easing.OutExpo);
|
||||||
logo.ScaleTo(1, 800, Easing.OutExpo);
|
logo.ScaleTo(1, 800, Easing.OutExpo);
|
||||||
}, 150);
|
}, buttonArea.Alpha * 150);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case MenuState.TopLevel:
|
case MenuState.TopLevel:
|
||||||
case MenuState.Play:
|
case MenuState.Play:
|
||||||
logo.ClearTransforms(targetMember: nameof(Position));
|
|
||||||
logo.RelativePositionAxes = Axes.None;
|
|
||||||
|
|
||||||
switch (lastState)
|
switch (lastState)
|
||||||
{
|
{
|
||||||
case MenuState.TopLevel: // coming from toplevel to play
|
case MenuState.TopLevel: // coming from toplevel to play
|
||||||
|
break;
|
||||||
case MenuState.Initial:
|
case MenuState.Initial:
|
||||||
logoTracking = false;
|
logo.ClearTransforms(targetMember: nameof(Position));
|
||||||
logo.ScaleTo(0.5f, 200, Easing.In);
|
logo.RelativePositionAxes = Axes.None;
|
||||||
|
|
||||||
|
bool impact = logo.Scale.X > 0.6f;
|
||||||
|
|
||||||
|
if (lastState == MenuState.Initial)
|
||||||
|
logo.ScaleTo(0.5f, 200, Easing.In);
|
||||||
|
|
||||||
logo.MoveTo(logoTrackingPosition, lastState == MenuState.EnteringMode ? 0 : 200, Easing.In);
|
logo.MoveTo(logoTrackingPosition, lastState == MenuState.EnteringMode ? 0 : 200, Easing.In);
|
||||||
|
|
||||||
|
logoDelayedAction?.Cancel();
|
||||||
logoDelayedAction = Scheduler.AddDelayed(() =>
|
logoDelayedAction = Scheduler.AddDelayed(() =>
|
||||||
{
|
{
|
||||||
logoTracking = true;
|
logoTracking = true;
|
||||||
|
|
||||||
logo.Impact();
|
if (impact)
|
||||||
|
logo.Impact();
|
||||||
|
|
||||||
hideOverlaysOnEnter.Value = false;
|
hideOverlaysOnEnter.Value = false;
|
||||||
allowOpeningOverlays.Value = true;
|
allowOpeningOverlays.Value = true;
|
||||||
}, 200);
|
}, 200);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
logo.ClearTransforms(targetMember: nameof(Position));
|
||||||
|
logo.RelativePositionAxes = Axes.None;
|
||||||
logoTracking = true;
|
logoTracking = true;
|
||||||
logo.ScaleTo(0.5f, 200, Easing.OutQuint);
|
logo.ScaleTo(0.5f, 200, Easing.OutQuint);
|
||||||
break;
|
break;
|
||||||
|
@ -22,6 +22,7 @@ namespace osu.Game.Screens.Multi.Components
|
|||||||
}
|
}
|
||||||
|
|
||||||
private BeatmapInfo beatmap;
|
private BeatmapInfo beatmap;
|
||||||
|
|
||||||
public BeatmapInfo Beatmap
|
public BeatmapInfo Beatmap
|
||||||
{
|
{
|
||||||
set
|
set
|
||||||
@ -41,18 +42,9 @@ namespace osu.Game.Screens.Multi.Components
|
|||||||
|
|
||||||
Children = new[]
|
Children = new[]
|
||||||
{
|
{
|
||||||
beatmapTitle = new OsuSpriteText
|
beatmapTitle = new OsuSpriteText { Font = @"Exo2.0-BoldItalic", },
|
||||||
{
|
beatmapDash = new OsuSpriteText { Font = @"Exo2.0-BoldItalic", },
|
||||||
Font = @"Exo2.0-BoldItalic",
|
beatmapArtist = new OsuSpriteText { Font = @"Exo2.0-RegularItalic", },
|
||||||
},
|
|
||||||
beatmapDash = new OsuSpriteText
|
|
||||||
{
|
|
||||||
Font = @"Exo2.0-BoldItalic",
|
|
||||||
},
|
|
||||||
beatmapArtist = new OsuSpriteText
|
|
||||||
{
|
|
||||||
Font = @"Exo2.0-RegularItalic",
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,7 +57,6 @@ namespace osu.Game.Screens.Multi.Components
|
|||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
|
|
||||||
updateText();
|
updateText();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,7 +65,6 @@ namespace osu.Game.Screens.Multi.Components
|
|||||||
if (beatmap == null)
|
if (beatmap == null)
|
||||||
{
|
{
|
||||||
beatmapTitle.Current = beatmapArtist.Current = null;
|
beatmapTitle.Current = beatmapArtist.Current = null;
|
||||||
|
|
||||||
beatmapTitle.Text = "Changing map";
|
beatmapTitle.Text = "Changing map";
|
||||||
beatmapDash.Text = beatmapArtist.Text = string.Empty;
|
beatmapDash.Text = beatmapArtist.Text = string.Empty;
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ namespace osu.Game.Screens.Multi.Components
|
|||||||
|
|
||||||
public int Count
|
public int Count
|
||||||
{
|
{
|
||||||
set { count.Text = value.ToString(); }
|
set => count.Text = value.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int? Max
|
public int? Max
|
||||||
@ -31,8 +31,8 @@ namespace osu.Game.Screens.Multi.Components
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
slash.FadeIn(transition_duration);
|
slash.FadeIn(transition_duration);
|
||||||
max.FadeIn(transition_duration);
|
|
||||||
max.Text = value.ToString();
|
max.Text = value.ToString();
|
||||||
|
max.FadeIn(transition_duration);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ namespace osu.Game.Screens.Multi
|
|||||||
{
|
{
|
||||||
public const float HEIGHT = 121;
|
public const float HEIGHT = 121;
|
||||||
|
|
||||||
private readonly OsuSpriteText screenTitle;
|
private readonly OsuSpriteText screenType;
|
||||||
private readonly HeaderBreadcrumbControl breadcrumbs;
|
private readonly HeaderBreadcrumbControl breadcrumbs;
|
||||||
|
|
||||||
public Header(Screen initialScreen)
|
public Header(Screen initialScreen)
|
||||||
@ -67,7 +67,7 @@ namespace osu.Game.Screens.Multi
|
|||||||
Text = "multiplayer ",
|
Text = "multiplayer ",
|
||||||
TextSize = 25,
|
TextSize = 25,
|
||||||
},
|
},
|
||||||
screenTitle = new OsuSpriteText
|
screenType = new OsuSpriteText
|
||||||
{
|
{
|
||||||
TextSize = 25,
|
TextSize = 25,
|
||||||
Font = @"Exo2.0-Light",
|
Font = @"Exo2.0-Light",
|
||||||
@ -86,14 +86,14 @@ namespace osu.Game.Screens.Multi
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
breadcrumbs.Current.ValueChanged += s => screenTitle.Text = ((MultiplayerScreen)s).Title;
|
breadcrumbs.Current.ValueChanged += s => screenType.Text = ((MultiplayerScreen)s).Type.ToLower();
|
||||||
breadcrumbs.Current.TriggerChange();
|
breadcrumbs.Current.TriggerChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuColour colours)
|
private void load(OsuColour colours)
|
||||||
{
|
{
|
||||||
screenTitle.Colour = colours.Yellow;
|
screenType.Colour = colours.Yellow;
|
||||||
breadcrumbs.StripColour = colours.Green;
|
breadcrumbs.StripColour = colours.Green;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ namespace osu.Game.Screens.Multi.Screens.Lounge
|
|||||||
protected readonly FillFlowContainer<DrawableRoom> RoomsContainer;
|
protected readonly FillFlowContainer<DrawableRoom> RoomsContainer;
|
||||||
protected readonly RoomInspector Inspector;
|
protected readonly RoomInspector Inspector;
|
||||||
|
|
||||||
public override string Title => "lounge";
|
public override string Title => "Lounge";
|
||||||
|
|
||||||
protected override Container<Drawable> TransitionContent => content;
|
protected override Container<Drawable> TransitionContent => content;
|
||||||
|
|
||||||
|
@ -15,6 +15,11 @@ namespace osu.Game.Screens.Multi.Screens
|
|||||||
|
|
||||||
protected virtual Container<Drawable> TransitionContent => Content;
|
protected virtual Container<Drawable> TransitionContent => Content;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The type to display in the title of the <see cref="Header"/>.
|
||||||
|
/// </summary>
|
||||||
|
public virtual string Type => Title;
|
||||||
|
|
||||||
protected override void OnEntering(Screen last)
|
protected override void OnEntering(Screen last)
|
||||||
{
|
{
|
||||||
base.OnEntering(last);
|
base.OnEntering(last);
|
||||||
|
@ -231,7 +231,10 @@ namespace osu.Game.Screens
|
|||||||
|
|
||||||
private void applyArrivingDefaults(bool isResuming)
|
private void applyArrivingDefaults(bool isResuming)
|
||||||
{
|
{
|
||||||
logo.AppendAnimatingAction(() => LogoArriving(logo, isResuming), true);
|
logo.AppendAnimatingAction(() =>
|
||||||
|
{
|
||||||
|
if (IsCurrentScreen) LogoArriving(logo, isResuming);
|
||||||
|
}, true);
|
||||||
|
|
||||||
if (backgroundParallaxContainer != null)
|
if (backgroundParallaxContainer != null)
|
||||||
backgroundParallaxContainer.ParallaxAmount = ParallaxContainer.DEFAULT_PARALLAX_AMOUNT * BackgroundParallaxAmount;
|
backgroundParallaxContainer.ParallaxAmount = ParallaxContainer.DEFAULT_PARALLAX_AMOUNT * BackgroundParallaxAmount;
|
||||||
|
@ -209,8 +209,11 @@ namespace osu.Game.Screens.Play
|
|||||||
{
|
{
|
||||||
base.Dispose(isDisposing);
|
base.Dispose(isDisposing);
|
||||||
|
|
||||||
// if the player never got pushed, we should explicitly dispose it.
|
if (isDisposing)
|
||||||
loadTask?.ContinueWith(_ => player.Dispose());
|
{
|
||||||
|
// if the player never got pushed, we should explicitly dispose it.
|
||||||
|
loadTask?.ContinueWith(_ => player.Dispose());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class BeatmapMetadataDisplay : Container
|
private class BeatmapMetadataDisplay : Container
|
||||||
|
@ -57,6 +57,7 @@ namespace osu.Game.Screens.Ranking
|
|||||||
{
|
{
|
||||||
base.OnEntering(last);
|
base.OnEntering(last);
|
||||||
(Background as BackgroundScreenBeatmap)?.BlurTo(background_blur, 2500, Easing.OutQuint);
|
(Background as BackgroundScreenBeatmap)?.BlurTo(background_blur, 2500, Easing.OutQuint);
|
||||||
|
Background.ScaleTo(1.1f, transition_time, Easing.OutQuint);
|
||||||
|
|
||||||
allCircles.ForEach(c =>
|
allCircles.ForEach(c =>
|
||||||
{
|
{
|
||||||
@ -102,6 +103,8 @@ namespace osu.Game.Screens.Ranking
|
|||||||
c.ScaleTo(0, transition_time, Easing.OutSine);
|
c.ScaleTo(0, transition_time, Easing.OutSine);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Background.ScaleTo(1f, transition_time / 4, Easing.OutQuint);
|
||||||
|
|
||||||
Content.FadeOut(transition_time / 4);
|
Content.FadeOut(transition_time / 4);
|
||||||
|
|
||||||
return base.OnExiting(next);
|
return base.OnExiting(next);
|
||||||
@ -160,7 +163,6 @@ namespace osu.Game.Screens.Ranking
|
|||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
ParallaxAmount = 0.01f,
|
ParallaxAmount = 0.01f,
|
||||||
Scale = new Vector2(1 / circle_outer_scale / overscan),
|
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
|
@ -51,7 +51,7 @@ namespace osu.Game.Screens.Select.Carousel
|
|||||||
|
|
||||||
if (songSelect != null)
|
if (songSelect != null)
|
||||||
{
|
{
|
||||||
startRequested = songSelect.FinaliseSelection;
|
startRequested = b => songSelect.FinaliseSelection(b);
|
||||||
editRequested = songSelect.Edit;
|
editRequested = songSelect.Edit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ namespace osu.Game.Screens.Select
|
|||||||
{
|
{
|
||||||
protected override bool ShowFooter => false;
|
protected override bool ShowFooter => false;
|
||||||
|
|
||||||
protected override bool OnSelectionFinalised()
|
protected override bool OnStart()
|
||||||
{
|
{
|
||||||
Exit();
|
Exit();
|
||||||
return true;
|
return true;
|
||||||
|
@ -5,7 +5,7 @@ namespace osu.Game.Screens.Select
|
|||||||
{
|
{
|
||||||
public class MatchSongSelect : SongSelect
|
public class MatchSongSelect : SongSelect
|
||||||
{
|
{
|
||||||
protected override bool OnSelectionFinalised()
|
protected override bool OnStart()
|
||||||
{
|
{
|
||||||
Schedule(() =>
|
Schedule(() =>
|
||||||
{
|
{
|
||||||
|
@ -137,7 +137,7 @@ namespace osu.Game.Screens.Select
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnSelectionFinalised()
|
protected override bool OnStart()
|
||||||
{
|
{
|
||||||
if (player != null) return false;
|
if (player != null) return false;
|
||||||
|
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Threading;
|
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Input;
|
using OpenTK.Input;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
@ -63,8 +62,6 @@ namespace osu.Game.Screens.Select
|
|||||||
private SampleChannel sampleChangeDifficulty;
|
private SampleChannel sampleChangeDifficulty;
|
||||||
private SampleChannel sampleChangeBeatmap;
|
private SampleChannel sampleChangeBeatmap;
|
||||||
|
|
||||||
private CancellationTokenSource initialAddSetsTask;
|
|
||||||
|
|
||||||
private DependencyContainer dependencies;
|
private DependencyContainer dependencies;
|
||||||
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent) => dependencies = new DependencyContainer(parent);
|
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent) => dependencies = new DependencyContainer(parent);
|
||||||
|
|
||||||
@ -207,9 +204,7 @@ namespace osu.Game.Screens.Select
|
|||||||
sampleChangeDifficulty = audio.Sample.Get(@"SongSelect/select-difficulty");
|
sampleChangeDifficulty = audio.Sample.Get(@"SongSelect/select-difficulty");
|
||||||
sampleChangeBeatmap = audio.Sample.Get(@"SongSelect/select-expand");
|
sampleChangeBeatmap = audio.Sample.Get(@"SongSelect/select-expand");
|
||||||
|
|
||||||
initialAddSetsTask = new CancellationTokenSource();
|
Carousel.BeatmapSets = this.beatmaps.GetAllUsableBeatmapSetsEnumerable();
|
||||||
|
|
||||||
Carousel.BeatmapSets = this.beatmaps.GetAllUsableBeatmapSets();
|
|
||||||
|
|
||||||
Beatmap.DisabledChanged += disabled => Carousel.AllowSelection = !disabled;
|
Beatmap.DisabledChanged += disabled => Carousel.AllowSelection = !disabled;
|
||||||
Beatmap.TriggerChange();
|
Beatmap.TriggerChange();
|
||||||
@ -227,7 +222,8 @@ namespace osu.Game.Screens.Select
|
|||||||
/// Call to make a selection and perform the default action for this SongSelect.
|
/// Call to make a selection and perform the default action for this SongSelect.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="beatmap">An optional beatmap to override the current carousel selection.</param>
|
/// <param name="beatmap">An optional beatmap to override the current carousel selection.</param>
|
||||||
public void FinaliseSelection(BeatmapInfo beatmap = null)
|
/// <param name="performStartAction">Whether to trigger <see cref="OnStart"/>.</param>
|
||||||
|
public void FinaliseSelection(BeatmapInfo beatmap = null, bool performStartAction = true)
|
||||||
{
|
{
|
||||||
// if we have a pending filter operation, we want to run it now.
|
// if we have a pending filter operation, we want to run it now.
|
||||||
// it could change selection (ie. if the ruleset has been changed).
|
// it could change selection (ie. if the ruleset has been changed).
|
||||||
@ -243,14 +239,15 @@ namespace osu.Game.Screens.Select
|
|||||||
selectionChangedDebounce = null;
|
selectionChangedDebounce = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
OnSelectionFinalised();
|
if (performStartAction)
|
||||||
|
OnStart();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Called when a selection is made.
|
/// Called when a selection is made.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>If a resultant action occurred that takes the user away from SongSelect.</returns>
|
/// <returns>If a resultant action occurred that takes the user away from SongSelect.</returns>
|
||||||
protected abstract bool OnSelectionFinalised();
|
protected abstract bool OnStart();
|
||||||
|
|
||||||
private ScheduledDelegate selectionChangedDebounce;
|
private ScheduledDelegate selectionChangedDebounce;
|
||||||
|
|
||||||
@ -395,7 +392,7 @@ namespace osu.Game.Screens.Select
|
|||||||
|
|
||||||
protected override bool OnExiting(Screen next)
|
protected override bool OnExiting(Screen next)
|
||||||
{
|
{
|
||||||
FinaliseSelection();
|
FinaliseSelection(performStartAction: false);
|
||||||
|
|
||||||
beatmapInfoWedge.State = Visibility.Hidden;
|
beatmapInfoWedge.State = Visibility.Hidden;
|
||||||
|
|
||||||
@ -417,8 +414,6 @@ namespace osu.Game.Screens.Select
|
|||||||
beatmaps.BeatmapHidden -= onBeatmapHidden;
|
beatmaps.BeatmapHidden -= onBeatmapHidden;
|
||||||
beatmaps.BeatmapRestored -= onBeatmapRestored;
|
beatmaps.BeatmapRestored -= onBeatmapRestored;
|
||||||
}
|
}
|
||||||
|
|
||||||
initialAddSetsTask?.Cancel();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
<ItemGroup Label="Package References">
|
<ItemGroup Label="Package References">
|
||||||
<PackageReference Include="Humanizer" Version="2.2.0" />
|
<PackageReference Include="Humanizer" Version="2.2.0" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.0.1" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.0.1" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.0.1" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.0.3" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
|
||||||
<PackageReference Include="SharpCompress" Version="0.18.1" />
|
<PackageReference Include="SharpCompress" Version="0.18.1" />
|
||||||
<PackageReference Include="NUnit" Version="3.10.1" />
|
<PackageReference Include="NUnit" Version="3.10.1" />
|
||||||
|
Loading…
Reference in New Issue
Block a user