mirror of
https://github.com/ppy/osu.git
synced 2025-01-28 05:22:54 +08:00
Merge branch 'master' into mod-icon-colors
This commit is contained in:
commit
779d512b44
@ -9,7 +9,6 @@
|
||||
<GenerateProgramFile>false</GenerateProgramFile>
|
||||
</PropertyGroup>
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
|
||||
<PackageReference Include="NUnit" Version="3.13.3" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.1.0" />
|
||||
|
@ -9,7 +9,6 @@
|
||||
<GenerateProgramFile>false</GenerateProgramFile>
|
||||
</PropertyGroup>
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
|
||||
<PackageReference Include="NUnit" Version="3.13.3" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.1.0" />
|
||||
|
@ -9,7 +9,6 @@
|
||||
<GenerateProgramFile>false</GenerateProgramFile>
|
||||
</PropertyGroup>
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
|
||||
<PackageReference Include="NUnit" Version="3.13.3" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.1.0" />
|
||||
|
@ -9,7 +9,6 @@
|
||||
<GenerateProgramFile>false</GenerateProgramFile>
|
||||
</PropertyGroup>
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
|
||||
<PackageReference Include="NUnit" Version="3.13.3" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.1.0" />
|
||||
|
@ -24,7 +24,7 @@
|
||||
<ProjectReference Include="..\osu.Game.Rulesets.Taiko\osu.Game.Rulesets.Taiko.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="Clowd.Squirrel" Version="2.9.40" />
|
||||
<PackageReference Include="Clowd.Squirrel" Version="2.9.42" />
|
||||
<PackageReference Include="Mono.Posix.NETStandard" Version="1.0.0" />
|
||||
<PackageReference Include="System.IO.Packaging" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="5.0.14" />
|
||||
|
@ -1,8 +1,6 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
#nullable disable
|
||||
|
||||
using System.IO;
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using osu.Framework.IO.Stores;
|
||||
|
@ -1,8 +1,6 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
#nullable disable
|
||||
|
||||
using System;
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using osu.Game.Rulesets.Osu.Mods;
|
||||
@ -11,7 +9,7 @@ namespace osu.Game.Benchmarks
|
||||
{
|
||||
public class BenchmarkMod : BenchmarkTest
|
||||
{
|
||||
private OsuModDoubleTime mod;
|
||||
private OsuModDoubleTime mod = null!;
|
||||
|
||||
[Params(1, 10, 100)]
|
||||
public int Times { get; set; }
|
||||
|
@ -1,8 +1,6 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
#nullable disable
|
||||
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using BenchmarkDotNet.Attributes;
|
||||
@ -17,9 +15,9 @@ namespace osu.Game.Benchmarks
|
||||
{
|
||||
public class BenchmarkRealmReads : BenchmarkTest
|
||||
{
|
||||
private TemporaryNativeStorage storage;
|
||||
private RealmAccess realm;
|
||||
private UpdateThread updateThread;
|
||||
private TemporaryNativeStorage storage = null!;
|
||||
private RealmAccess realm = null!;
|
||||
private UpdateThread updateThread = null!;
|
||||
|
||||
[Params(1, 100, 1000)]
|
||||
public int ReadsPerFetch { get; set; }
|
||||
@ -135,9 +133,9 @@ namespace osu.Game.Benchmarks
|
||||
[GlobalCleanup]
|
||||
public void Cleanup()
|
||||
{
|
||||
realm?.Dispose();
|
||||
storage?.Dispose();
|
||||
updateThread?.Exit();
|
||||
realm.Dispose();
|
||||
storage.Dispose();
|
||||
updateThread.Exit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,6 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
#nullable disable
|
||||
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using BenchmarkDotNet.Engines;
|
||||
using osu.Game.Online.API;
|
||||
@ -13,9 +11,9 @@ namespace osu.Game.Benchmarks
|
||||
{
|
||||
public class BenchmarkRuleset : BenchmarkTest
|
||||
{
|
||||
private OsuRuleset ruleset;
|
||||
private APIMod apiModDoubleTime;
|
||||
private APIMod apiModDifficultyAdjust;
|
||||
private OsuRuleset ruleset = null!;
|
||||
private APIMod apiModDoubleTime = null!;
|
||||
private APIMod apiModDifficultyAdjust = null!;
|
||||
|
||||
public override void SetUp()
|
||||
{
|
||||
|
@ -1,8 +1,6 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
#nullable disable
|
||||
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using BenchmarkDotNet.Running;
|
||||
using NUnit.Framework;
|
||||
|
@ -1,8 +1,6 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
#nullable disable
|
||||
|
||||
using BenchmarkDotNet.Configs;
|
||||
using BenchmarkDotNet.Running;
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="..\osu.TestProject.props" />
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
|
||||
<PackageReference Include="NUnit" Version="3.13.3" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.1.0" />
|
||||
|
@ -1,7 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="..\osu.TestProject.props" />
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
|
||||
<PackageReference Include="NUnit" Version="3.13.3" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.1.0" />
|
||||
|
@ -1,9 +1,8 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="..\osu.TestProject.props" />
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
|
||||
<PackageReference Include="Moq" Version="4.17.2" />
|
||||
<PackageReference Include="Moq" Version="4.18.1" />
|
||||
<PackageReference Include="NUnit" Version="3.13.3" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.1.0" />
|
||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||
|
@ -196,6 +196,27 @@ namespace osu.Game.Rulesets.Osu.Utils
|
||||
var slider = (Slider)workingObject.HitObject;
|
||||
var possibleMovementBounds = calculatePossibleMovementBounds(slider);
|
||||
|
||||
// The slider rotation applied in computeModifiedPosition might make it impossible to fit the slider into the playfield
|
||||
// For example, a long horizontal slider will be off-screen when rotated by 90 degrees
|
||||
// In this case, limit the rotation to either 0 or 180 degrees
|
||||
if (possibleMovementBounds.Width < 0 || possibleMovementBounds.Height < 0)
|
||||
{
|
||||
float currentRotation = getSliderRotation(slider);
|
||||
float diff1 = getAngleDifference(workingObject.RotationOriginal, currentRotation);
|
||||
float diff2 = getAngleDifference(workingObject.RotationOriginal + MathF.PI, currentRotation);
|
||||
|
||||
if (diff1 < diff2)
|
||||
{
|
||||
RotateSlider(slider, workingObject.RotationOriginal - getSliderRotation(slider));
|
||||
}
|
||||
else
|
||||
{
|
||||
RotateSlider(slider, workingObject.RotationOriginal + MathF.PI - getSliderRotation(slider));
|
||||
}
|
||||
|
||||
possibleMovementBounds = calculatePossibleMovementBounds(slider);
|
||||
}
|
||||
|
||||
var previousPosition = workingObject.PositionModified;
|
||||
|
||||
// Clamp slider position to the placement area
|
||||
@ -353,6 +374,18 @@ namespace osu.Game.Rulesets.Osu.Utils
|
||||
return MathF.Atan2(endPositionVector.Y, endPositionVector.X);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the absolute difference between 2 angles measured in Radians.
|
||||
/// </summary>
|
||||
/// <param name="angle1">The first angle</param>
|
||||
/// <param name="angle2">The second angle</param>
|
||||
/// <returns>The absolute difference with interval <c>[0, MathF.PI)</c></returns>
|
||||
private static float getAngleDifference(float angle1, float angle2)
|
||||
{
|
||||
float diff = MathF.Abs(angle1 - angle2) % (MathF.PI * 2);
|
||||
return MathF.Min(diff, MathF.PI * 2 - diff);
|
||||
}
|
||||
|
||||
public class ObjectPositionInfo
|
||||
{
|
||||
/// <summary>
|
||||
@ -395,6 +428,7 @@ namespace osu.Game.Rulesets.Osu.Utils
|
||||
|
||||
private class WorkingObject
|
||||
{
|
||||
public float RotationOriginal { get; }
|
||||
public Vector2 PositionOriginal { get; }
|
||||
public Vector2 PositionModified { get; set; }
|
||||
public Vector2 EndPositionModified { get; set; }
|
||||
@ -405,6 +439,7 @@ namespace osu.Game.Rulesets.Osu.Utils
|
||||
public WorkingObject(ObjectPositionInfo positionInfo)
|
||||
{
|
||||
PositionInfo = positionInfo;
|
||||
RotationOriginal = HitObject is Slider slider ? getSliderRotation(slider) : 0;
|
||||
PositionModified = PositionOriginal = HitObject.Position;
|
||||
EndPositionModified = HitObject.EndPosition;
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="..\osu.TestProject.props" />
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
|
||||
<PackageReference Include="NUnit" Version="3.13.3" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.1.0" />
|
||||
|
@ -83,20 +83,20 @@ namespace osu.Game.Tests.Skins.IO
|
||||
#region Cases where imports should match existing
|
||||
|
||||
[Test]
|
||||
public Task TestImportTwiceWithSameMetadataAndFilename() => runSkinTest(async osu =>
|
||||
public Task TestImportTwiceWithSameMetadataAndFilename([Values] bool batchImport) => runSkinTest(async osu =>
|
||||
{
|
||||
var import1 = await loadSkinIntoOsu(osu, new ImportTask(createOskWithIni("test skin", "skinner"), "skin.osk"));
|
||||
var import2 = await loadSkinIntoOsu(osu, new ImportTask(createOskWithIni("test skin", "skinner"), "skin.osk"));
|
||||
var import1 = await loadSkinIntoOsu(osu, new ImportTask(createOskWithIni("test skin", "skinner"), "skin.osk"), batchImport);
|
||||
var import2 = await loadSkinIntoOsu(osu, new ImportTask(createOskWithIni("test skin", "skinner"), "skin.osk"), batchImport);
|
||||
|
||||
assertImportedOnce(import1, import2);
|
||||
});
|
||||
|
||||
[Test]
|
||||
public Task TestImportTwiceWithNoMetadataSameDownloadFilename() => runSkinTest(async osu =>
|
||||
public Task TestImportTwiceWithNoMetadataSameDownloadFilename([Values] bool batchImport) => runSkinTest(async osu =>
|
||||
{
|
||||
// if a user downloads two skins that do have skin.ini files but don't have any creator metadata in the skin.ini, they should both import separately just for safety.
|
||||
var import1 = await loadSkinIntoOsu(osu, new ImportTask(createOskWithIni(string.Empty, string.Empty), "download.osk"));
|
||||
var import2 = await loadSkinIntoOsu(osu, new ImportTask(createOskWithIni(string.Empty, string.Empty), "download.osk"));
|
||||
var import1 = await loadSkinIntoOsu(osu, new ImportTask(createOskWithIni(string.Empty, string.Empty), "download.osk"), batchImport);
|
||||
var import2 = await loadSkinIntoOsu(osu, new ImportTask(createOskWithIni(string.Empty, string.Empty), "download.osk"), batchImport);
|
||||
|
||||
assertImportedOnce(import1, import2);
|
||||
});
|
||||
@ -134,10 +134,10 @@ namespace osu.Game.Tests.Skins.IO
|
||||
});
|
||||
|
||||
[Test]
|
||||
public Task TestSameMetadataNameSameFolderName() => runSkinTest(async osu =>
|
||||
public Task TestSameMetadataNameSameFolderName([Values] bool batchImport) => runSkinTest(async osu =>
|
||||
{
|
||||
var import1 = await loadSkinIntoOsu(osu, new ImportTask(createOskWithIni("name 1", "author 1"), "my custom skin 1"));
|
||||
var import2 = await loadSkinIntoOsu(osu, new ImportTask(createOskWithIni("name 1", "author 1"), "my custom skin 1"));
|
||||
var import1 = await loadSkinIntoOsu(osu, new ImportTask(createOskWithIni("name 1", "author 1"), "my custom skin 1"), batchImport);
|
||||
var import2 = await loadSkinIntoOsu(osu, new ImportTask(createOskWithIni("name 1", "author 1"), "my custom skin 1"), batchImport);
|
||||
|
||||
assertImportedOnce(import1, import2);
|
||||
assertCorrectMetadata(import1, "name 1 [my custom skin 1]", "author 1", osu);
|
||||
@ -357,10 +357,10 @@ namespace osu.Game.Tests.Skins.IO
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<Live<SkinInfo>> loadSkinIntoOsu(OsuGameBase osu, ImportTask import)
|
||||
private async Task<Live<SkinInfo>> loadSkinIntoOsu(OsuGameBase osu, ImportTask import, bool batchImport = false)
|
||||
{
|
||||
var skinManager = osu.Dependencies.Get<SkinManager>();
|
||||
return await skinManager.Import(import);
|
||||
return await skinManager.Import(import, batchImport);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,11 +6,13 @@
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Screens.Edit;
|
||||
using osu.Game.Screens.Edit.Compose.Components.Timeline;
|
||||
using osu.Game.Screens.Select;
|
||||
@ -23,7 +25,9 @@ namespace osu.Game.Tests.Visual.Editing
|
||||
[Test]
|
||||
public void TestCantExitWithoutSaving()
|
||||
{
|
||||
AddUntilStep("Wait for dialog overlay load", () => ((Drawable)Game.Dependencies.Get<IDialogOverlay>()).IsLoaded);
|
||||
AddRepeatStep("Exit", () => InputManager.Key(Key.Escape), 10);
|
||||
AddAssert("Sample playback disabled", () => Editor.SamplePlaybackDisabled.Value);
|
||||
AddAssert("Editor is still active screen", () => Game.ScreenStack.CurrentScreen is Editor);
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,107 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Extensions.ObjectExtensions;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Scoring;
|
||||
using osu.Game.Screens.Ranking;
|
||||
using osu.Game.Tests.Resources;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Gameplay
|
||||
{
|
||||
public class TestScenePlayerLocalScoreImport : PlayerTestScene
|
||||
{
|
||||
private BeatmapManager beatmaps = null!;
|
||||
private RulesetStore rulesets = null!;
|
||||
|
||||
private BeatmapSetInfo? importedSet;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(GameHost host, AudioManager audio)
|
||||
{
|
||||
Dependencies.Cache(rulesets = new RealmRulesetStore(Realm));
|
||||
Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, Realm, rulesets, null, audio, Resources, host, Beatmap.Default));
|
||||
Dependencies.Cache(new ScoreManager(rulesets, () => beatmaps, LocalStorage, Realm, Scheduler, API));
|
||||
Dependencies.Cache(Realm);
|
||||
}
|
||||
|
||||
public override void SetUpSteps()
|
||||
{
|
||||
base.SetUpSteps();
|
||||
|
||||
AddStep("import beatmap", () =>
|
||||
{
|
||||
beatmaps.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely();
|
||||
importedSet = beatmaps.GetAllUsableBeatmapSets().First();
|
||||
});
|
||||
}
|
||||
|
||||
protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) => beatmaps.GetWorkingBeatmap(importedSet?.Beatmaps.First()).Beatmap;
|
||||
|
||||
private Ruleset? customRuleset;
|
||||
|
||||
protected override Ruleset CreatePlayerRuleset() => customRuleset ?? new OsuRuleset();
|
||||
|
||||
protected override TestPlayer CreatePlayer(Ruleset ruleset) => new TestPlayer(false);
|
||||
|
||||
protected override bool HasCustomSteps => true;
|
||||
|
||||
protected override bool AllowFail => false;
|
||||
|
||||
[Test]
|
||||
public void TestScoreStoredLocally()
|
||||
{
|
||||
AddStep("set no custom ruleset", () => customRuleset = null);
|
||||
|
||||
CreateTest();
|
||||
|
||||
AddUntilStep("wait for track to start running", () => Beatmap.Value.Track.IsRunning);
|
||||
|
||||
AddStep("seek to completion", () => Player.GameplayClockContainer.Seek(Player.DrawableRuleset.Objects.Last().GetEndTime()));
|
||||
|
||||
AddUntilStep("results displayed", () => Player.GetChildScreen() is ResultsScreen);
|
||||
AddUntilStep("score in database", () => Realm.Run(r => r.Find<ScoreInfo>(Player.Score.ScoreInfo.ID) != null));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestScoreStoredLocallyCustomRuleset()
|
||||
{
|
||||
Ruleset createCustomRuleset() => new CustomRuleset();
|
||||
|
||||
AddStep("import custom ruleset", () => Realm.Write(r => r.Add(createCustomRuleset().RulesetInfo)));
|
||||
AddStep("set custom ruleset", () => customRuleset = createCustomRuleset());
|
||||
|
||||
CreateTest();
|
||||
|
||||
AddAssert("score has custom ruleset", () => Player.Score.ScoreInfo.Ruleset.Equals(customRuleset.AsNonNull().RulesetInfo));
|
||||
|
||||
AddUntilStep("wait for track to start running", () => Beatmap.Value.Track.IsRunning);
|
||||
|
||||
AddStep("seek to completion", () => Player.GameplayClockContainer.Seek(Player.DrawableRuleset.Objects.Last().GetEndTime()));
|
||||
|
||||
AddUntilStep("results displayed", () => Player.GetChildScreen() is ResultsScreen);
|
||||
AddUntilStep("score in database", () => Realm.Run(r => r.Find<ScoreInfo>(Player.Score.ScoreInfo.ID) != null));
|
||||
}
|
||||
|
||||
private class CustomRuleset : OsuRuleset, ILegacyRuleset
|
||||
{
|
||||
public override string Description => "custom";
|
||||
public override string ShortName => "custom";
|
||||
|
||||
int ILegacyRuleset.LegacyID => -1;
|
||||
|
||||
public override ScoreProcessor CreateScoreProcessor() => new ScoreProcessor(this);
|
||||
}
|
||||
}
|
||||
}
|
@ -365,21 +365,9 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
|
||||
ImportedScore = score;
|
||||
|
||||
// It was discovered that Score members could sometimes be half-populated.
|
||||
// In particular, the RulesetID property could be set to 0 even on non-osu! maps.
|
||||
// We want to test that the state of that property is consistent in this test.
|
||||
// EF makes this impossible.
|
||||
//
|
||||
// First off, because of the EF navigational property-explicit foreign key field duality,
|
||||
// it can happen that - for example - the Ruleset navigational property is correctly initialised to mania,
|
||||
// but the RulesetID foreign key property is not initialised and remains 0.
|
||||
// EF silently bypasses this by prioritising the Ruleset navigational property over the RulesetID foreign key one.
|
||||
//
|
||||
// Additionally, adding an entity to an EF DbSet CAUSES SIDE EFFECTS with regard to the foreign key property.
|
||||
// In the above instance, if a ScoreInfo with Ruleset = {mania} and RulesetID = 0 is attached to an EF context,
|
||||
// RulesetID WILL BE SILENTLY SET TO THE CORRECT VALUE of 3.
|
||||
//
|
||||
// For the above reasons, actual importing is disabled in this test.
|
||||
// Calling base.ImportScore is omitted as it will fail for the test method which uses a custom ruleset.
|
||||
// This can be resolved by doing something similar to what TestScenePlayerLocalScoreImport is doing,
|
||||
// but requires a bit of restructuring.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -142,6 +142,28 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
AddAssert("button is not enabled", () => !downloadButton.ChildrenOfType<DownloadButton>().First().Enabled.Value);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestLocallyAvailableWithoutReplay()
|
||||
{
|
||||
Live<ScoreInfo> imported = null;
|
||||
|
||||
AddStep("import score", () => imported = scoreManager.Import(getScoreInfo(false, false)));
|
||||
|
||||
AddStep("create button without replay", () =>
|
||||
{
|
||||
Child = downloadButton = new TestReplayDownloadButton(imported.Value)
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
};
|
||||
});
|
||||
|
||||
AddUntilStep("wait for load", () => downloadButton.IsLoaded);
|
||||
|
||||
AddUntilStep("state is not downloaded", () => downloadButton.State.Value == DownloadState.NotDownloaded);
|
||||
AddAssert("button is not enabled", () => !downloadButton.ChildrenOfType<DownloadButton>().First().Enabled.Value);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestScoreImportThenDelete()
|
||||
{
|
||||
@ -189,11 +211,11 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
AddAssert("button is not enabled", () => !downloadButton.ChildrenOfType<DownloadButton>().First().Enabled.Value);
|
||||
}
|
||||
|
||||
private ScoreInfo getScoreInfo(bool replayAvailable)
|
||||
private ScoreInfo getScoreInfo(bool replayAvailable, bool hasOnlineId = true)
|
||||
{
|
||||
return new APIScore
|
||||
{
|
||||
OnlineID = online_score_id,
|
||||
OnlineID = hasOnlineId ? online_score_id : 0,
|
||||
RulesetID = 0,
|
||||
Beatmap = CreateAPIBeatmapSet(new OsuRuleset().RulesetInfo).Beatmaps.First(),
|
||||
HasReplay = replayAvailable,
|
||||
|
@ -24,10 +24,11 @@ namespace osu.Game.Tests.Visual.Menus
|
||||
public void TestMusicPlayAction()
|
||||
{
|
||||
AddStep("ensure playing something", () => Game.MusicController.EnsurePlayingSomething());
|
||||
AddUntilStep("music playing", () => Game.MusicController.IsPlaying);
|
||||
AddStep("toggle playback", () => globalActionContainer.TriggerPressed(GlobalAction.MusicPlay));
|
||||
AddAssert("music paused", () => !Game.MusicController.IsPlaying && Game.MusicController.UserPauseRequested);
|
||||
AddUntilStep("music paused", () => !Game.MusicController.IsPlaying && Game.MusicController.UserPauseRequested);
|
||||
AddStep("toggle playback", () => globalActionContainer.TriggerPressed(GlobalAction.MusicPlay));
|
||||
AddAssert("music resumed", () => Game.MusicController.IsPlaying && !Game.MusicController.UserPauseRequested);
|
||||
AddUntilStep("music resumed", () => Game.MusicController.IsPlaying && !Game.MusicController.UserPauseRequested);
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -47,7 +47,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
|
||||
dependencies.Cache(rulesetStore = new RealmRulesetStore(Realm));
|
||||
dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, Realm, rulesetStore, null, dependencies.Get<AudioManager>(), Resources, dependencies.Get<GameHost>(), Beatmap.Default));
|
||||
dependencies.Cache(scoreManager = new ScoreManager(rulesetStore, () => beatmapManager, LocalStorage, Realm, Scheduler));
|
||||
dependencies.Cache(scoreManager = new ScoreManager(rulesetStore, () => beatmapManager, LocalStorage, Realm, Scheduler, API));
|
||||
Dependencies.Cache(Realm);
|
||||
|
||||
return dependencies;
|
||||
|
@ -32,7 +32,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
{
|
||||
Dependencies.Cache(rulesets = new RealmRulesetStore(Realm));
|
||||
Dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, Realm, rulesets, null, audio, Resources, host, Beatmap.Default));
|
||||
Dependencies.Cache(scoreManager = new ScoreManager(rulesets, () => beatmapManager, LocalStorage, Realm, Scheduler));
|
||||
Dependencies.Cache(scoreManager = new ScoreManager(rulesets, () => beatmapManager, LocalStorage, Realm, Scheduler, API));
|
||||
Dependencies.Cache(Realm);
|
||||
|
||||
beatmapManager.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely();
|
||||
|
@ -74,7 +74,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
|
||||
dependencies.Cache(rulesetStore = new RealmRulesetStore(Realm));
|
||||
dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, Realm, rulesetStore, null, dependencies.Get<AudioManager>(), Resources, dependencies.Get<GameHost>(), Beatmap.Default));
|
||||
dependencies.Cache(scoreManager = new ScoreManager(dependencies.Get<RulesetStore>(), () => beatmapManager, LocalStorage, Realm, Scheduler));
|
||||
dependencies.Cache(scoreManager = new ScoreManager(dependencies.Get<RulesetStore>(), () => beatmapManager, LocalStorage, Realm, Scheduler, API));
|
||||
Dependencies.Cache(Realm);
|
||||
|
||||
return dependencies;
|
||||
|
@ -1,14 +1,13 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="..\osu.TestProject.props" />
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||
<PackageReference Include="DeepEqual" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
|
||||
<PackageReference Include="Nito.AsyncEx" Version="5.1.2" />
|
||||
<PackageReference Include="NUnit" Version="3.13.3" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.1.0" />
|
||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||
<PackageReference Include="Moq" Version="4.17.2" />
|
||||
<PackageReference Include="Moq" Version="4.18.1" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Project">
|
||||
<OutputType>WinExe</OutputType>
|
||||
|
@ -4,7 +4,6 @@
|
||||
<StartupObject>osu.Game.Tournament.Tests.TournamentTestRunner</StartupObject>
|
||||
</PropertyGroup>
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
|
||||
<PackageReference Include="NUnit" Version="3.13.3" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.1.0" />
|
||||
|
@ -258,15 +258,13 @@ namespace osu.Game.Database
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
bool checkedExisting = false;
|
||||
TModel? existing = null;
|
||||
TModel? existing;
|
||||
|
||||
if (batchImport && archive != null)
|
||||
{
|
||||
// this is a fast bail condition to improve large import performance.
|
||||
item.Hash = computeHashFast(archive);
|
||||
|
||||
checkedExisting = true;
|
||||
existing = CheckForExisting(item, realm);
|
||||
|
||||
if (existing != null)
|
||||
@ -311,8 +309,12 @@ namespace osu.Game.Database
|
||||
// TODO: we may want to run this outside of the transaction.
|
||||
Populate(item, archive, realm, cancellationToken);
|
||||
|
||||
if (!checkedExisting)
|
||||
existing = CheckForExisting(item, realm);
|
||||
// Populate() may have adjusted file content (see SkinImporter.updateSkinIniMetadata), so regardless of whether a fast check was done earlier, let's
|
||||
// check for existing items a second time.
|
||||
//
|
||||
// If this is ever a performance issue, the fast-check hash can be compared and trigger a skip of this second check if it still matches.
|
||||
// I don't think it is a huge deal doing a second indexed check, though.
|
||||
existing = CheckForExisting(item, realm);
|
||||
|
||||
if (existing != null)
|
||||
{
|
||||
@ -336,11 +338,11 @@ namespace osu.Game.Database
|
||||
// import to store
|
||||
realm.Add(item);
|
||||
|
||||
PostImport(item, realm);
|
||||
|
||||
transaction.Commit();
|
||||
}
|
||||
|
||||
PostImport(item, realm);
|
||||
|
||||
LogForModel(item, @"Import successfully completed!");
|
||||
}
|
||||
catch (Exception e)
|
||||
@ -477,7 +479,7 @@ namespace osu.Game.Database
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Perform any final actions after the import has been committed to the database.
|
||||
/// Perform any final actions before the import has been committed to the database.
|
||||
/// </summary>
|
||||
/// <param name="model">The model prepared for import.</param>
|
||||
/// <param name="realm">The current realm context.</param>
|
||||
|
@ -38,15 +38,21 @@ namespace osu.Game.Graphics.Backgrounds
|
||||
private void load(OsuConfigManager config, SessionStatics sessionStatics)
|
||||
{
|
||||
seasonalBackgroundMode = config.GetBindable<SeasonalBackgroundMode>(OsuSetting.SeasonalBackgroundMode);
|
||||
seasonalBackgroundMode.BindValueChanged(_ => SeasonalBackgroundChanged?.Invoke());
|
||||
seasonalBackgroundMode.BindValueChanged(_ => triggerSeasonalBackgroundChanged());
|
||||
|
||||
seasonalBackgrounds = sessionStatics.GetBindable<APISeasonalBackgrounds>(Static.SeasonalBackgrounds);
|
||||
seasonalBackgrounds.BindValueChanged(_ => SeasonalBackgroundChanged?.Invoke());
|
||||
seasonalBackgrounds.BindValueChanged(_ => triggerSeasonalBackgroundChanged());
|
||||
|
||||
apiState.BindTo(api.State);
|
||||
apiState.BindValueChanged(fetchSeasonalBackgrounds, true);
|
||||
}
|
||||
|
||||
private void triggerSeasonalBackgroundChanged()
|
||||
{
|
||||
if (shouldShowSeasonal)
|
||||
SeasonalBackgroundChanged?.Invoke();
|
||||
}
|
||||
|
||||
private void fetchSeasonalBackgrounds(ValueChangedEvent<APIState> stateChanged)
|
||||
{
|
||||
if (seasonalBackgrounds.Value != null || stateChanged.NewValue != APIState.Online)
|
||||
@ -64,15 +70,10 @@ namespace osu.Game.Graphics.Backgrounds
|
||||
|
||||
public SeasonalBackground LoadNextBackground()
|
||||
{
|
||||
if (seasonalBackgroundMode.Value == SeasonalBackgroundMode.Never
|
||||
|| (seasonalBackgroundMode.Value == SeasonalBackgroundMode.Sometimes && !isInSeason))
|
||||
{
|
||||
if (!shouldShowSeasonal)
|
||||
return null;
|
||||
}
|
||||
|
||||
var backgrounds = seasonalBackgrounds.Value?.Backgrounds;
|
||||
if (backgrounds == null || !backgrounds.Any())
|
||||
return null;
|
||||
var backgrounds = seasonalBackgrounds.Value.Backgrounds;
|
||||
|
||||
current = (current + 1) % backgrounds.Count;
|
||||
string url = backgrounds[current].Url;
|
||||
@ -80,6 +81,20 @@ namespace osu.Game.Graphics.Backgrounds
|
||||
return new SeasonalBackground(url);
|
||||
}
|
||||
|
||||
private bool shouldShowSeasonal
|
||||
{
|
||||
get
|
||||
{
|
||||
if (seasonalBackgroundMode.Value == SeasonalBackgroundMode.Never)
|
||||
return false;
|
||||
|
||||
if (seasonalBackgroundMode.Value == SeasonalBackgroundMode.Sometimes && !isInSeason)
|
||||
return false;
|
||||
|
||||
return seasonalBackgrounds.Value?.Backgrounds?.Any() == true;
|
||||
}
|
||||
}
|
||||
|
||||
private bool isInSeason => seasonalBackgrounds.Value != null && DateTimeOffset.Now < seasonalBackgrounds.Value.EndDate;
|
||||
}
|
||||
|
||||
|
@ -19,7 +19,7 @@ namespace osu.Game.IO
|
||||
|
||||
public LineBufferedReader(Stream stream, bool leaveOpen = false)
|
||||
{
|
||||
streamReader = new StreamReader(stream, Encoding.UTF8, true, -1, leaveOpen);
|
||||
streamReader = new StreamReader(stream, Encoding.UTF8, true, 1024, leaveOpen);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -272,7 +272,7 @@ namespace osu.Game
|
||||
dependencies.Cache(difficultyCache = new BeatmapDifficultyCache());
|
||||
|
||||
// ordering is important here to ensure foreign keys rules are not broken in ModelStore.Cleanup()
|
||||
dependencies.Cache(ScoreManager = new ScoreManager(RulesetStore, () => BeatmapManager, Storage, realm, Scheduler, difficultyCache, LocalConfig));
|
||||
dependencies.Cache(ScoreManager = new ScoreManager(RulesetStore, () => BeatmapManager, Storage, realm, Scheduler, API, difficultyCache, LocalConfig));
|
||||
|
||||
dependencies.Cache(BeatmapManager = new BeatmapManager(Storage, realm, RulesetStore, API, Audio, Resources, Host, defaultBeatmap, difficultyCache, performOnlineLookups: true));
|
||||
|
||||
|
@ -13,6 +13,9 @@ using osu.Game.Database;
|
||||
using osu.Game.IO.Archives;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Scoring.Legacy;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Online.API.Requests;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using Realms;
|
||||
|
||||
namespace osu.Game.Scoring
|
||||
@ -26,11 +29,14 @@ namespace osu.Game.Scoring
|
||||
private readonly RulesetStore rulesets;
|
||||
private readonly Func<BeatmapManager> beatmaps;
|
||||
|
||||
public ScoreImporter(RulesetStore rulesets, Func<BeatmapManager> beatmaps, Storage storage, RealmAccess realm)
|
||||
private readonly IAPIProvider api;
|
||||
|
||||
public ScoreImporter(RulesetStore rulesets, Func<BeatmapManager> beatmaps, Storage storage, RealmAccess realm, IAPIProvider api)
|
||||
: base(storage, realm)
|
||||
{
|
||||
this.rulesets = rulesets;
|
||||
this.beatmaps = beatmaps;
|
||||
this.api = api;
|
||||
}
|
||||
|
||||
protected override ScoreInfo? CreateModel(ArchiveReader archive)
|
||||
@ -68,5 +74,17 @@ namespace osu.Game.Scoring
|
||||
if (string.IsNullOrEmpty(model.StatisticsJson))
|
||||
model.StatisticsJson = JsonConvert.SerializeObject(model.Statistics);
|
||||
}
|
||||
|
||||
protected override void PostImport(ScoreInfo model, Realm realm)
|
||||
{
|
||||
base.PostImport(model, realm);
|
||||
|
||||
var userRequest = new GetUserRequest(model.RealmUser.Username);
|
||||
|
||||
api.Perform(userRequest);
|
||||
|
||||
if (userRequest.Response is APIUser user)
|
||||
model.RealmUser.OnlineID = user.Id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ using osu.Game.IO.Archives;
|
||||
using osu.Game.Overlays.Notifications;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Online.API;
|
||||
|
||||
namespace osu.Game.Scoring
|
||||
{
|
||||
@ -31,7 +32,7 @@ namespace osu.Game.Scoring
|
||||
private readonly OsuConfigManager configManager;
|
||||
private readonly ScoreImporter scoreImporter;
|
||||
|
||||
public ScoreManager(RulesetStore rulesets, Func<BeatmapManager> beatmaps, Storage storage, RealmAccess realm, Scheduler scheduler,
|
||||
public ScoreManager(RulesetStore rulesets, Func<BeatmapManager> beatmaps, Storage storage, RealmAccess realm, Scheduler scheduler, IAPIProvider api,
|
||||
BeatmapDifficultyCache difficultyCache = null, OsuConfigManager configManager = null)
|
||||
: base(storage, realm)
|
||||
{
|
||||
@ -39,7 +40,7 @@ namespace osu.Game.Scoring
|
||||
this.difficultyCache = difficultyCache;
|
||||
this.configManager = configManager;
|
||||
|
||||
scoreImporter = new ScoreImporter(rulesets, beatmaps, storage, realm)
|
||||
scoreImporter = new ScoreImporter(rulesets, beatmaps, storage, realm, api)
|
||||
{
|
||||
PostNotification = obj => PostNotification?.Invoke(obj)
|
||||
};
|
||||
|
@ -7,6 +7,7 @@ using System.Threading;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Logging;
|
||||
using osu.Framework.Threading;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Game.Beatmaps;
|
||||
@ -26,7 +27,7 @@ namespace osu.Game.Screens.Backgrounds
|
||||
private const int background_count = 7;
|
||||
private IBindable<APIUser> user;
|
||||
private Bindable<Skin> skin;
|
||||
private Bindable<BackgroundSource> mode;
|
||||
private Bindable<BackgroundSource> source;
|
||||
private Bindable<IntroSequence> introSequence;
|
||||
private readonly SeasonalBackgroundLoader seasonalBackgroundLoader = new SeasonalBackgroundLoader();
|
||||
|
||||
@ -45,24 +46,29 @@ namespace osu.Game.Screens.Backgrounds
|
||||
{
|
||||
user = api.LocalUser.GetBoundCopy();
|
||||
skin = skinManager.CurrentSkin.GetBoundCopy();
|
||||
mode = config.GetBindable<BackgroundSource>(OsuSetting.MenuBackgroundSource);
|
||||
source = config.GetBindable<BackgroundSource>(OsuSetting.MenuBackgroundSource);
|
||||
introSequence = config.GetBindable<IntroSequence>(OsuSetting.IntroSequence);
|
||||
|
||||
AddInternal(seasonalBackgroundLoader);
|
||||
|
||||
user.ValueChanged += _ => Scheduler.AddOnce(loadNextIfRequired);
|
||||
skin.ValueChanged += _ => Scheduler.AddOnce(loadNextIfRequired);
|
||||
mode.ValueChanged += _ => Scheduler.AddOnce(loadNextIfRequired);
|
||||
beatmap.ValueChanged += _ => Scheduler.AddOnce(loadNextIfRequired);
|
||||
introSequence.ValueChanged += _ => Scheduler.AddOnce(loadNextIfRequired);
|
||||
seasonalBackgroundLoader.SeasonalBackgroundChanged += () => Scheduler.AddOnce(loadNextIfRequired);
|
||||
|
||||
// Load first background asynchronously as part of BDL load.
|
||||
currentDisplay = RNG.Next(0, background_count);
|
||||
|
||||
Next();
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
user.ValueChanged += _ => Scheduler.AddOnce(next);
|
||||
skin.ValueChanged += _ => Scheduler.AddOnce(next);
|
||||
source.ValueChanged += _ => Scheduler.AddOnce(next);
|
||||
beatmap.ValueChanged += _ => Scheduler.AddOnce(next);
|
||||
introSequence.ValueChanged += _ => Scheduler.AddOnce(next);
|
||||
seasonalBackgroundLoader.SeasonalBackgroundChanged += () => Scheduler.AddOnce(next);
|
||||
|
||||
// helper function required for AddOnce usage.
|
||||
void loadNextIfRequired() => Next();
|
||||
void next() => Next();
|
||||
}
|
||||
|
||||
private ScheduledDelegate nextTask;
|
||||
@ -80,6 +86,8 @@ namespace osu.Game.Screens.Backgrounds
|
||||
if (nextBackground == background)
|
||||
return false;
|
||||
|
||||
Logger.Log("🌅 Background change queued");
|
||||
|
||||
cancellationTokenSource?.Cancel();
|
||||
cancellationTokenSource = new CancellationTokenSource();
|
||||
|
||||
@ -108,12 +116,12 @@ namespace osu.Game.Screens.Backgrounds
|
||||
|
||||
if (newBackground == null && user.Value?.IsSupporter == true)
|
||||
{
|
||||
switch (mode.Value)
|
||||
switch (source.Value)
|
||||
{
|
||||
case BackgroundSource.Beatmap:
|
||||
case BackgroundSource.BeatmapWithStoryboard:
|
||||
{
|
||||
if (mode.Value == BackgroundSource.BeatmapWithStoryboard && AllowStoryboardBackground)
|
||||
if (source.Value == BackgroundSource.BeatmapWithStoryboard && AllowStoryboardBackground)
|
||||
newBackground = new BeatmapBackgroundWithStoryboard(beatmap.Value, getBackgroundTextureName());
|
||||
newBackground ??= new BeatmapBackground(beatmap.Value, getBackgroundTextureName());
|
||||
|
||||
|
@ -921,7 +921,7 @@ namespace osu.Game.Screens.Edit
|
||||
|
||||
private void cancelExit()
|
||||
{
|
||||
samplePlaybackDisabled.Value = false;
|
||||
updateSampleDisabledState();
|
||||
loader?.CancelPendingDifficultySwitch();
|
||||
}
|
||||
|
||||
|
@ -88,6 +88,11 @@ namespace osu.Game.Screens.Menu
|
||||
/// </summary>
|
||||
protected bool UsingThemedIntro { get; private set; }
|
||||
|
||||
protected override BackgroundScreen CreateBackground() => new BackgroundScreenDefault(false)
|
||||
{
|
||||
Colour = Color4.Black
|
||||
};
|
||||
|
||||
protected IntroScreen([CanBeNull] Func<MainMenu> createNextScreen = null)
|
||||
{
|
||||
this.createNextScreen = createNextScreen;
|
||||
@ -201,6 +206,8 @@ namespace osu.Game.Screens.Menu
|
||||
{
|
||||
this.FadeIn(300);
|
||||
|
||||
ApplyToBackground(b => b.FadeColour(Color4.Black, 100));
|
||||
|
||||
double fadeOutTime = exit_delay;
|
||||
|
||||
var track = musicController.CurrentTrack;
|
||||
@ -243,13 +250,22 @@ namespace osu.Game.Screens.Menu
|
||||
base.OnResuming(e);
|
||||
}
|
||||
|
||||
private bool backgroundFaded;
|
||||
|
||||
protected void FadeInBackground(float duration = 0)
|
||||
{
|
||||
ApplyToBackground(b => b.FadeColour(Color4.White, duration));
|
||||
backgroundFaded = true;
|
||||
}
|
||||
|
||||
public override void OnSuspending(ScreenTransitionEvent e)
|
||||
{
|
||||
base.OnSuspending(e);
|
||||
initialBeatmap = null;
|
||||
}
|
||||
|
||||
protected override BackgroundScreen CreateBackground() => new BackgroundScreenBlack();
|
||||
if (!backgroundFaded)
|
||||
FadeInBackground(200);
|
||||
}
|
||||
|
||||
protected virtual void StartTrack()
|
||||
{
|
||||
|
@ -8,19 +8,18 @@ using JetBrains.Annotations;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Audio.Sample;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Framework.Logging;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Framework.Timing;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Screens.Backgrounds;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
@ -32,16 +31,9 @@ namespace osu.Game.Screens.Menu
|
||||
|
||||
protected override string BeatmapFile => "triangles.osz";
|
||||
|
||||
protected override BackgroundScreen CreateBackground() => background = new BackgroundScreenDefault(false)
|
||||
{
|
||||
Alpha = 0,
|
||||
};
|
||||
|
||||
[Resolved]
|
||||
private AudioManager audio { get; set; }
|
||||
|
||||
private BackgroundScreenDefault background;
|
||||
|
||||
private Sample welcome;
|
||||
|
||||
private DecoupleableInterpolatingFramedClock decoupledClock;
|
||||
@ -75,7 +67,7 @@ namespace osu.Game.Screens.Menu
|
||||
if (UsingThemedIntro)
|
||||
decoupledClock.ChangeSource(Track);
|
||||
|
||||
LoadComponentAsync(intro = new TrianglesIntroSequence(logo, background)
|
||||
LoadComponentAsync(intro = new TrianglesIntroSequence(logo, () => FadeInBackground())
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Clock = decoupledClock,
|
||||
@ -95,19 +87,10 @@ namespace osu.Game.Screens.Menu
|
||||
{
|
||||
base.OnSuspending(e);
|
||||
|
||||
// ensure the background is shown, even if the TriangleIntroSequence failed to do so.
|
||||
background.ApplyToBackground(b => b.Show());
|
||||
|
||||
// important as there is a clock attached to a track which will likely be disposed before returning to this screen.
|
||||
intro.Expire();
|
||||
}
|
||||
|
||||
public override void OnResuming(ScreenTransitionEvent e)
|
||||
{
|
||||
base.OnResuming(e);
|
||||
background.FadeOut(100);
|
||||
}
|
||||
|
||||
protected override void StartTrack()
|
||||
{
|
||||
decoupledClock.Start();
|
||||
@ -116,7 +99,7 @@ namespace osu.Game.Screens.Menu
|
||||
private class TrianglesIntroSequence : CompositeDrawable
|
||||
{
|
||||
private readonly OsuLogo logo;
|
||||
private readonly BackgroundScreenDefault background;
|
||||
private readonly Action showBackgroundAction;
|
||||
private OsuSpriteText welcomeText;
|
||||
|
||||
private RulesetFlow rulesets;
|
||||
@ -128,10 +111,10 @@ namespace osu.Game.Screens.Menu
|
||||
|
||||
public Action LoadMenu;
|
||||
|
||||
public TrianglesIntroSequence(OsuLogo logo, BackgroundScreenDefault background)
|
||||
public TrianglesIntroSequence(OsuLogo logo, Action showBackgroundAction)
|
||||
{
|
||||
this.logo = logo;
|
||||
this.background = background;
|
||||
this.showBackgroundAction = showBackgroundAction;
|
||||
}
|
||||
|
||||
[Resolved]
|
||||
@ -205,7 +188,6 @@ namespace osu.Game.Screens.Menu
|
||||
|
||||
rulesets.Hide();
|
||||
lazerLogo.Hide();
|
||||
background.ApplyToBackground(b => b.Hide());
|
||||
|
||||
using (BeginAbsoluteSequence(0))
|
||||
{
|
||||
@ -267,7 +249,7 @@ namespace osu.Game.Screens.Menu
|
||||
|
||||
logo.FadeIn();
|
||||
|
||||
background.ApplyToBackground(b => b.Show());
|
||||
showBackgroundAction();
|
||||
|
||||
game.Add(new GameWideFlash());
|
||||
|
||||
|
@ -5,11 +5,9 @@
|
||||
|
||||
using System;
|
||||
using JetBrains.Annotations;
|
||||
using osuTK;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Audio.Sample;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
@ -17,8 +15,8 @@ using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Game.Audio;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Screens.Backgrounds;
|
||||
using osu.Game.Skinning;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Screens.Menu
|
||||
@ -35,13 +33,6 @@ namespace osu.Game.Screens.Menu
|
||||
private ISample pianoReverb;
|
||||
protected override string SeeyaSampleName => "Intro/Welcome/seeya";
|
||||
|
||||
protected override BackgroundScreen CreateBackground() => background = new BackgroundScreenDefault(false)
|
||||
{
|
||||
Alpha = 0,
|
||||
};
|
||||
|
||||
private BackgroundScreenDefault background;
|
||||
|
||||
public IntroWelcome([CanBeNull] Func<MainMenu> createNextScreen = null)
|
||||
: base(createNextScreen)
|
||||
{
|
||||
@ -100,7 +91,7 @@ namespace osu.Game.Screens.Menu
|
||||
logo.ScaleTo(1);
|
||||
logo.FadeIn(fade_in_time);
|
||||
|
||||
background.FadeIn(fade_in_time);
|
||||
FadeInBackground(fade_in_time);
|
||||
|
||||
LoadMenu();
|
||||
}, delay_step_two);
|
||||
@ -108,12 +99,6 @@ namespace osu.Game.Screens.Menu
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnResuming(ScreenTransitionEvent e)
|
||||
{
|
||||
base.OnResuming(e);
|
||||
background.FadeOut(100);
|
||||
}
|
||||
|
||||
private class WelcomeIntroSequence : Container
|
||||
{
|
||||
private Drawable welcomeText;
|
||||
|
@ -65,9 +65,7 @@ namespace osu.Game.Screens.Menu
|
||||
[Resolved(canBeNull: true)]
|
||||
private IDialogOverlay dialogOverlay { get; set; }
|
||||
|
||||
private BackgroundScreenDefault background;
|
||||
|
||||
protected override BackgroundScreen CreateBackground() => background;
|
||||
protected override BackgroundScreen CreateBackground() => new BackgroundScreenDefault();
|
||||
|
||||
protected override bool PlayExitSound => false;
|
||||
|
||||
@ -148,7 +146,6 @@ namespace osu.Game.Screens.Menu
|
||||
Buttons.OnSettings = () => settings?.ToggleVisibility();
|
||||
Buttons.OnBeatmapListing = () => beatmapListing?.ToggleVisibility();
|
||||
|
||||
LoadComponentAsync(background = new BackgroundScreenDefault());
|
||||
preloadSongSelect();
|
||||
}
|
||||
|
||||
|
@ -314,6 +314,9 @@ namespace osu.Game.Screens.OnlinePlay.Match
|
||||
|
||||
public override void OnSuspending(ScreenTransitionEvent e)
|
||||
{
|
||||
// Should be a noop in most cases, but let's ensure beyond doubt that the beatmap is in a correct state.
|
||||
updateWorkingBeatmap();
|
||||
|
||||
onLeaving();
|
||||
base.OnSuspending(e);
|
||||
}
|
||||
|
@ -53,9 +53,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate
|
||||
[CanBeNull]
|
||||
public Score Score { get; private set; }
|
||||
|
||||
[Resolved]
|
||||
private BeatmapManager beatmapManager { get; set; }
|
||||
|
||||
private readonly BindableDouble volumeAdjustment = new BindableDouble();
|
||||
private readonly Container gameplayContent;
|
||||
private readonly LoadingLayer loadingLayer;
|
||||
@ -84,6 +81,9 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate
|
||||
GameplayClock.Source = masterClock;
|
||||
}
|
||||
|
||||
[Resolved]
|
||||
private IBindable<WorkingBeatmap> beatmap { get; set; }
|
||||
|
||||
public void LoadScore([NotNull] Score score)
|
||||
{
|
||||
if (Score != null)
|
||||
@ -91,7 +91,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate
|
||||
|
||||
Score = score;
|
||||
|
||||
gameplayContent.Child = new PlayerIsolationContainer(beatmapManager.GetWorkingBeatmap(Score.ScoreInfo.BeatmapInfo), Score.ScoreInfo.Ruleset, Score.ScoreInfo.Mods)
|
||||
gameplayContent.Child = new PlayerIsolationContainer(beatmap.Value, Score.ScoreInfo.Ruleset, Score.ScoreInfo.Mods)
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Child = stack = new OsuScreenStack
|
||||
|
@ -140,9 +140,14 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
|
||||
},
|
||||
new Section("Duration")
|
||||
{
|
||||
Child = DurationField = new DurationDropdown
|
||||
Child = new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Height = 40,
|
||||
Child = DurationField = new DurationDropdown
|
||||
{
|
||||
RelativeSizeAxes = Axes.X
|
||||
}
|
||||
}
|
||||
},
|
||||
new Section("Allowed attempts (across all playlist items)")
|
||||
|
@ -22,6 +22,7 @@ using osu.Framework.Threading;
|
||||
using osu.Game.Audio;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Extensions;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.IO.Archives;
|
||||
using osu.Game.Online.API;
|
||||
@ -1064,12 +1065,15 @@ namespace osu.Game.Screens.Play
|
||||
if (DrawableRuleset.ReplayScore != null)
|
||||
return Task.CompletedTask;
|
||||
|
||||
LegacyByteArrayReader replayReader;
|
||||
LegacyByteArrayReader replayReader = null;
|
||||
|
||||
using (var stream = new MemoryStream())
|
||||
if (score.ScoreInfo.Ruleset.IsLegacyRuleset())
|
||||
{
|
||||
new LegacyScoreEncoder(score, GameplayState.Beatmap).Encode(stream);
|
||||
replayReader = new LegacyByteArrayReader(stream.ToArray(), "replay.osr");
|
||||
using (var stream = new MemoryStream())
|
||||
{
|
||||
new LegacyScoreEncoder(score, GameplayState.Beatmap).Encode(stream);
|
||||
replayReader = new LegacyByteArrayReader(stream.ToArray(), "replay.osr");
|
||||
}
|
||||
}
|
||||
|
||||
// the import process will re-attach managed beatmap/rulesets to this score. we don't want this for now, so create a temporary copy to import.
|
||||
|
@ -49,7 +49,7 @@ namespace osu.Game.Tests.Visual
|
||||
|
||||
action?.Invoke();
|
||||
|
||||
AddStep(CreatePlayerRuleset().Description, LoadPlayer);
|
||||
AddStep($"Load player for {CreatePlayerRuleset().Description}", LoadPlayer);
|
||||
AddUntilStep("player loaded", () => Player.IsLoaded && Player.Alpha == 1);
|
||||
}
|
||||
|
||||
|
@ -20,12 +20,12 @@
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="AutoMapper" Version="11.0.1" />
|
||||
<PackageReference Include="DiffPlex" Version="1.7.1" />
|
||||
<PackageReference Include="HtmlAgilityPack" Version="1.11.42" />
|
||||
<PackageReference Include="HtmlAgilityPack" Version="1.11.43" />
|
||||
<PackageReference Include="Humanizer" Version="2.14.1" />
|
||||
<PackageReference Include="MessagePack" Version="2.3.85" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="6.0.5" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.MessagePack" Version="6.0.5" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.NewtonsoftJson" Version="6.0.5" />
|
||||
<PackageReference Include="MessagePack" Version="2.4.35" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="6.0.6" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.MessagePack" Version="6.0.6" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.NewtonsoftJson" Version="6.0.6" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="5.0.14" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="5.0.14" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="6.0.0" />
|
||||
@ -38,8 +38,8 @@
|
||||
<PackageReference Include="Realm" Version="10.14.0" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2022.707.0" />
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2022.702.0" />
|
||||
<PackageReference Include="Sentry" Version="3.17.1" />
|
||||
<PackageReference Include="SharpCompress" Version="0.31.0" />
|
||||
<PackageReference Include="Sentry" Version="3.19.0" />
|
||||
<PackageReference Include="SharpCompress" Version="0.32.1" />
|
||||
<PackageReference Include="NUnit" Version="3.13.3" />
|
||||
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
|
||||
<PackageReference Include="TagLibSharp" Version="2.2.0" />
|
||||
|
@ -85,7 +85,7 @@
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="5.0.14" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2022.707.0" />
|
||||
<PackageReference Include="SharpCompress" Version="0.31.0" />
|
||||
<PackageReference Include="SharpCompress" Version="0.32.1" />
|
||||
<PackageReference Include="NUnit" Version="3.13.3" />
|
||||
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.NativeLibs" Version="2022.429.0" ExcludeAssets="all" />
|
||||
|
Loading…
Reference in New Issue
Block a user