mirror of
https://github.com/ppy/osu.git
synced 2024-12-14 14:32:55 +08:00
Merge branch 'master' into realm-key-binding-store
This commit is contained in:
commit
66efc3c4de
@ -2,12 +2,6 @@
|
||||
"version": 1,
|
||||
"isRoot": true,
|
||||
"tools": {
|
||||
"cake.tool": {
|
||||
"version": "0.35.0",
|
||||
"commands": [
|
||||
"dotnet-cake"
|
||||
]
|
||||
},
|
||||
"dotnet-format": {
|
||||
"version": "3.1.37601",
|
||||
"commands": [
|
||||
@ -27,7 +21,7 @@
|
||||
]
|
||||
},
|
||||
"codefilesanity": {
|
||||
"version": "15.0.0",
|
||||
"version": "0.0.36",
|
||||
"commands": [
|
||||
"CodeFileSanity"
|
||||
]
|
||||
@ -39,4 +33,4 @@
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
14
.vscode/launch.json
vendored
14
.vscode/launch.json
vendored
@ -113,20 +113,6 @@
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build benchmarks",
|
||||
"console": "internalConsole"
|
||||
},
|
||||
{
|
||||
"name": "Cake: Debug Script",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"program": "${workspaceRoot}/build/tools/Cake.CoreCLR/0.30.0/Cake.dll",
|
||||
"args": [
|
||||
"${workspaceRoot}/build/build.cake",
|
||||
"--debug",
|
||||
"--verbosity=diagnostic"
|
||||
],
|
||||
"cwd": "${workspaceRoot}/build",
|
||||
"stopAtEntry": true,
|
||||
"externalConsole": false
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -1,27 +1,11 @@
|
||||
[CmdletBinding()]
|
||||
Param(
|
||||
[string]$Target,
|
||||
[string]$Configuration,
|
||||
[ValidateSet("Quiet", "Minimal", "Normal", "Verbose", "Diagnostic")]
|
||||
[string]$Verbosity,
|
||||
[switch]$ShowDescription,
|
||||
[Alias("WhatIf", "Noop")]
|
||||
[switch]$DryRun,
|
||||
[Parameter(Position = 0, Mandatory = $false, ValueFromRemainingArguments = $true)]
|
||||
[string[]]$ScriptArgs
|
||||
)
|
||||
|
||||
# Build Cake arguments
|
||||
$cakeArguments = "";
|
||||
if ($Target) { $cakeArguments += "-target=$Target" }
|
||||
if ($Configuration) { $cakeArguments += "-configuration=$Configuration" }
|
||||
if ($Verbosity) { $cakeArguments += "-verbosity=$Verbosity" }
|
||||
if ($ShowDescription) { $cakeArguments += "-showdescription" }
|
||||
if ($DryRun) { $cakeArguments += "-dryrun" }
|
||||
if ($Experimental) { $cakeArguments += "-experimental" }
|
||||
$cakeArguments += $ScriptArgs
|
||||
|
||||
dotnet tool restore
|
||||
dotnet cake ./build/InspectCode.cake --bootstrap
|
||||
dotnet cake ./build/InspectCode.cake $cakeArguments
|
||||
exit $LASTEXITCODE
|
||||
|
||||
# Temporarily disabled until the tool is upgraded to 5.0.
|
||||
# The version specified in .config/dotnet-tools.json (3.1.37601) won't run on .NET hosts >=5.0.7.
|
||||
# - cmd: dotnet format --dry-run --check
|
||||
|
||||
dotnet CodeFileSanity
|
||||
dotnet jb inspectcode "osu.Desktop.slnf" --output="inspectcodereport.xml" --caches-home="inspectcode" --verbosity=WARN
|
||||
dotnet nvika parsereport "inspectcodereport.xml" --treatwarningsaserrors
|
||||
|
||||
exit $LASTEXITCODE
|
||||
|
6
InspectCode.sh
Executable file
6
InspectCode.sh
Executable file
@ -0,0 +1,6 @@
|
||||
#!/bin/bash
|
||||
|
||||
dotnet tool restore
|
||||
dotnet CodeFileSanity
|
||||
dotnet jb inspectcode "osu.Desktop.slnf" --output="inspectcodereport.xml" --caches-home="inspectcode" --verbosity=WARN
|
||||
dotnet nvika parsereport "inspectcodereport.xml" --treatwarningsaserrors
|
15
appveyor.yml
15
appveyor.yml
@ -1,24 +1,27 @@
|
||||
clone_depth: 1
|
||||
version: '{branch}-{build}'
|
||||
image: Visual Studio 2019
|
||||
cache:
|
||||
- '%LOCALAPPDATA%\NuGet\v3-cache -> appveyor.yml'
|
||||
|
||||
dotnet_csproj:
|
||||
patch: true
|
||||
file: 'osu.Game\osu.Game.csproj' # Use wildcard when it's able to exclude Xamarin projects
|
||||
version: '0.0.{build}'
|
||||
cache:
|
||||
- '%LOCALAPPDATA%\NuGet\v3-cache -> appveyor.yml'
|
||||
|
||||
before_build:
|
||||
- ps: dotnet --info # Useful when version mismatch between CI and local
|
||||
- ps: nuget restore -verbosity quiet # Only nuget.exe knows both new (.NET Core) and old (Xamarin) projects
|
||||
- cmd: dotnet --info # Useful when version mismatch between CI and local
|
||||
- cmd: nuget restore -verbosity quiet # Only nuget.exe knows both new (.NET Core) and old (Xamarin) projects
|
||||
|
||||
build:
|
||||
project: osu.sln
|
||||
parallel: true
|
||||
verbosity: minimal
|
||||
publish_nuget: true
|
||||
|
||||
after_build:
|
||||
- ps: dotnet tool restore
|
||||
- ps: dotnet format --dry-run --check
|
||||
- ps: .\InspectCode.ps1
|
||||
|
||||
test:
|
||||
assemblies:
|
||||
except:
|
||||
|
@ -1,17 +0,0 @@
|
||||
<Project Sdk="Microsoft.Build.Traversal">
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\osu.Desktop\osu.Desktop.csproj" />
|
||||
<ProjectReference Include="..\osu.Game.Rulesets.Catch.Tests\osu.Game.Rulesets.Catch.Tests.csproj" />
|
||||
<ProjectReference Include="..\osu.Game.Rulesets.Catch\osu.Game.Rulesets.Catch.csproj" />
|
||||
<ProjectReference Include="..\osu.Game.Rulesets.Mania.Tests\osu.Game.Rulesets.Mania.Tests.csproj" />
|
||||
<ProjectReference Include="..\osu.Game.Rulesets.Mania\osu.Game.Rulesets.Mania.csproj" />
|
||||
<ProjectReference Include="..\osu.Game.Rulesets.Osu.Tests\osu.Game.Rulesets.Osu.Tests.csproj" />
|
||||
<ProjectReference Include="..\osu.Game.Rulesets.Osu\osu.Game.Rulesets.Osu.csproj" />
|
||||
<ProjectReference Include="..\osu.Game.Rulesets.Taiko.Tests\osu.Game.Rulesets.Taiko.Tests.csproj" />
|
||||
<ProjectReference Include="..\osu.Game.Rulesets.Taiko\osu.Game.Rulesets.Taiko.csproj" />
|
||||
<ProjectReference Include="..\osu.Game.Tests\osu.Game.Tests.csproj" />
|
||||
<ProjectReference Include="..\osu.Game.Tournament.Tests\osu.Game.Tournament.Tests.csproj" />
|
||||
<ProjectReference Include="..\osu.Game.Tournament\osu.Game.Tournament.csproj" />
|
||||
<ProjectReference Include="..\osu.Game\osu.Game.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
@ -1,41 +0,0 @@
|
||||
#addin "nuget:?package=CodeFileSanity&version=0.0.36"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// ARGUMENTS
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
var target = Argument("target", "CodeAnalysis");
|
||||
var configuration = Argument("configuration", "Release");
|
||||
|
||||
var rootDirectory = new DirectoryPath("..");
|
||||
var sln = rootDirectory.CombineWithFilePath("osu.sln");
|
||||
var desktopSlnf = rootDirectory.CombineWithFilePath("osu.Desktop.slnf");
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// TASKS
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Task("InspectCode")
|
||||
.Does(() => {
|
||||
var inspectcodereport = "inspectcodereport.xml";
|
||||
var cacheDir = "inspectcode";
|
||||
var verbosity = AppVeyor.IsRunningOnAppVeyor ? "WARN" : "INFO"; // Don't flood CI output
|
||||
|
||||
DotNetCoreTool(rootDirectory.FullPath,
|
||||
"jb", $@"inspectcode ""{desktopSlnf}"" --output=""{inspectcodereport}"" --caches-home=""{cacheDir}"" --verbosity={verbosity}");
|
||||
DotNetCoreTool(rootDirectory.FullPath, "nvika", $@"parsereport ""{inspectcodereport}"" --treatwarningsaserrors");
|
||||
});
|
||||
|
||||
Task("CodeFileSanity")
|
||||
.Does(() => {
|
||||
ValidateCodeSanity(new ValidateCodeSanitySettings {
|
||||
RootDirectory = rootDirectory.FullPath,
|
||||
IsAppveyorBuild = AppVeyor.IsRunningOnAppVeyor
|
||||
});
|
||||
});
|
||||
|
||||
Task("CodeAnalysis")
|
||||
.IsDependentOn("CodeFileSanity")
|
||||
.IsDependentOn("InspectCode");
|
||||
|
||||
RunTarget(target);
|
@ -1,5 +0,0 @@
|
||||
|
||||
[Nuget]
|
||||
Source=https://api.nuget.org/v3/index.json
|
||||
UseInProcessClient=true
|
||||
LoadDependencies=true
|
@ -52,6 +52,6 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.611.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2021.611.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2021.614.0" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
@ -12,6 +12,7 @@ using osu.Game.Rulesets.Osu.Objects;
|
||||
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||
using osu.Game.Skinning;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
||||
{
|
||||
@ -40,6 +41,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.Centre,
|
||||
Texture = source.GetTexture("spinner-background"),
|
||||
Colour = source.GetConfig<OsuSkinColour, Color4>(OsuSkinColour.SpinnerBackground)?.Value ?? new Color4(100, 100, 100, 255),
|
||||
Scale = new Vector2(SPRITE_SCALE),
|
||||
Y = SPINNER_Y_CENTRE,
|
||||
},
|
||||
|
@ -7,6 +7,7 @@ namespace osu.Game.Rulesets.Osu.Skinning
|
||||
{
|
||||
SliderTrackOverride,
|
||||
SliderBorder,
|
||||
SliderBall
|
||||
SliderBall,
|
||||
SpinnerBackground,
|
||||
}
|
||||
}
|
||||
|
@ -113,7 +113,6 @@ namespace osu.Game.Tests.Collections.IO
|
||||
await importCollectionsFromStream(osu, ms);
|
||||
}
|
||||
|
||||
Assert.That(host.UpdateThread.Running, Is.True);
|
||||
Assert.That(exceptionThrown, Is.False);
|
||||
Assert.That(osu.CollectionManager.Collections.Count, Is.EqualTo(0));
|
||||
}
|
||||
|
@ -2,15 +2,22 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Online.Leaderboards;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Osu.Mods;
|
||||
using osu.Game.Scoring;
|
||||
using osu.Game.Screens.Select.Leaderboards;
|
||||
using osu.Game.Tests.Resources;
|
||||
using osu.Game.Users;
|
||||
using osuTK;
|
||||
|
||||
@ -23,32 +30,98 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
[Cached]
|
||||
private readonly DialogOverlay dialogOverlay;
|
||||
|
||||
private ScoreManager scoreManager;
|
||||
|
||||
private RulesetStore rulesetStore;
|
||||
private BeatmapManager beatmapManager;
|
||||
|
||||
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
|
||||
{
|
||||
var dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
|
||||
|
||||
dependencies.Cache(rulesetStore = new RulesetStore(ContextFactory));
|
||||
dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, ContextFactory, rulesetStore, null, dependencies.Get<AudioManager>(), Resources, dependencies.Get<GameHost>(), Beatmap.Default));
|
||||
dependencies.Cache(scoreManager = new ScoreManager(rulesetStore, () => beatmapManager, LocalStorage, null, ContextFactory));
|
||||
|
||||
return dependencies;
|
||||
}
|
||||
|
||||
public TestSceneBeatmapLeaderboard()
|
||||
{
|
||||
Add(dialogOverlay = new DialogOverlay
|
||||
AddRange(new Drawable[]
|
||||
{
|
||||
Depth = -1
|
||||
dialogOverlay = new DialogOverlay
|
||||
{
|
||||
Depth = -1
|
||||
},
|
||||
leaderboard = new FailableLeaderboard
|
||||
{
|
||||
Origin = Anchor.Centre,
|
||||
Anchor = Anchor.Centre,
|
||||
Size = new Vector2(550f, 450f),
|
||||
Scope = BeatmapLeaderboardScope.Global,
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestLocalScoresDisplay()
|
||||
{
|
||||
BeatmapInfo beatmapInfo = null;
|
||||
|
||||
AddStep(@"Set scope", () => leaderboard.Scope = BeatmapLeaderboardScope.Local);
|
||||
|
||||
AddStep(@"Set beatmap", () =>
|
||||
{
|
||||
beatmapManager.Import(TestResources.GetQuickTestBeatmapForImport()).Wait();
|
||||
beatmapInfo = beatmapManager.GetAllUsableBeatmapSets().First().Beatmaps.First();
|
||||
|
||||
leaderboard.Beatmap = beatmapInfo;
|
||||
});
|
||||
|
||||
Add(leaderboard = new FailableLeaderboard
|
||||
{
|
||||
Origin = Anchor.Centre,
|
||||
Anchor = Anchor.Centre,
|
||||
Size = new Vector2(550f, 450f),
|
||||
Scope = BeatmapLeaderboardScope.Global,
|
||||
});
|
||||
clearScores();
|
||||
checkCount(0);
|
||||
|
||||
AddStep(@"New Scores", newScores);
|
||||
loadMoreScores(() => beatmapInfo);
|
||||
checkCount(10);
|
||||
|
||||
loadMoreScores(() => beatmapInfo);
|
||||
checkCount(20);
|
||||
|
||||
clearScores();
|
||||
checkCount(0);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestGlobalScoresDisplay()
|
||||
{
|
||||
AddStep(@"Set scope", () => leaderboard.Scope = BeatmapLeaderboardScope.Global);
|
||||
AddStep(@"New Scores", () => leaderboard.Scores = generateSampleScores(null));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestPersonalBest()
|
||||
{
|
||||
AddStep(@"Show personal best", showPersonalBest);
|
||||
AddStep("null personal best position", showPersonalBestWithNullPosition);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestPlaceholderStates()
|
||||
{
|
||||
AddStep(@"Empty Scores", () => leaderboard.SetRetrievalState(PlaceholderState.NoScores));
|
||||
AddStep(@"Network failure", () => leaderboard.SetRetrievalState(PlaceholderState.NetworkFailure));
|
||||
AddStep(@"No supporter", () => leaderboard.SetRetrievalState(PlaceholderState.NotSupporter));
|
||||
AddStep(@"Not logged in", () => leaderboard.SetRetrievalState(PlaceholderState.NotLoggedIn));
|
||||
AddStep(@"Unavailable", () => leaderboard.SetRetrievalState(PlaceholderState.Unavailable));
|
||||
AddStep(@"None selected", () => leaderboard.SetRetrievalState(PlaceholderState.NoneSelected));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestBeatmapStates()
|
||||
{
|
||||
foreach (BeatmapSetOnlineStatus status in Enum.GetValues(typeof(BeatmapSetOnlineStatus)))
|
||||
AddStep($"{status} beatmap", () => showBeatmapWithStatus(status));
|
||||
AddStep("null personal best position", showPersonalBestWithNullPosition);
|
||||
}
|
||||
|
||||
private void showPersonalBestWithNullPosition()
|
||||
@ -96,9 +169,26 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
};
|
||||
}
|
||||
|
||||
private void newScores()
|
||||
private void loadMoreScores(Func<BeatmapInfo> beatmapInfo)
|
||||
{
|
||||
var scores = new[]
|
||||
AddStep(@"Load new scores via manager", () =>
|
||||
{
|
||||
foreach (var score in generateSampleScores(beatmapInfo()))
|
||||
scoreManager.Import(score).Wait();
|
||||
});
|
||||
}
|
||||
|
||||
private void clearScores()
|
||||
{
|
||||
AddStep("Clear all scores", () => scoreManager.Delete(scoreManager.GetAllUsableScores()));
|
||||
}
|
||||
|
||||
private void checkCount(int expected) =>
|
||||
AddUntilStep("Correct count displayed", () => leaderboard.ChildrenOfType<LeaderboardScore>().Count() == expected);
|
||||
|
||||
private static ScoreInfo[] generateSampleScores(BeatmapInfo beatmap)
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
new ScoreInfo
|
||||
{
|
||||
@ -107,6 +197,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
MaxCombo = 244,
|
||||
TotalScore = 1707827,
|
||||
//Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
||||
Beatmap = beatmap,
|
||||
User = new User
|
||||
{
|
||||
Id = 6602580,
|
||||
@ -125,6 +216,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
MaxCombo = 244,
|
||||
TotalScore = 1707827,
|
||||
//Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
||||
Beatmap = beatmap,
|
||||
User = new User
|
||||
{
|
||||
Id = 4608074,
|
||||
@ -143,6 +235,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
MaxCombo = 244,
|
||||
TotalScore = 1707827,
|
||||
//Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
||||
Beatmap = beatmap,
|
||||
User = new User
|
||||
{
|
||||
Id = 1014222,
|
||||
@ -161,6 +254,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
MaxCombo = 244,
|
||||
TotalScore = 1707827,
|
||||
//Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
||||
Beatmap = beatmap,
|
||||
User = new User
|
||||
{
|
||||
Id = 1541390,
|
||||
@ -179,6 +273,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
MaxCombo = 244,
|
||||
TotalScore = 1707827,
|
||||
//Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
||||
Beatmap = beatmap,
|
||||
User = new User
|
||||
{
|
||||
Id = 2243452,
|
||||
@ -197,6 +292,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
MaxCombo = 244,
|
||||
TotalScore = 1707827,
|
||||
//Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
||||
Beatmap = beatmap,
|
||||
User = new User
|
||||
{
|
||||
Id = 2705430,
|
||||
@ -215,6 +311,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
MaxCombo = 244,
|
||||
TotalScore = 1707827,
|
||||
//Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
||||
Beatmap = beatmap,
|
||||
User = new User
|
||||
{
|
||||
Id = 7151382,
|
||||
@ -233,6 +330,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
MaxCombo = 244,
|
||||
TotalScore = 1707827,
|
||||
//Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
||||
Beatmap = beatmap,
|
||||
User = new User
|
||||
{
|
||||
Id = 2051389,
|
||||
@ -251,6 +349,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
MaxCombo = 244,
|
||||
TotalScore = 1707827,
|
||||
//Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
||||
Beatmap = beatmap,
|
||||
User = new User
|
||||
{
|
||||
Id = 6169483,
|
||||
@ -269,6 +368,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
MaxCombo = 244,
|
||||
TotalScore = 1707827,
|
||||
//Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
||||
Beatmap = beatmap,
|
||||
User = new User
|
||||
{
|
||||
Id = 6702666,
|
||||
@ -281,8 +381,6 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
leaderboard.Scores = scores;
|
||||
}
|
||||
|
||||
private void showBeatmapWithStatus(BeatmapSetOnlineStatus status)
|
||||
|
@ -7,17 +7,17 @@ namespace osu.Game.Localisation
|
||||
{
|
||||
public static class ChatStrings
|
||||
{
|
||||
private const string prefix = "osu.Game.Localisation.Chat";
|
||||
private const string prefix = @"osu.Game.Localisation.Chat";
|
||||
|
||||
/// <summary>
|
||||
/// "chat"
|
||||
/// </summary>
|
||||
public static LocalisableString HeaderTitle => new TranslatableString(getKey("header_title"), "chat");
|
||||
public static LocalisableString HeaderTitle => new TranslatableString(getKey(@"header_title"), @"chat");
|
||||
|
||||
/// <summary>
|
||||
/// "join the real-time discussion"
|
||||
/// </summary>
|
||||
public static LocalisableString HeaderDescription => new TranslatableString(getKey("header_description"), "join the real-time discussion");
|
||||
public static LocalisableString HeaderDescription => new TranslatableString(getKey(@"header_description"), @"join the real-time discussion");
|
||||
|
||||
private static string getKey(string key) => $"{prefix}:{key}";
|
||||
}
|
||||
|
@ -7,12 +7,12 @@ namespace osu.Game.Localisation
|
||||
{
|
||||
public static class CommonStrings
|
||||
{
|
||||
private const string prefix = "osu.Game.Localisation.Common";
|
||||
private const string prefix = @"osu.Game.Localisation.Common";
|
||||
|
||||
/// <summary>
|
||||
/// "Cancel"
|
||||
/// </summary>
|
||||
public static LocalisableString Cancel => new TranslatableString(getKey("cancel"), "Cancel");
|
||||
public static LocalisableString Cancel => new TranslatableString(getKey(@"cancel"), @"Cancel");
|
||||
|
||||
private static string getKey(string key) => $"{prefix}:{key}";
|
||||
}
|
||||
|
@ -7,10 +7,10 @@ namespace osu.Game.Localisation
|
||||
{
|
||||
public enum Language
|
||||
{
|
||||
[Description("English")]
|
||||
[Description(@"English")]
|
||||
en,
|
||||
|
||||
[Description("日本語")]
|
||||
[Description(@"日本語")]
|
||||
ja
|
||||
}
|
||||
}
|
||||
|
@ -7,17 +7,17 @@ namespace osu.Game.Localisation
|
||||
{
|
||||
public static class NotificationsStrings
|
||||
{
|
||||
private const string prefix = "osu.Game.Localisation.Notifications";
|
||||
private const string prefix = @"osu.Game.Localisation.Notifications";
|
||||
|
||||
/// <summary>
|
||||
/// "notifications"
|
||||
/// </summary>
|
||||
public static LocalisableString HeaderTitle => new TranslatableString(getKey("header_title"), "notifications");
|
||||
public static LocalisableString HeaderTitle => new TranslatableString(getKey(@"header_title"), @"notifications");
|
||||
|
||||
/// <summary>
|
||||
/// "waiting for 'ya"
|
||||
/// </summary>
|
||||
public static LocalisableString HeaderDescription => new TranslatableString(getKey("header_description"), "waiting for 'ya");
|
||||
public static LocalisableString HeaderDescription => new TranslatableString(getKey(@"header_description"), @"waiting for 'ya");
|
||||
|
||||
private static string getKey(string key) => $"{prefix}:{key}";
|
||||
}
|
||||
|
@ -7,17 +7,17 @@ namespace osu.Game.Localisation
|
||||
{
|
||||
public static class NowPlayingStrings
|
||||
{
|
||||
private const string prefix = "osu.Game.Localisation.NowPlaying";
|
||||
private const string prefix = @"osu.Game.Localisation.NowPlaying";
|
||||
|
||||
/// <summary>
|
||||
/// "now playing"
|
||||
/// </summary>
|
||||
public static LocalisableString HeaderTitle => new TranslatableString(getKey("header_title"), "now playing");
|
||||
public static LocalisableString HeaderTitle => new TranslatableString(getKey(@"header_title"), @"now playing");
|
||||
|
||||
/// <summary>
|
||||
/// "manage the currently playing track"
|
||||
/// </summary>
|
||||
public static LocalisableString HeaderDescription => new TranslatableString(getKey("header_description"), "manage the currently playing track");
|
||||
public static LocalisableString HeaderDescription => new TranslatableString(getKey(@"header_description"), @"manage the currently playing track");
|
||||
|
||||
private static string getKey(string key) => $"{prefix}:{key}";
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Resources;
|
||||
using System.Threading.Tasks;
|
||||
using osu.Framework.Localisation;
|
||||
@ -34,7 +35,29 @@ namespace osu.Game.Localisation
|
||||
lock (resourceManagers)
|
||||
{
|
||||
if (!resourceManagers.TryGetValue(ns, out var manager))
|
||||
resourceManagers[ns] = manager = new ResourceManager(ns, GetType().Assembly);
|
||||
{
|
||||
var loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies();
|
||||
|
||||
// Traverse backwards through periods in the namespace to find a matching assembly.
|
||||
string assemblyName = ns;
|
||||
|
||||
while (!string.IsNullOrEmpty(assemblyName))
|
||||
{
|
||||
var matchingAssembly = loadedAssemblies.FirstOrDefault(asm => asm.GetName().Name == assemblyName);
|
||||
|
||||
if (matchingAssembly != null)
|
||||
{
|
||||
resourceManagers[ns] = manager = new ResourceManager(ns, matchingAssembly);
|
||||
break;
|
||||
}
|
||||
|
||||
int lastIndex = Math.Max(0, assemblyName.LastIndexOf('.'));
|
||||
assemblyName = assemblyName.Substring(0, lastIndex);
|
||||
}
|
||||
}
|
||||
|
||||
if (manager == null)
|
||||
return null;
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -7,17 +7,17 @@ namespace osu.Game.Localisation
|
||||
{
|
||||
public static class SettingsStrings
|
||||
{
|
||||
private const string prefix = "osu.Game.Localisation.Settings";
|
||||
private const string prefix = @"osu.Game.Localisation.Settings";
|
||||
|
||||
/// <summary>
|
||||
/// "settings"
|
||||
/// </summary>
|
||||
public static LocalisableString HeaderTitle => new TranslatableString(getKey("header_title"), "settings");
|
||||
public static LocalisableString HeaderTitle => new TranslatableString(getKey(@"header_title"), @"settings");
|
||||
|
||||
/// <summary>
|
||||
/// "change the way osu! behaves"
|
||||
/// </summary>
|
||||
public static LocalisableString HeaderDescription => new TranslatableString(getKey("header_description"), "change the way osu! behaves");
|
||||
public static LocalisableString HeaderDescription => new TranslatableString(getKey(@"header_description"), @"change the way osu! behaves");
|
||||
|
||||
private static string getKey(string key) => $"{prefix}:{key}";
|
||||
}
|
||||
|
@ -44,9 +44,9 @@ namespace osu.Game.Online.Leaderboards
|
||||
|
||||
protected override Container<Drawable> Content => content;
|
||||
|
||||
private IEnumerable<TScoreInfo> scores;
|
||||
private ICollection<TScoreInfo> scores;
|
||||
|
||||
public IEnumerable<TScoreInfo> Scores
|
||||
public ICollection<TScoreInfo> Scores
|
||||
{
|
||||
get => scores;
|
||||
set
|
||||
@ -126,7 +126,7 @@ namespace osu.Game.Online.Leaderboards
|
||||
return;
|
||||
|
||||
scope = value;
|
||||
UpdateScores();
|
||||
RefreshScores();
|
||||
}
|
||||
}
|
||||
|
||||
@ -154,7 +154,7 @@ namespace osu.Game.Online.Leaderboards
|
||||
case PlaceholderState.NetworkFailure:
|
||||
replacePlaceholder(new ClickablePlaceholder(@"Couldn't fetch scores!", FontAwesome.Solid.Sync)
|
||||
{
|
||||
Action = UpdateScores,
|
||||
Action = RefreshScores
|
||||
});
|
||||
break;
|
||||
|
||||
@ -254,8 +254,6 @@ namespace osu.Game.Online.Leaderboards
|
||||
apiState.BindValueChanged(onlineStateChanged, true);
|
||||
}
|
||||
|
||||
public void RefreshScores() => UpdateScores();
|
||||
|
||||
private APIRequest getScoresRequest;
|
||||
|
||||
protected abstract bool IsOnlineScope { get; }
|
||||
@ -267,12 +265,14 @@ namespace osu.Game.Online.Leaderboards
|
||||
case APIState.Online:
|
||||
case APIState.Offline:
|
||||
if (IsOnlineScope)
|
||||
UpdateScores();
|
||||
RefreshScores();
|
||||
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
public void RefreshScores() => Scheduler.AddOnce(UpdateScores);
|
||||
|
||||
protected void UpdateScores()
|
||||
{
|
||||
// don't display any scores or placeholder until the first Scores_Set has been called.
|
||||
@ -290,7 +290,7 @@ namespace osu.Game.Online.Leaderboards
|
||||
|
||||
getScoresRequest = FetchScores(scores => Schedule(() =>
|
||||
{
|
||||
Scores = scores;
|
||||
Scores = scores.ToArray();
|
||||
PlaceholderState = Scores.Any() ? PlaceholderState.Successful : PlaceholderState.NoScores;
|
||||
}));
|
||||
|
||||
|
@ -2,16 +2,20 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
|
||||
namespace osu.Game.Overlays.Settings
|
||||
{
|
||||
public class SettingsNumberBox : SettingsItem<string>
|
||||
{
|
||||
protected override Drawable CreateControl() => new OsuNumberBox
|
||||
protected override Drawable CreateControl() => new NumberBox
|
||||
{
|
||||
Margin = new MarginPadding { Top = 5 },
|
||||
RelativeSizeAxes = Axes.X,
|
||||
};
|
||||
|
||||
public class NumberBox : SettingsTextBox.TextBox
|
||||
{
|
||||
protected override bool CanAddCharacter(char character) => char.IsNumber(character);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,18 +1,60 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Overlays.Settings
|
||||
{
|
||||
public class SettingsTextBox : SettingsItem<string>
|
||||
{
|
||||
protected override Drawable CreateControl() => new OsuTextBox
|
||||
protected override Drawable CreateControl() => new TextBox
|
||||
{
|
||||
Margin = new MarginPadding { Top = 5 },
|
||||
RelativeSizeAxes = Axes.X,
|
||||
CommitOnFocusLost = true,
|
||||
};
|
||||
|
||||
public class TextBox : OsuTextBox
|
||||
{
|
||||
private const float border_thickness = 3;
|
||||
|
||||
private Color4 borderColourFocused;
|
||||
private Color4 borderColourUnfocused;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colour)
|
||||
{
|
||||
borderColourUnfocused = colour.Gray4.Opacity(0.5f);
|
||||
borderColourFocused = BorderColour;
|
||||
|
||||
updateBorder();
|
||||
}
|
||||
|
||||
protected override void OnFocus(FocusEvent e)
|
||||
{
|
||||
base.OnFocus(e);
|
||||
|
||||
updateBorder();
|
||||
}
|
||||
|
||||
protected override void OnFocusLost(FocusLostEvent e)
|
||||
{
|
||||
base.OnFocusLost(e);
|
||||
|
||||
updateBorder();
|
||||
}
|
||||
|
||||
private void updateBorder()
|
||||
{
|
||||
BorderThickness = border_thickness;
|
||||
BorderColour = HasFocus ? borderColourFocused : borderColourUnfocused;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,6 @@ using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Overlays.Settings;
|
||||
|
||||
namespace osu.Game.Rulesets.Mods
|
||||
@ -50,7 +49,7 @@ namespace osu.Game.Rulesets.Mods
|
||||
}
|
||||
}
|
||||
|
||||
private readonly OsuNumberBox seedNumberBox;
|
||||
private readonly SettingsNumberBox.NumberBox seedNumberBox;
|
||||
|
||||
public SeedControl()
|
||||
{
|
||||
@ -76,7 +75,7 @@ namespace osu.Game.Rulesets.Mods
|
||||
{
|
||||
new Drawable[]
|
||||
{
|
||||
seedNumberBox = new OsuNumberBox
|
||||
seedNumberBox = new SettingsNumberBox.NumberBox
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
CommitOnFocusLost = true
|
||||
|
@ -19,6 +19,20 @@ namespace osu.Game.Rulesets.UI.Scrolling
|
||||
private readonly IBindable<double> timeRange = new BindableDouble();
|
||||
private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>();
|
||||
|
||||
/// <summary>
|
||||
/// Whether the scrolling direction is horizontal or vertical.
|
||||
/// </summary>
|
||||
private Direction scrollingAxis => direction.Value == ScrollingDirection.Left || direction.Value == ScrollingDirection.Right ? Direction.Horizontal : Direction.Vertical;
|
||||
|
||||
/// <summary>
|
||||
/// The scrolling axis is inverted if objects temporally farther in the future have a smaller position value across the scrolling axis.
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// <see cref="ScrollingDirection.Down"/> is inverted, because given two objects, one of which is at the current time and one of which is 1000ms in the future,
|
||||
/// in the current time instant the future object is spatially above the current object, and therefore has a smaller value of the Y coordinate of its position.
|
||||
/// </example>
|
||||
private bool axisInverted => direction.Value == ScrollingDirection.Down || direction.Value == ScrollingDirection.Right;
|
||||
|
||||
/// <summary>
|
||||
/// A set of top-level <see cref="DrawableHitObject"/>s which have an up-to-date layout.
|
||||
/// </summary>
|
||||
@ -48,99 +62,64 @@ namespace osu.Game.Rulesets.UI.Scrolling
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Given a position in screen space, return the time within this column.
|
||||
/// Given a position at <paramref name="currentTime"/>, return the time of the object corresponding to the position.
|
||||
/// </summary>
|
||||
public double TimeAtScreenSpacePosition(Vector2 screenSpacePosition)
|
||||
/// <remarks>
|
||||
/// If there are multiple valid time values, one arbitrary time is returned.
|
||||
/// </remarks>
|
||||
public double TimeAtPosition(float localPosition, double currentTime)
|
||||
{
|
||||
// convert to local space of column so we can snap and fetch correct location.
|
||||
Vector2 localPosition = ToLocalSpace(screenSpacePosition);
|
||||
|
||||
float position = 0;
|
||||
|
||||
switch (scrollingInfo.Direction.Value)
|
||||
{
|
||||
case ScrollingDirection.Up:
|
||||
case ScrollingDirection.Down:
|
||||
position = localPosition.Y;
|
||||
break;
|
||||
|
||||
case ScrollingDirection.Right:
|
||||
case ScrollingDirection.Left:
|
||||
position = localPosition.X;
|
||||
break;
|
||||
}
|
||||
|
||||
flipPositionIfRequired(ref position);
|
||||
|
||||
return scrollingInfo.Algorithm.TimeAt(position, Time.Current, scrollingInfo.TimeRange.Value, scrollLength);
|
||||
float scrollPosition = axisInverted ? scrollLength - localPosition : localPosition;
|
||||
return scrollingInfo.Algorithm.TimeAt(scrollPosition, currentTime, timeRange.Value, scrollLength);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Given a time, return the screen space position within this column.
|
||||
/// Given a position at the current time in screen space, return the time of the object corresponding the position.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If there are multiple valid time values, one arbitrary time is returned.
|
||||
/// </remarks>
|
||||
public double TimeAtScreenSpacePosition(Vector2 screenSpacePosition)
|
||||
{
|
||||
Vector2 localPosition = ToLocalSpace(screenSpacePosition);
|
||||
return TimeAtPosition(scrollingAxis == Direction.Horizontal ? localPosition.X : localPosition.Y, Time.Current);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Given a time, return the position along the scrolling axis within this <see cref="HitObjectContainer"/> at time <paramref name="currentTime"/>.
|
||||
/// </summary>
|
||||
public float PositionAtTime(double time, double currentTime)
|
||||
{
|
||||
float scrollPosition = scrollingInfo.Algorithm.PositionAt(time, currentTime, timeRange.Value, scrollLength);
|
||||
return axisInverted ? scrollLength - scrollPosition : scrollPosition;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Given a time, return the position along the scrolling axis within this <see cref="HitObjectContainer"/> at the current time.
|
||||
/// </summary>
|
||||
public float PositionAtTime(double time) => PositionAtTime(time, Time.Current);
|
||||
|
||||
/// <summary>
|
||||
/// Given a time, return the screen space position within this <see cref="HitObjectContainer"/>.
|
||||
/// In the non-scrolling axis, the center of this <see cref="HitObjectContainer"/> is returned.
|
||||
/// </summary>
|
||||
public Vector2 ScreenSpacePositionAtTime(double time)
|
||||
{
|
||||
var pos = scrollingInfo.Algorithm.PositionAt(time, Time.Current, scrollingInfo.TimeRange.Value, scrollLength);
|
||||
|
||||
flipPositionIfRequired(ref pos);
|
||||
|
||||
switch (scrollingInfo.Direction.Value)
|
||||
{
|
||||
case ScrollingDirection.Up:
|
||||
case ScrollingDirection.Down:
|
||||
return ToScreenSpace(new Vector2(getBreadth() / 2, pos));
|
||||
|
||||
default:
|
||||
return ToScreenSpace(new Vector2(pos, getBreadth() / 2));
|
||||
}
|
||||
float localPosition = PositionAtTime(time, Time.Current);
|
||||
return scrollingAxis == Direction.Horizontal
|
||||
? ToScreenSpace(new Vector2(localPosition, DrawHeight / 2))
|
||||
: ToScreenSpace(new Vector2(DrawWidth / 2, localPosition));
|
||||
}
|
||||
|
||||
private float scrollLength
|
||||
/// <summary>
|
||||
/// Given a start time and end time of a scrolling object, return the length of the object along the scrolling axis.
|
||||
/// </summary>
|
||||
public float LengthAtTime(double startTime, double endTime)
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (scrollingInfo.Direction.Value)
|
||||
{
|
||||
case ScrollingDirection.Left:
|
||||
case ScrollingDirection.Right:
|
||||
return DrawWidth;
|
||||
|
||||
default:
|
||||
return DrawHeight;
|
||||
}
|
||||
}
|
||||
return scrollingInfo.Algorithm.GetLength(startTime, endTime, timeRange.Value, scrollLength);
|
||||
}
|
||||
|
||||
private float getBreadth()
|
||||
{
|
||||
switch (scrollingInfo.Direction.Value)
|
||||
{
|
||||
case ScrollingDirection.Up:
|
||||
case ScrollingDirection.Down:
|
||||
return DrawWidth;
|
||||
|
||||
default:
|
||||
return DrawHeight;
|
||||
}
|
||||
}
|
||||
|
||||
private void flipPositionIfRequired(ref float position)
|
||||
{
|
||||
// We're dealing with screen coordinates in which the position decreases towards the centre of the screen resulting in an increase in start time.
|
||||
// The scrolling algorithm instead assumes a top anchor meaning an increase in time corresponds to an increase in position,
|
||||
// so when scrolling downwards the coordinates need to be flipped.
|
||||
|
||||
switch (scrollingInfo.Direction.Value)
|
||||
{
|
||||
case ScrollingDirection.Down:
|
||||
position = DrawHeight - position;
|
||||
break;
|
||||
|
||||
case ScrollingDirection.Right:
|
||||
position = DrawWidth - position;
|
||||
break;
|
||||
}
|
||||
}
|
||||
private float scrollLength => scrollingAxis == Direction.Horizontal ? DrawWidth : DrawHeight;
|
||||
|
||||
protected override void AddDrawable(HitObjectLifetimeEntry entry, DrawableHitObject drawable)
|
||||
{
|
||||
@ -237,18 +216,11 @@ namespace osu.Game.Rulesets.UI.Scrolling
|
||||
{
|
||||
if (hitObject.HitObject is IHasDuration e)
|
||||
{
|
||||
switch (direction.Value)
|
||||
{
|
||||
case ScrollingDirection.Up:
|
||||
case ScrollingDirection.Down:
|
||||
hitObject.Height = scrollingInfo.Algorithm.GetLength(hitObject.HitObject.StartTime, e.EndTime, timeRange.Value, scrollLength);
|
||||
break;
|
||||
|
||||
case ScrollingDirection.Left:
|
||||
case ScrollingDirection.Right:
|
||||
hitObject.Width = scrollingInfo.Algorithm.GetLength(hitObject.HitObject.StartTime, e.EndTime, timeRange.Value, scrollLength);
|
||||
break;
|
||||
}
|
||||
float length = LengthAtTime(hitObject.HitObject.StartTime, e.EndTime);
|
||||
if (scrollingAxis == Direction.Horizontal)
|
||||
hitObject.Width = length;
|
||||
else
|
||||
hitObject.Height = length;
|
||||
}
|
||||
|
||||
foreach (var obj in hitObject.NestedHitObjects)
|
||||
@ -262,24 +234,16 @@ namespace osu.Game.Rulesets.UI.Scrolling
|
||||
|
||||
private void updatePosition(DrawableHitObject hitObject, double currentTime)
|
||||
{
|
||||
switch (direction.Value)
|
||||
{
|
||||
case ScrollingDirection.Up:
|
||||
hitObject.Y = scrollingInfo.Algorithm.PositionAt(hitObject.HitObject.StartTime, currentTime, timeRange.Value, scrollLength);
|
||||
break;
|
||||
float position = PositionAtTime(hitObject.HitObject.StartTime, currentTime);
|
||||
|
||||
case ScrollingDirection.Down:
|
||||
hitObject.Y = -scrollingInfo.Algorithm.PositionAt(hitObject.HitObject.StartTime, currentTime, timeRange.Value, scrollLength);
|
||||
break;
|
||||
// The position returned from `PositionAtTime` is assuming the `TopLeft` anchor.
|
||||
// A correction is needed because the hit objects are using a different anchor for each direction (e.g. `BottomCentre` for `Bottom` direction).
|
||||
float anchorCorrection = axisInverted ? scrollLength : 0;
|
||||
|
||||
case ScrollingDirection.Left:
|
||||
hitObject.X = scrollingInfo.Algorithm.PositionAt(hitObject.HitObject.StartTime, currentTime, timeRange.Value, scrollLength);
|
||||
break;
|
||||
|
||||
case ScrollingDirection.Right:
|
||||
hitObject.X = -scrollingInfo.Algorithm.PositionAt(hitObject.HitObject.StartTime, currentTime, timeRange.Value, scrollLength);
|
||||
break;
|
||||
}
|
||||
if (scrollingAxis == Direction.Horizontal)
|
||||
hitObject.X = position - anchorCorrection;
|
||||
else
|
||||
hitObject.Y = position - anchorCorrection;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -44,6 +44,8 @@ namespace osu.Game.Screens.Select.Leaderboards
|
||||
|
||||
private IBindable<WeakReference<ScoreInfo>> itemRemoved;
|
||||
|
||||
private IBindable<WeakReference<ScoreInfo>> itemAdded;
|
||||
|
||||
/// <summary>
|
||||
/// Whether to apply the game's currently selected mods as a filter when retrieving scores.
|
||||
/// </summary>
|
||||
@ -85,6 +87,9 @@ namespace osu.Game.Screens.Select.Leaderboards
|
||||
|
||||
itemRemoved = scoreManager.ItemRemoved.GetBoundCopy();
|
||||
itemRemoved.BindValueChanged(onScoreRemoved);
|
||||
|
||||
itemAdded = scoreManager.ItemUpdated.GetBoundCopy();
|
||||
itemAdded.BindValueChanged(onScoreAdded);
|
||||
}
|
||||
|
||||
protected override void Reset()
|
||||
@ -93,7 +98,25 @@ namespace osu.Game.Screens.Select.Leaderboards
|
||||
TopScore = null;
|
||||
}
|
||||
|
||||
private void onScoreRemoved(ValueChangedEvent<WeakReference<ScoreInfo>> score) => Schedule(RefreshScores);
|
||||
private void onScoreRemoved(ValueChangedEvent<WeakReference<ScoreInfo>> score) =>
|
||||
scoreStoreChanged(score);
|
||||
|
||||
private void onScoreAdded(ValueChangedEvent<WeakReference<ScoreInfo>> score) =>
|
||||
scoreStoreChanged(score);
|
||||
|
||||
private void scoreStoreChanged(ValueChangedEvent<WeakReference<ScoreInfo>> score)
|
||||
{
|
||||
if (Scope != BeatmapLeaderboardScope.Local)
|
||||
return;
|
||||
|
||||
if (score.NewValue.TryGetTarget(out var scoreInfo))
|
||||
{
|
||||
if (Beatmap?.ID != scoreInfo.BeatmapInfoID)
|
||||
return;
|
||||
}
|
||||
|
||||
RefreshScores();
|
||||
}
|
||||
|
||||
protected override bool IsOnlineScope => Scope != BeatmapLeaderboardScope.Local;
|
||||
|
||||
|
@ -4,7 +4,6 @@
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Input;
|
||||
using osu.Framework.Testing.Input;
|
||||
using osu.Game.Graphics.Cursor;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
@ -49,7 +48,7 @@ namespace osu.Game.Tests.Visual
|
||||
InputManager = new ManualInputManager
|
||||
{
|
||||
UseParentInput = true,
|
||||
Child = new PlatformActionContainer().WithChild(mainContent)
|
||||
Child = mainContent
|
||||
},
|
||||
new Container
|
||||
{
|
||||
|
@ -36,7 +36,7 @@
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Realm" Version="10.2.0" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2021.611.0" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2021.614.0" />
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.611.0" />
|
||||
<PackageReference Include="Sentry" Version="3.4.0" />
|
||||
<PackageReference Include="SharpCompress" Version="0.28.2" />
|
||||
|
@ -70,7 +70,7 @@
|
||||
<Reference Include="System.Net.Http" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="ppy.osu.Framework.iOS" Version="2021.611.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.iOS" Version="2021.614.0" />
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.611.0" />
|
||||
</ItemGroup>
|
||||
<!-- See https://github.com/dotnet/runtime/issues/35988 (can be removed after Xamarin uses net5.0 / net6.0) -->
|
||||
@ -93,7 +93,7 @@
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2021.611.0" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2021.614.0" />
|
||||
<PackageReference Include="SharpCompress" Version="0.28.2" />
|
||||
<PackageReference Include="NUnit" Version="3.13.2" />
|
||||
<PackageReference Include="SharpRaven" Version="2.4.0" />
|
||||
|
Loading…
Reference in New Issue
Block a user