mirror of
https://github.com/osukey/osukey.git
synced 2025-07-02 00:40:09 +09:00
Merge branch 'master' into multiplayer-chat
This commit is contained in:
@ -52,7 +52,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.813.0" />
|
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.813.0" />
|
||||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2021.813.0" />
|
<PackageReference Include="ppy.osu.Framework.Android" Version="2021.818.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup Label="Transitive Dependencies">
|
<ItemGroup Label="Transitive Dependencies">
|
||||||
<!-- Realm needs to be directly referenced in all Xamarin projects, as it will not pull in its transitive dependencies otherwise. -->
|
<!-- Realm needs to be directly referenced in all Xamarin projects, as it will not pull in its transitive dependencies otherwise. -->
|
||||||
|
34
osu.Game.Benchmarks/BenchmarkMod.cs
Normal file
34
osu.Game.Benchmarks/BenchmarkMod.cs
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using BenchmarkDotNet.Attributes;
|
||||||
|
using osu.Game.Rulesets.Osu.Mods;
|
||||||
|
|
||||||
|
namespace osu.Game.Benchmarks
|
||||||
|
{
|
||||||
|
public class BenchmarkMod : BenchmarkTest
|
||||||
|
{
|
||||||
|
private OsuModDoubleTime mod;
|
||||||
|
|
||||||
|
[Params(1, 10, 100)]
|
||||||
|
public int Times { get; set; }
|
||||||
|
|
||||||
|
[GlobalSetup]
|
||||||
|
public void GlobalSetup()
|
||||||
|
{
|
||||||
|
mod = new OsuModDoubleTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public int ModHashCode()
|
||||||
|
{
|
||||||
|
var hashCode = new HashCode();
|
||||||
|
|
||||||
|
for (int i = 0; i < Times; i++)
|
||||||
|
hashCode.Add(mod);
|
||||||
|
|
||||||
|
return hashCode.ToHashCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -63,6 +63,8 @@ namespace osu.Game.Rulesets.Osu.Edit
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (hitObject is DrawableHitCircle circle)
|
if (hitObject is DrawableHitCircle circle)
|
||||||
|
{
|
||||||
|
using (circle.BeginAbsoluteSequence(circle.HitStateUpdateTime))
|
||||||
{
|
{
|
||||||
circle.ApproachCircle
|
circle.ApproachCircle
|
||||||
.FadeOutFromOne(EDITOR_HIT_OBJECT_FADE_OUT_EXTENSION * 4)
|
.FadeOutFromOne(EDITOR_HIT_OBJECT_FADE_OUT_EXTENSION * 4)
|
||||||
@ -70,6 +72,7 @@ namespace osu.Game.Rulesets.Osu.Edit
|
|||||||
|
|
||||||
circle.ApproachCircle.ScaleTo(1.1f, 300, Easing.OutQuint);
|
circle.ApproachCircle.ScaleTo(1.1f, 300, Easing.OutQuint);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (hitObject is IHasMainCirclePiece mainPieceContainer)
|
if (hitObject is IHasMainCirclePiece mainPieceContainer)
|
||||||
{
|
{
|
||||||
|
@ -1,56 +0,0 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
|
||||||
|
|
||||||
using NUnit.Framework;
|
|
||||||
using osu.Game.Beatmaps;
|
|
||||||
using osu.Game.Rulesets;
|
|
||||||
using osu.Game.Rulesets.Mods;
|
|
||||||
using osu.Game.Rulesets.Osu.Mods;
|
|
||||||
|
|
||||||
namespace osu.Game.Tests.Beatmaps
|
|
||||||
{
|
|
||||||
[TestFixture]
|
|
||||||
public class BeatmapDifficultyCacheTest
|
|
||||||
{
|
|
||||||
[Test]
|
|
||||||
public void TestKeyEqualsWithDifferentModInstances()
|
|
||||||
{
|
|
||||||
var key1 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = 1234 }, new RulesetInfo { ID = 0 }, new Mod[] { new OsuModHardRock(), new OsuModHidden() });
|
|
||||||
var key2 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = 1234 }, new RulesetInfo { ID = 0 }, new Mod[] { new OsuModHardRock(), new OsuModHidden() });
|
|
||||||
|
|
||||||
Assert.That(key1, Is.EqualTo(key2));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void TestKeyEqualsWithDifferentModOrder()
|
|
||||||
{
|
|
||||||
var key1 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = 1234 }, new RulesetInfo { ID = 0 }, new Mod[] { new OsuModHardRock(), new OsuModHidden() });
|
|
||||||
var key2 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = 1234 }, new RulesetInfo { ID = 0 }, new Mod[] { new OsuModHidden(), new OsuModHardRock() });
|
|
||||||
|
|
||||||
Assert.That(key1, Is.EqualTo(key2));
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestCase(1.3, DifficultyRating.Easy)]
|
|
||||||
[TestCase(1.993, DifficultyRating.Easy)]
|
|
||||||
[TestCase(1.998, DifficultyRating.Normal)]
|
|
||||||
[TestCase(2.4, DifficultyRating.Normal)]
|
|
||||||
[TestCase(2.693, DifficultyRating.Normal)]
|
|
||||||
[TestCase(2.698, DifficultyRating.Hard)]
|
|
||||||
[TestCase(3.5, DifficultyRating.Hard)]
|
|
||||||
[TestCase(3.993, DifficultyRating.Hard)]
|
|
||||||
[TestCase(3.997, DifficultyRating.Insane)]
|
|
||||||
[TestCase(5.0, DifficultyRating.Insane)]
|
|
||||||
[TestCase(5.292, DifficultyRating.Insane)]
|
|
||||||
[TestCase(5.297, DifficultyRating.Expert)]
|
|
||||||
[TestCase(6.2, DifficultyRating.Expert)]
|
|
||||||
[TestCase(6.493, DifficultyRating.Expert)]
|
|
||||||
[TestCase(6.498, DifficultyRating.ExpertPlus)]
|
|
||||||
[TestCase(8.3, DifficultyRating.ExpertPlus)]
|
|
||||||
public void TestDifficultyRatingMapping(double starRating, DifficultyRating expectedBracket)
|
|
||||||
{
|
|
||||||
var actualBracket = BeatmapDifficultyCache.GetDifficultyRating(starRating);
|
|
||||||
|
|
||||||
Assert.AreEqual(expectedBracket, actualBracket);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
146
osu.Game.Tests/Beatmaps/TestSceneBeatmapDifficultyCache.cs
Normal file
146
osu.Game.Tests/Beatmaps/TestSceneBeatmapDifficultyCache.cs
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Testing;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets;
|
||||||
|
using osu.Game.Rulesets.Mods;
|
||||||
|
using osu.Game.Rulesets.Osu.Mods;
|
||||||
|
using osu.Game.Tests.Beatmaps.IO;
|
||||||
|
using osu.Game.Tests.Visual;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.Beatmaps
|
||||||
|
{
|
||||||
|
[HeadlessTest]
|
||||||
|
public class TestSceneBeatmapDifficultyCache : OsuTestScene
|
||||||
|
{
|
||||||
|
public const double BASE_STARS = 5.55;
|
||||||
|
|
||||||
|
private BeatmapSetInfo importedSet;
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private BeatmapManager beatmaps { get; set; }
|
||||||
|
|
||||||
|
private TestBeatmapDifficultyCache difficultyCache;
|
||||||
|
|
||||||
|
private IBindable<StarDifficulty?> starDifficultyBindable;
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuGameBase osu)
|
||||||
|
{
|
||||||
|
importedSet = ImportBeatmapTest.LoadQuickOszIntoOsu(osu).Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
[SetUpSteps]
|
||||||
|
public void SetUpSteps()
|
||||||
|
{
|
||||||
|
AddStep("setup difficulty cache", () =>
|
||||||
|
{
|
||||||
|
SelectedMods.Value = Array.Empty<Mod>();
|
||||||
|
|
||||||
|
Child = difficultyCache = new TestBeatmapDifficultyCache();
|
||||||
|
|
||||||
|
starDifficultyBindable = difficultyCache.GetBindableDifficulty(importedSet.Beatmaps.First());
|
||||||
|
});
|
||||||
|
|
||||||
|
AddUntilStep($"star difficulty -> {BASE_STARS}", () => starDifficultyBindable.Value?.Stars == BASE_STARS);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestStarDifficultyChangesOnModSettings()
|
||||||
|
{
|
||||||
|
OsuModDoubleTime dt = null;
|
||||||
|
|
||||||
|
AddStep("change selected mod to DT", () => SelectedMods.Value = new[] { dt = new OsuModDoubleTime { SpeedChange = { Value = 1.5 } } });
|
||||||
|
AddUntilStep($"star difficulty -> {BASE_STARS + 1.5}", () => starDifficultyBindable.Value?.Stars == BASE_STARS + 1.5);
|
||||||
|
|
||||||
|
AddStep("change DT speed to 1.25", () => dt.SpeedChange.Value = 1.25);
|
||||||
|
AddUntilStep($"star difficulty -> {BASE_STARS + 1.25}", () => starDifficultyBindable.Value?.Stars == BASE_STARS + 1.25);
|
||||||
|
|
||||||
|
AddStep("change selected mod to NC", () => SelectedMods.Value = new[] { new OsuModNightcore { SpeedChange = { Value = 1.75 } } });
|
||||||
|
AddUntilStep($"star difficulty -> {BASE_STARS + 1.75}", () => starDifficultyBindable.Value?.Stars == BASE_STARS + 1.75);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestKeyEqualsWithDifferentModInstances()
|
||||||
|
{
|
||||||
|
var key1 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = 1234 }, new RulesetInfo { ID = 0 }, new Mod[] { new OsuModHardRock(), new OsuModHidden() });
|
||||||
|
var key2 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = 1234 }, new RulesetInfo { ID = 0 }, new Mod[] { new OsuModHardRock(), new OsuModHidden() });
|
||||||
|
|
||||||
|
Assert.That(key1, Is.EqualTo(key2));
|
||||||
|
Assert.That(key1.GetHashCode(), Is.EqualTo(key2.GetHashCode()));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestKeyEqualsWithDifferentModOrder()
|
||||||
|
{
|
||||||
|
var key1 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = 1234 }, new RulesetInfo { ID = 0 }, new Mod[] { new OsuModHardRock(), new OsuModHidden() });
|
||||||
|
var key2 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = 1234 }, new RulesetInfo { ID = 0 }, new Mod[] { new OsuModHidden(), new OsuModHardRock() });
|
||||||
|
|
||||||
|
Assert.That(key1, Is.EqualTo(key2));
|
||||||
|
Assert.That(key1.GetHashCode(), Is.EqualTo(key2.GetHashCode()));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestKeyDoesntEqualWithDifferentModSettings()
|
||||||
|
{
|
||||||
|
var key1 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = 1234 }, new RulesetInfo { ID = 0 }, new Mod[] { new OsuModDoubleTime { SpeedChange = { Value = 1.1 } } });
|
||||||
|
var key2 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = 1234 }, new RulesetInfo { ID = 0 }, new Mod[] { new OsuModDoubleTime { SpeedChange = { Value = 1.9 } } });
|
||||||
|
|
||||||
|
Assert.That(key1, Is.Not.EqualTo(key2));
|
||||||
|
Assert.That(key1.GetHashCode(), Is.Not.EqualTo(key2.GetHashCode()));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestKeyEqualWithMatchingModSettings()
|
||||||
|
{
|
||||||
|
var key1 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = 1234 }, new RulesetInfo { ID = 0 }, new Mod[] { new OsuModDoubleTime { SpeedChange = { Value = 1.25 } } });
|
||||||
|
var key2 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = 1234 }, new RulesetInfo { ID = 0 }, new Mod[] { new OsuModDoubleTime { SpeedChange = { Value = 1.25 } } });
|
||||||
|
|
||||||
|
Assert.That(key1, Is.EqualTo(key2));
|
||||||
|
Assert.That(key1.GetHashCode(), Is.EqualTo(key2.GetHashCode()));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestCase(1.3, DifficultyRating.Easy)]
|
||||||
|
[TestCase(1.993, DifficultyRating.Easy)]
|
||||||
|
[TestCase(1.998, DifficultyRating.Normal)]
|
||||||
|
[TestCase(2.4, DifficultyRating.Normal)]
|
||||||
|
[TestCase(2.693, DifficultyRating.Normal)]
|
||||||
|
[TestCase(2.698, DifficultyRating.Hard)]
|
||||||
|
[TestCase(3.5, DifficultyRating.Hard)]
|
||||||
|
[TestCase(3.993, DifficultyRating.Hard)]
|
||||||
|
[TestCase(3.997, DifficultyRating.Insane)]
|
||||||
|
[TestCase(5.0, DifficultyRating.Insane)]
|
||||||
|
[TestCase(5.292, DifficultyRating.Insane)]
|
||||||
|
[TestCase(5.297, DifficultyRating.Expert)]
|
||||||
|
[TestCase(6.2, DifficultyRating.Expert)]
|
||||||
|
[TestCase(6.493, DifficultyRating.Expert)]
|
||||||
|
[TestCase(6.498, DifficultyRating.ExpertPlus)]
|
||||||
|
[TestCase(8.3, DifficultyRating.ExpertPlus)]
|
||||||
|
public void TestDifficultyRatingMapping(double starRating, DifficultyRating expectedBracket)
|
||||||
|
{
|
||||||
|
var actualBracket = BeatmapDifficultyCache.GetDifficultyRating(starRating);
|
||||||
|
|
||||||
|
Assert.AreEqual(expectedBracket, actualBracket);
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TestBeatmapDifficultyCache : BeatmapDifficultyCache
|
||||||
|
{
|
||||||
|
protected override Task<StarDifficulty> ComputeValueAsync(DifficultyCacheLookup lookup, CancellationToken token = default)
|
||||||
|
{
|
||||||
|
var rateAdjust = lookup.OrderedMods.OfType<ModRateAdjust>().SingleOrDefault();
|
||||||
|
if (rateAdjust != null)
|
||||||
|
return Task.FromResult(new StarDifficulty(BASE_STARS + rateAdjust.SpeedChange.Value, 0));
|
||||||
|
|
||||||
|
return Task.FromResult(new StarDifficulty(BASE_STARS, 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -50,10 +50,10 @@ namespace osu.Game.Tests.Skins.IO
|
|||||||
var imported2 = await loadSkinIntoOsu(osu, new ZipArchiveReader(createOsk("test skin", "skinner"), "skin2.osk"));
|
var imported2 = await loadSkinIntoOsu(osu, new ZipArchiveReader(createOsk("test skin", "skinner"), "skin2.osk"));
|
||||||
|
|
||||||
Assert.That(imported2.ID, Is.Not.EqualTo(imported.ID));
|
Assert.That(imported2.ID, Is.Not.EqualTo(imported.ID));
|
||||||
Assert.That(osu.Dependencies.Get<SkinManager>().GetAllUserSkins().Count, Is.EqualTo(1));
|
Assert.That(osu.Dependencies.Get<SkinManager>().GetAllUserSkins(true).Count, Is.EqualTo(1));
|
||||||
|
|
||||||
// the first should be overwritten by the second import.
|
// the first should be overwritten by the second import.
|
||||||
Assert.That(osu.Dependencies.Get<SkinManager>().GetAllUserSkins().First().Files.First().FileInfoID, Is.EqualTo(imported2.Files.First().FileInfoID));
|
Assert.That(osu.Dependencies.Get<SkinManager>().GetAllUserSkins(true).First().Files.First().FileInfoID, Is.EqualTo(imported2.Files.First().FileInfoID));
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
@ -76,10 +76,10 @@ namespace osu.Game.Tests.Skins.IO
|
|||||||
var imported2 = await loadSkinIntoOsu(osu, new ZipArchiveReader(createOsk(string.Empty, string.Empty), "download.osk"));
|
var imported2 = await loadSkinIntoOsu(osu, new ZipArchiveReader(createOsk(string.Empty, string.Empty), "download.osk"));
|
||||||
|
|
||||||
Assert.That(imported2.ID, Is.Not.EqualTo(imported.ID));
|
Assert.That(imported2.ID, Is.Not.EqualTo(imported.ID));
|
||||||
Assert.That(osu.Dependencies.Get<SkinManager>().GetAllUserSkins().Count, Is.EqualTo(2));
|
Assert.That(osu.Dependencies.Get<SkinManager>().GetAllUserSkins(true).Count, Is.EqualTo(2));
|
||||||
|
|
||||||
Assert.That(osu.Dependencies.Get<SkinManager>().GetAllUserSkins().First().Files.First().FileInfoID, Is.EqualTo(imported.Files.First().FileInfoID));
|
Assert.That(osu.Dependencies.Get<SkinManager>().GetAllUserSkins(true).First().Files.First().FileInfoID, Is.EqualTo(imported.Files.First().FileInfoID));
|
||||||
Assert.That(osu.Dependencies.Get<SkinManager>().GetAllUserSkins().Last().Files.First().FileInfoID, Is.EqualTo(imported2.Files.First().FileInfoID));
|
Assert.That(osu.Dependencies.Get<SkinManager>().GetAllUserSkins(true).Last().Files.First().FileInfoID, Is.EqualTo(imported2.Files.First().FileInfoID));
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
@ -101,10 +101,10 @@ namespace osu.Game.Tests.Skins.IO
|
|||||||
var imported2 = await loadSkinIntoOsu(osu, new ZipArchiveReader(createOsk("test skin v2.1", "skinner"), "skin2.osk"));
|
var imported2 = await loadSkinIntoOsu(osu, new ZipArchiveReader(createOsk("test skin v2.1", "skinner"), "skin2.osk"));
|
||||||
|
|
||||||
Assert.That(imported2.ID, Is.Not.EqualTo(imported.ID));
|
Assert.That(imported2.ID, Is.Not.EqualTo(imported.ID));
|
||||||
Assert.That(osu.Dependencies.Get<SkinManager>().GetAllUserSkins().Count, Is.EqualTo(2));
|
Assert.That(osu.Dependencies.Get<SkinManager>().GetAllUserSkins(true).Count, Is.EqualTo(2));
|
||||||
|
|
||||||
Assert.That(osu.Dependencies.Get<SkinManager>().GetAllUserSkins().First().Files.First().FileInfoID, Is.EqualTo(imported.Files.First().FileInfoID));
|
Assert.That(osu.Dependencies.Get<SkinManager>().GetAllUserSkins(true).First().Files.First().FileInfoID, Is.EqualTo(imported.Files.First().FileInfoID));
|
||||||
Assert.That(osu.Dependencies.Get<SkinManager>().GetAllUserSkins().Last().Files.First().FileInfoID, Is.EqualTo(imported2.Files.First().FileInfoID));
|
Assert.That(osu.Dependencies.Get<SkinManager>().GetAllUserSkins(true).Last().Files.First().FileInfoID, Is.EqualTo(imported2.Files.First().FileInfoID));
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
@ -19,6 +19,8 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
{
|
{
|
||||||
public class TestSceneHUDOverlay : OsuManualInputManagerTestScene
|
public class TestSceneHUDOverlay : OsuManualInputManagerTestScene
|
||||||
{
|
{
|
||||||
|
private OsuConfigManager localConfig;
|
||||||
|
|
||||||
private HUDOverlay hudOverlay;
|
private HUDOverlay hudOverlay;
|
||||||
|
|
||||||
[Cached]
|
[Cached]
|
||||||
@ -31,8 +33,14 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
private Drawable hideTarget => hudOverlay.KeyCounter;
|
private Drawable hideTarget => hudOverlay.KeyCounter;
|
||||||
private FillFlowContainer<KeyCounter> keyCounterFlow => hudOverlay.KeyCounter.ChildrenOfType<FillFlowContainer<KeyCounter>>().First();
|
private FillFlowContainer<KeyCounter> keyCounterFlow => hudOverlay.KeyCounter.ChildrenOfType<FillFlowContainer<KeyCounter>>().First();
|
||||||
|
|
||||||
[Resolved]
|
[BackgroundDependencyLoader]
|
||||||
private OsuConfigManager config { get; set; }
|
private void load()
|
||||||
|
{
|
||||||
|
Dependencies.Cache(localConfig = new OsuConfigManager(LocalStorage));
|
||||||
|
}
|
||||||
|
|
||||||
|
[SetUp]
|
||||||
|
public void SetUp() => Schedule(() => localConfig.SetValue(OsuSetting.HUDVisibilityMode, HUDVisibilityMode.Always));
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestComboCounterIncrementing()
|
public void TestComboCounterIncrementing()
|
||||||
@ -85,11 +93,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
{
|
{
|
||||||
createNew();
|
createNew();
|
||||||
|
|
||||||
HUDVisibilityMode originalConfigValue = HUDVisibilityMode.HideDuringGameplay;
|
AddStep("set hud to never show", () => localConfig.SetValue(OsuSetting.HUDVisibilityMode, HUDVisibilityMode.Never));
|
||||||
|
|
||||||
AddStep("get original config value", () => originalConfigValue = config.Get<HUDVisibilityMode>(OsuSetting.HUDVisibilityMode));
|
|
||||||
|
|
||||||
AddStep("set hud to never show", () => config.SetValue(OsuSetting.HUDVisibilityMode, HUDVisibilityMode.Never));
|
|
||||||
|
|
||||||
AddUntilStep("wait for fade", () => !hideTarget.IsPresent);
|
AddUntilStep("wait for fade", () => !hideTarget.IsPresent);
|
||||||
|
|
||||||
@ -98,37 +102,28 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
|
|
||||||
AddStep("stop trigering", () => InputManager.ReleaseKey(Key.ControlLeft));
|
AddStep("stop trigering", () => InputManager.ReleaseKey(Key.ControlLeft));
|
||||||
AddUntilStep("wait for fade", () => !hideTarget.IsPresent);
|
AddUntilStep("wait for fade", () => !hideTarget.IsPresent);
|
||||||
|
|
||||||
AddStep("set original config value", () => config.SetValue(OsuSetting.HUDVisibilityMode, originalConfigValue));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestExternalHideDoesntAffectConfig()
|
public void TestExternalHideDoesntAffectConfig()
|
||||||
{
|
{
|
||||||
HUDVisibilityMode originalConfigValue = HUDVisibilityMode.HideDuringGameplay;
|
|
||||||
|
|
||||||
createNew();
|
createNew();
|
||||||
|
|
||||||
AddStep("get original config value", () => originalConfigValue = config.Get<HUDVisibilityMode>(OsuSetting.HUDVisibilityMode));
|
|
||||||
|
|
||||||
AddStep("set showhud false", () => hudOverlay.ShowHud.Value = false);
|
AddStep("set showhud false", () => hudOverlay.ShowHud.Value = false);
|
||||||
AddAssert("config unchanged", () => originalConfigValue == config.Get<HUDVisibilityMode>(OsuSetting.HUDVisibilityMode));
|
AddAssert("config unchanged", () => localConfig.GetBindable<HUDVisibilityMode>(OsuSetting.HUDVisibilityMode).IsDefault);
|
||||||
|
|
||||||
AddStep("set showhud true", () => hudOverlay.ShowHud.Value = true);
|
AddStep("set showhud true", () => hudOverlay.ShowHud.Value = true);
|
||||||
AddAssert("config unchanged", () => originalConfigValue == config.Get<HUDVisibilityMode>(OsuSetting.HUDVisibilityMode));
|
AddAssert("config unchanged", () => localConfig.GetBindable<HUDVisibilityMode>(OsuSetting.HUDVisibilityMode).IsDefault);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestChangeHUDVisibilityOnHiddenKeyCounter()
|
public void TestChangeHUDVisibilityOnHiddenKeyCounter()
|
||||||
{
|
{
|
||||||
bool keyCounterVisibleValue = false;
|
|
||||||
|
|
||||||
createNew();
|
createNew();
|
||||||
AddStep("save keycounter visible value", () => keyCounterVisibleValue = config.Get<bool>(OsuSetting.KeyOverlay));
|
|
||||||
|
|
||||||
AddStep("set keycounter visible false", () =>
|
AddStep("hide key overlay", () =>
|
||||||
{
|
{
|
||||||
config.SetValue(OsuSetting.KeyOverlay, false);
|
localConfig.SetValue(OsuSetting.KeyOverlay, false);
|
||||||
hudOverlay.KeyCounter.AlwaysVisible.Value = false;
|
hudOverlay.KeyCounter.AlwaysVisible.Value = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -139,24 +134,16 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
AddStep("set showhud true", () => hudOverlay.ShowHud.Value = true);
|
AddStep("set showhud true", () => hudOverlay.ShowHud.Value = true);
|
||||||
AddUntilStep("hidetarget is visible", () => hideTarget.IsPresent);
|
AddUntilStep("hidetarget is visible", () => hideTarget.IsPresent);
|
||||||
AddAssert("key counters still hidden", () => !keyCounterFlow.IsPresent);
|
AddAssert("key counters still hidden", () => !keyCounterFlow.IsPresent);
|
||||||
|
|
||||||
AddStep("return value", () => config.SetValue(OsuSetting.KeyOverlay, keyCounterVisibleValue));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestHiddenHUDDoesntBlockSkinnableComponentsLoad()
|
public void TestHiddenHUDDoesntBlockSkinnableComponentsLoad()
|
||||||
{
|
{
|
||||||
HUDVisibilityMode originalConfigValue = default;
|
AddStep("set hud to never show", () => localConfig.SetValue(OsuSetting.HUDVisibilityMode, HUDVisibilityMode.Never));
|
||||||
|
|
||||||
AddStep("get original config value", () => originalConfigValue = config.Get<HUDVisibilityMode>(OsuSetting.HUDVisibilityMode));
|
|
||||||
|
|
||||||
AddStep("set hud to never show", () => config.SetValue(OsuSetting.HUDVisibilityMode, HUDVisibilityMode.Never));
|
|
||||||
|
|
||||||
createNew();
|
createNew();
|
||||||
AddUntilStep("wait for hud load", () => hudOverlay.IsLoaded);
|
AddUntilStep("wait for hud load", () => hudOverlay.IsLoaded);
|
||||||
AddUntilStep("skinnable components loaded", () => hudOverlay.ChildrenOfType<SkinnableTargetContainer>().Single().ComponentsLoaded);
|
AddUntilStep("skinnable components loaded", () => hudOverlay.ChildrenOfType<SkinnableTargetContainer>().Single().ComponentsLoaded);
|
||||||
|
|
||||||
AddStep("set original config value", () => config.SetValue(OsuSetting.HUDVisibilityMode, originalConfigValue));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createNew(Action<HUDOverlay> action = null)
|
private void createNew(Action<HUDOverlay> action = null)
|
||||||
@ -175,5 +162,11 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
Child = hudOverlay;
|
Child = hudOverlay;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void Dispose(bool isDisposing)
|
||||||
|
{
|
||||||
|
localConfig?.Dispose();
|
||||||
|
base.Dispose(isDisposing);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,11 +10,11 @@ using osu.Framework.Graphics;
|
|||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Framework.Utils;
|
using osu.Framework.Utils;
|
||||||
using osu.Game.Graphics.UserInterface;
|
|
||||||
using osu.Game.Online.Rooms;
|
using osu.Game.Online.Rooms;
|
||||||
using osu.Game.Online.Rooms.RoomStatuses;
|
using osu.Game.Online.Rooms.RoomStatuses;
|
||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
using osu.Game.Rulesets.Osu;
|
using osu.Game.Rulesets.Osu;
|
||||||
|
using osu.Game.Screens.OnlinePlay.Lounge;
|
||||||
using osu.Game.Screens.OnlinePlay.Lounge.Components;
|
using osu.Game.Screens.OnlinePlay.Lounge.Components;
|
||||||
using osu.Game.Tests.Beatmaps;
|
using osu.Game.Tests.Beatmaps;
|
||||||
using osu.Game.Users;
|
using osu.Game.Users;
|
||||||
@ -108,12 +108,6 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
EndDate = { Value = DateTimeOffset.Now },
|
EndDate = { Value = DateTimeOffset.Now },
|
||||||
}),
|
}),
|
||||||
createDrawableRoom(new Room
|
createDrawableRoom(new Room
|
||||||
{
|
|
||||||
Name = { Value = "Room 4 (realtime)" },
|
|
||||||
Status = { Value = new RoomStatusOpen() },
|
|
||||||
Category = { Value = RoomCategory.Realtime },
|
|
||||||
}),
|
|
||||||
createDrawableRoom(new Room
|
|
||||||
{
|
{
|
||||||
Name = { Value = "Room 4 (spotlight)" },
|
Name = { Value = "Room 4 (spotlight)" },
|
||||||
Status = { Value = new RoomStatusOpen() },
|
Status = { Value = new RoomStatusOpen() },
|
||||||
@ -134,7 +128,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
{
|
{
|
||||||
Name = { Value = "Room with password" },
|
Name = { Value = "Room with password" },
|
||||||
Status = { Value = new RoomStatusOpen() },
|
Status = { Value = new RoomStatusOpen() },
|
||||||
Category = { Value = RoomCategory.Realtime },
|
Type = { Value = MatchType.HeadToHead },
|
||||||
}));
|
}));
|
||||||
|
|
||||||
AddAssert("password icon hidden", () => Precision.AlmostEquals(0, drawableRoom.ChildrenOfType<DrawableRoom.PasswordProtectedIcon>().Single().Alpha));
|
AddAssert("password icon hidden", () => Precision.AlmostEquals(0, drawableRoom.ChildrenOfType<DrawableRoom.PasswordProtectedIcon>().Single().Alpha));
|
||||||
@ -159,10 +153,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
var drawableRoom = new DrawableRoom(room) { MatchingFilter = true };
|
return new DrawableLoungeRoom(room) { MatchingFilter = true };
|
||||||
drawableRoom.Action = () => drawableRoom.State = drawableRoom.State == SelectionState.Selected ? SelectionState.NotSelected : SelectionState.Selected;
|
|
||||||
|
|
||||||
return drawableRoom;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ using osu.Framework.Testing;
|
|||||||
using osu.Game.Online.Rooms;
|
using osu.Game.Online.Rooms;
|
||||||
using osu.Game.Rulesets.Catch;
|
using osu.Game.Rulesets.Catch;
|
||||||
using osu.Game.Rulesets.Osu;
|
using osu.Game.Rulesets.Osu;
|
||||||
|
using osu.Game.Screens.OnlinePlay.Lounge;
|
||||||
using osu.Game.Screens.OnlinePlay.Lounge.Components;
|
using osu.Game.Screens.OnlinePlay.Lounge.Components;
|
||||||
using osu.Game.Tests.Visual.OnlinePlay;
|
using osu.Game.Tests.Visual.OnlinePlay;
|
||||||
using osuTK.Input;
|
using osuTK.Input;
|
||||||
@ -17,7 +18,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
{
|
{
|
||||||
public class TestSceneLoungeRoomsContainer : OnlinePlayTestScene
|
public class TestSceneLoungeRoomsContainer : OnlinePlayTestScene
|
||||||
{
|
{
|
||||||
protected new BasicTestRoomManager RoomManager => (BasicTestRoomManager)base.RoomManager;
|
protected new TestRequestHandlingRoomManager RoomManager => (TestRequestHandlingRoomManager)base.RoomManager;
|
||||||
|
|
||||||
private RoomsContainer container;
|
private RoomsContainer container;
|
||||||
|
|
||||||
@ -38,7 +39,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
AddStep("add rooms", () => RoomManager.AddRooms(3));
|
AddStep("add rooms", () => RoomManager.AddRooms(3));
|
||||||
|
|
||||||
AddAssert("has 3 rooms", () => container.Rooms.Count == 3);
|
AddAssert("has 3 rooms", () => container.Rooms.Count == 3);
|
||||||
AddStep("remove first room", () => RoomManager.Rooms.Remove(RoomManager.Rooms.FirstOrDefault()));
|
AddStep("remove first room", () => RoomManager.RemoveRoom(RoomManager.Rooms.FirstOrDefault()));
|
||||||
AddAssert("has 2 rooms", () => container.Rooms.Count == 2);
|
AddAssert("has 2 rooms", () => container.Rooms.Count == 2);
|
||||||
AddAssert("first room removed", () => container.Rooms.All(r => r.Room.RoomID.Value != 0));
|
AddAssert("first room removed", () => container.Rooms.All(r => r.Room.RoomID.Value != 0));
|
||||||
|
|
||||||
@ -150,6 +151,6 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
private bool checkRoomSelected(Room room) => SelectedRoom.Value == room;
|
private bool checkRoomSelected(Room room) => SelectedRoom.Value == room;
|
||||||
|
|
||||||
private Room getRoomInFlow(int index) =>
|
private Room getRoomInFlow(int index) =>
|
||||||
(container.ChildrenOfType<FillFlowContainer<DrawableRoom>>().First().FlowingChildren.ElementAt(index) as DrawableRoom)?.Room;
|
(container.ChildrenOfType<FillFlowContainer<DrawableLoungeRoom>>().First().FlowingChildren.ElementAt(index) as DrawableRoom)?.Room;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,55 +0,0 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
|
||||||
|
|
||||||
using NUnit.Framework;
|
|
||||||
using osu.Game.Beatmaps;
|
|
||||||
using osu.Game.Online.Rooms;
|
|
||||||
using osu.Game.Rulesets.Osu;
|
|
||||||
using osu.Game.Rulesets.Osu.Mods;
|
|
||||||
using osu.Game.Screens.OnlinePlay.Match.Components;
|
|
||||||
using osu.Game.Tests.Visual.OnlinePlay;
|
|
||||||
using osu.Game.Users;
|
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual.Multiplayer
|
|
||||||
{
|
|
||||||
public class TestSceneMatchHeader : OnlinePlayTestScene
|
|
||||||
{
|
|
||||||
[SetUp]
|
|
||||||
public new void Setup() => Schedule(() =>
|
|
||||||
{
|
|
||||||
SelectedRoom.Value = new Room
|
|
||||||
{
|
|
||||||
Name = { Value = "A very awesome room" },
|
|
||||||
Host = { Value = new User { Id = 2, Username = "peppy" } },
|
|
||||||
Playlist =
|
|
||||||
{
|
|
||||||
new PlaylistItem
|
|
||||||
{
|
|
||||||
Beatmap =
|
|
||||||
{
|
|
||||||
Value = new BeatmapInfo
|
|
||||||
{
|
|
||||||
Metadata = new BeatmapMetadata
|
|
||||||
{
|
|
||||||
Title = "Title",
|
|
||||||
Artist = "Artist",
|
|
||||||
AuthorString = "Author",
|
|
||||||
},
|
|
||||||
Version = "Version",
|
|
||||||
Ruleset = new OsuRuleset().RulesetInfo
|
|
||||||
}
|
|
||||||
},
|
|
||||||
RequiredMods =
|
|
||||||
{
|
|
||||||
new OsuModDoubleTime(),
|
|
||||||
new OsuModNoFail(),
|
|
||||||
new OsuModRelax(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Child = new Header();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
@ -236,8 +236,8 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
AddStep("select room", () => InputManager.Key(Key.Down));
|
AddStep("select room", () => InputManager.Key(Key.Down));
|
||||||
AddStep("join room", () => InputManager.Key(Key.Enter));
|
AddStep("join room", () => InputManager.Key(Key.Enter));
|
||||||
|
|
||||||
DrawableRoom.PasswordEntryPopover passwordEntryPopover = null;
|
DrawableLoungeRoom.PasswordEntryPopover passwordEntryPopover = null;
|
||||||
AddUntilStep("password prompt appeared", () => (passwordEntryPopover = InputManager.ChildrenOfType<DrawableRoom.PasswordEntryPopover>().FirstOrDefault()) != null);
|
AddUntilStep("password prompt appeared", () => (passwordEntryPopover = InputManager.ChildrenOfType<DrawableLoungeRoom.PasswordEntryPopover>().FirstOrDefault()) != null);
|
||||||
AddStep("enter password in text box", () => passwordEntryPopover.ChildrenOfType<TextBox>().First().Text = "password");
|
AddStep("enter password in text box", () => passwordEntryPopover.ChildrenOfType<TextBox>().First().Text = "password");
|
||||||
AddStep("press join room button", () => passwordEntryPopover.ChildrenOfType<OsuButton>().First().TriggerClick());
|
AddStep("press join room button", () => passwordEntryPopover.ChildrenOfType<OsuButton>().First().TriggerClick());
|
||||||
|
|
||||||
|
@ -9,7 +9,6 @@ using osu.Framework.Testing;
|
|||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
using osu.Game.Online.Rooms;
|
using osu.Game.Online.Rooms;
|
||||||
using osu.Game.Screens.OnlinePlay.Lounge;
|
using osu.Game.Screens.OnlinePlay.Lounge;
|
||||||
using osu.Game.Screens.OnlinePlay.Lounge.Components;
|
|
||||||
using osu.Game.Screens.OnlinePlay.Multiplayer;
|
using osu.Game.Screens.OnlinePlay.Multiplayer;
|
||||||
using osu.Game.Tests.Visual.OnlinePlay;
|
using osu.Game.Tests.Visual.OnlinePlay;
|
||||||
using osuTK.Input;
|
using osuTK.Input;
|
||||||
@ -18,7 +17,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
{
|
{
|
||||||
public class TestSceneMultiplayerLoungeSubScreen : OnlinePlayTestScene
|
public class TestSceneMultiplayerLoungeSubScreen : OnlinePlayTestScene
|
||||||
{
|
{
|
||||||
protected new BasicTestRoomManager RoomManager => (BasicTestRoomManager)base.RoomManager;
|
protected new TestRequestHandlingRoomManager RoomManager => (TestRequestHandlingRoomManager)base.RoomManager;
|
||||||
|
|
||||||
private LoungeSubScreen loungeScreen;
|
private LoungeSubScreen loungeScreen;
|
||||||
|
|
||||||
@ -59,20 +58,20 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
AddStep("select room", () => InputManager.Key(Key.Down));
|
AddStep("select room", () => InputManager.Key(Key.Down));
|
||||||
AddStep("attempt join room", () => InputManager.Key(Key.Enter));
|
AddStep("attempt join room", () => InputManager.Key(Key.Enter));
|
||||||
|
|
||||||
AddUntilStep("password prompt appeared", () => InputManager.ChildrenOfType<DrawableRoom.PasswordEntryPopover>().Any());
|
AddUntilStep("password prompt appeared", () => InputManager.ChildrenOfType<DrawableLoungeRoom.PasswordEntryPopover>().Any());
|
||||||
AddStep("exit screen", () => Stack.Exit());
|
AddStep("exit screen", () => Stack.Exit());
|
||||||
AddUntilStep("password prompt hidden", () => !InputManager.ChildrenOfType<DrawableRoom.PasswordEntryPopover>().Any());
|
AddUntilStep("password prompt hidden", () => !InputManager.ChildrenOfType<DrawableLoungeRoom.PasswordEntryPopover>().Any());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestJoinRoomWithPassword()
|
public void TestJoinRoomWithPassword()
|
||||||
{
|
{
|
||||||
DrawableRoom.PasswordEntryPopover passwordEntryPopover = null;
|
DrawableLoungeRoom.PasswordEntryPopover passwordEntryPopover = null;
|
||||||
|
|
||||||
AddStep("add room", () => RoomManager.AddRooms(1, withPassword: true));
|
AddStep("add room", () => RoomManager.AddRooms(1, withPassword: true));
|
||||||
AddStep("select room", () => InputManager.Key(Key.Down));
|
AddStep("select room", () => InputManager.Key(Key.Down));
|
||||||
AddStep("attempt join room", () => InputManager.Key(Key.Enter));
|
AddStep("attempt join room", () => InputManager.Key(Key.Enter));
|
||||||
AddUntilStep("password prompt appeared", () => (passwordEntryPopover = InputManager.ChildrenOfType<DrawableRoom.PasswordEntryPopover>().FirstOrDefault()) != null);
|
AddUntilStep("password prompt appeared", () => (passwordEntryPopover = InputManager.ChildrenOfType<DrawableLoungeRoom.PasswordEntryPopover>().FirstOrDefault()) != null);
|
||||||
AddStep("enter password in text box", () => passwordEntryPopover.ChildrenOfType<TextBox>().First().Text = "password");
|
AddStep("enter password in text box", () => passwordEntryPopover.ChildrenOfType<TextBox>().First().Text = "password");
|
||||||
AddStep("press join room button", () => passwordEntryPopover.ChildrenOfType<OsuButton>().First().TriggerClick());
|
AddStep("press join room button", () => passwordEntryPopover.ChildrenOfType<OsuButton>().First().TriggerClick());
|
||||||
|
|
||||||
@ -83,12 +82,12 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestJoinRoomWithPasswordViaKeyboardOnly()
|
public void TestJoinRoomWithPasswordViaKeyboardOnly()
|
||||||
{
|
{
|
||||||
DrawableRoom.PasswordEntryPopover passwordEntryPopover = null;
|
DrawableLoungeRoom.PasswordEntryPopover passwordEntryPopover = null;
|
||||||
|
|
||||||
AddStep("add room", () => RoomManager.AddRooms(1, withPassword: true));
|
AddStep("add room", () => RoomManager.AddRooms(1, withPassword: true));
|
||||||
AddStep("select room", () => InputManager.Key(Key.Down));
|
AddStep("select room", () => InputManager.Key(Key.Down));
|
||||||
AddStep("attempt join room", () => InputManager.Key(Key.Enter));
|
AddStep("attempt join room", () => InputManager.Key(Key.Enter));
|
||||||
AddUntilStep("password prompt appeared", () => (passwordEntryPopover = InputManager.ChildrenOfType<DrawableRoom.PasswordEntryPopover>().FirstOrDefault()) != null);
|
AddUntilStep("password prompt appeared", () => (passwordEntryPopover = InputManager.ChildrenOfType<DrawableLoungeRoom.PasswordEntryPopover>().FirstOrDefault()) != null);
|
||||||
AddStep("enter password in text box", () => passwordEntryPopover.ChildrenOfType<TextBox>().First().Text = "password");
|
AddStep("enter password in text box", () => passwordEntryPopover.ChildrenOfType<TextBox>().First().Text = "password");
|
||||||
AddStep("press enter", () => InputManager.Key(Key.Enter));
|
AddStep("press enter", () => InputManager.Key(Key.Enter));
|
||||||
|
|
||||||
|
@ -59,23 +59,6 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
AddUntilStep("wait for load", () => screen.IsCurrentScreen());
|
AddUntilStep("wait for load", () => screen.IsCurrentScreen());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void TestSettingValidity()
|
|
||||||
{
|
|
||||||
AddAssert("create button not enabled", () => !this.ChildrenOfType<MultiplayerMatchSettingsOverlay.CreateOrUpdateButton>().Single().Enabled.Value);
|
|
||||||
|
|
||||||
AddStep("set playlist", () =>
|
|
||||||
{
|
|
||||||
SelectedRoom.Value.Playlist.Add(new PlaylistItem
|
|
||||||
{
|
|
||||||
Beatmap = { Value = new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo },
|
|
||||||
Ruleset = { Value = new OsuRuleset().RulesetInfo },
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
AddAssert("create button enabled", () => this.ChildrenOfType<MultiplayerMatchSettingsOverlay.CreateOrUpdateButton>().Single().Enabled.Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestCreatedRoom()
|
public void TestCreatedRoom()
|
||||||
{
|
{
|
||||||
@ -97,6 +80,23 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
AddUntilStep("wait for join", () => Client.Room != null);
|
AddUntilStep("wait for join", () => Client.Room != null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestSettingValidity()
|
||||||
|
{
|
||||||
|
AddAssert("create button not enabled", () => !this.ChildrenOfType<MultiplayerMatchSettingsOverlay.CreateOrUpdateButton>().Single().Enabled.Value);
|
||||||
|
|
||||||
|
AddStep("set playlist", () =>
|
||||||
|
{
|
||||||
|
SelectedRoom.Value.Playlist.Add(new PlaylistItem
|
||||||
|
{
|
||||||
|
Beatmap = { Value = new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo },
|
||||||
|
Ruleset = { Value = new OsuRuleset().RulesetInfo },
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
AddAssert("create button enabled", () => this.ChildrenOfType<MultiplayerMatchSettingsOverlay.CreateOrUpdateButton>().Single().Enabled.Value);
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestStartMatchWhileSpectating()
|
public void TestStartMatchWhileSpectating()
|
||||||
{
|
{
|
||||||
|
@ -16,7 +16,7 @@ namespace osu.Game.Tests.Visual.Playlists
|
|||||||
{
|
{
|
||||||
public class TestScenePlaylistsLoungeSubScreen : OnlinePlayTestScene
|
public class TestScenePlaylistsLoungeSubScreen : OnlinePlayTestScene
|
||||||
{
|
{
|
||||||
protected new BasicTestRoomManager RoomManager => (BasicTestRoomManager)base.RoomManager;
|
protected new TestRequestHandlingRoomManager RoomManager => (TestRequestHandlingRoomManager)base.RoomManager;
|
||||||
|
|
||||||
private LoungeSubScreen loungeScreen;
|
private LoungeSubScreen loungeScreen;
|
||||||
|
|
||||||
@ -37,6 +37,7 @@ namespace osu.Game.Tests.Visual.Playlists
|
|||||||
AddStep("reset mouse", () => InputManager.ReleaseButton(MouseButton.Left));
|
AddStep("reset mouse", () => InputManager.ReleaseButton(MouseButton.Left));
|
||||||
|
|
||||||
AddStep("add rooms", () => RoomManager.AddRooms(30));
|
AddStep("add rooms", () => RoomManager.AddRooms(30));
|
||||||
|
AddUntilStep("wait for rooms", () => roomsContainer.Rooms.Count == 30);
|
||||||
|
|
||||||
AddUntilStep("first room is not masked", () => checkRoomVisible(roomsContainer.Rooms[0]));
|
AddUntilStep("first room is not masked", () => checkRoomVisible(roomsContainer.Rooms[0]));
|
||||||
|
|
||||||
@ -53,6 +54,7 @@ namespace osu.Game.Tests.Visual.Playlists
|
|||||||
public void TestScrollSelectedIntoView()
|
public void TestScrollSelectedIntoView()
|
||||||
{
|
{
|
||||||
AddStep("add rooms", () => RoomManager.AddRooms(30));
|
AddStep("add rooms", () => RoomManager.AddRooms(30));
|
||||||
|
AddUntilStep("wait for rooms", () => roomsContainer.Rooms.Count == 30);
|
||||||
|
|
||||||
AddUntilStep("first room is not masked", () => checkRoomVisible(roomsContainer.Rooms[0]));
|
AddUntilStep("first room is not masked", () => checkRoomVisible(roomsContainer.Rooms[0]));
|
||||||
|
|
||||||
|
@ -110,7 +110,7 @@ namespace osu.Game.Tests.Visual.Playlists
|
|||||||
AddUntilStep("error not displayed", () => !settings.ErrorText.IsPresent);
|
AddUntilStep("error not displayed", () => !settings.ErrorText.IsPresent);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TestRoomSettings : PlaylistsMatchSettingsOverlay
|
private class TestRoomSettings : PlaylistsRoomSettingsOverlay
|
||||||
{
|
{
|
||||||
public TriangleButton ApplyButton => ((MatchSettings)Settings).ApplyButton;
|
public TriangleButton ApplyButton => ((MatchSettings)Settings).ApplyButton;
|
||||||
|
|
||||||
|
@ -11,7 +11,6 @@ using osu.Framework.Platform;
|
|||||||
using osu.Framework.Screens;
|
using osu.Framework.Screens;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Online.API;
|
|
||||||
using osu.Game.Online.Rooms;
|
using osu.Game.Online.Rooms;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Rulesets.Osu;
|
using osu.Game.Rulesets.Osu;
|
||||||
@ -19,7 +18,6 @@ using osu.Game.Screens.OnlinePlay.Playlists;
|
|||||||
using osu.Game.Screens.Play;
|
using osu.Game.Screens.Play;
|
||||||
using osu.Game.Tests.Beatmaps;
|
using osu.Game.Tests.Beatmaps;
|
||||||
using osu.Game.Tests.Visual.OnlinePlay;
|
using osu.Game.Tests.Visual.OnlinePlay;
|
||||||
using osu.Game.Users;
|
|
||||||
using osuTK.Input;
|
using osuTK.Input;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual.Playlists
|
namespace osu.Game.Tests.Visual.Playlists
|
||||||
@ -36,18 +34,6 @@ namespace osu.Game.Tests.Visual.Playlists
|
|||||||
{
|
{
|
||||||
Dependencies.Cache(rulesets = new RulesetStore(ContextFactory));
|
Dependencies.Cache(rulesets = new RulesetStore(ContextFactory));
|
||||||
Dependencies.Cache(manager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, Resources, host, Beatmap.Default));
|
Dependencies.Cache(manager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, Resources, host, Beatmap.Default));
|
||||||
|
|
||||||
((DummyAPIAccess)API).HandleRequest = req =>
|
|
||||||
{
|
|
||||||
switch (req)
|
|
||||||
{
|
|
||||||
case CreateRoomScoreRequest createRoomScoreRequest:
|
|
||||||
createRoomScoreRequest.TriggerSuccess(new APIScoreToken { ID = 1 });
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[SetUpSteps]
|
[SetUpSteps]
|
||||||
@ -66,7 +52,7 @@ namespace osu.Game.Tests.Visual.Playlists
|
|||||||
{
|
{
|
||||||
SelectedRoom.Value.RoomID.Value = 1;
|
SelectedRoom.Value.RoomID.Value = 1;
|
||||||
SelectedRoom.Value.Name.Value = "my awesome room";
|
SelectedRoom.Value.Name.Value = "my awesome room";
|
||||||
SelectedRoom.Value.Host.Value = new User { Id = 2, Username = "peppy" };
|
SelectedRoom.Value.Host.Value = API.LocalUser.Value;
|
||||||
SelectedRoom.Value.RecentParticipants.Add(SelectedRoom.Value.Host.Value);
|
SelectedRoom.Value.RecentParticipants.Add(SelectedRoom.Value.Host.Value);
|
||||||
SelectedRoom.Value.EndDate.Value = DateTimeOffset.Now.AddMinutes(5);
|
SelectedRoom.Value.EndDate.Value = DateTimeOffset.Now.AddMinutes(5);
|
||||||
SelectedRoom.Value.Playlist.Add(new PlaylistItem
|
SelectedRoom.Value.Playlist.Add(new PlaylistItem
|
||||||
@ -86,7 +72,7 @@ namespace osu.Game.Tests.Visual.Playlists
|
|||||||
AddStep("set room properties", () =>
|
AddStep("set room properties", () =>
|
||||||
{
|
{
|
||||||
SelectedRoom.Value.Name.Value = "my awesome room";
|
SelectedRoom.Value.Name.Value = "my awesome room";
|
||||||
SelectedRoom.Value.Host.Value = new User { Id = 2, Username = "peppy" };
|
SelectedRoom.Value.Host.Value = API.LocalUser.Value;
|
||||||
SelectedRoom.Value.Playlist.Add(new PlaylistItem
|
SelectedRoom.Value.Playlist.Add(new PlaylistItem
|
||||||
{
|
{
|
||||||
Beatmap = { Value = new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo },
|
Beatmap = { Value = new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo },
|
||||||
@ -96,7 +82,7 @@ namespace osu.Game.Tests.Visual.Playlists
|
|||||||
|
|
||||||
AddStep("move mouse to create button", () =>
|
AddStep("move mouse to create button", () =>
|
||||||
{
|
{
|
||||||
InputManager.MoveMouseTo(this.ChildrenOfType<PlaylistsMatchSettingsOverlay.CreateRoomButton>().Single());
|
InputManager.MoveMouseTo(this.ChildrenOfType<PlaylistsRoomSettingsOverlay.CreateRoomButton>().Single());
|
||||||
});
|
});
|
||||||
|
|
||||||
AddStep("click", () => InputManager.Click(MouseButton.Left));
|
AddStep("click", () => InputManager.Click(MouseButton.Left));
|
||||||
@ -137,7 +123,7 @@ namespace osu.Game.Tests.Visual.Playlists
|
|||||||
AddStep("load room", () =>
|
AddStep("load room", () =>
|
||||||
{
|
{
|
||||||
SelectedRoom.Value.Name.Value = "my awesome room";
|
SelectedRoom.Value.Name.Value = "my awesome room";
|
||||||
SelectedRoom.Value.Host.Value = new User { Id = 2, Username = "peppy" };
|
SelectedRoom.Value.Host.Value = API.LocalUser.Value;
|
||||||
SelectedRoom.Value.Playlist.Add(new PlaylistItem
|
SelectedRoom.Value.Playlist.Add(new PlaylistItem
|
||||||
{
|
{
|
||||||
Beatmap = { Value = importedSet.Beatmaps[0] },
|
Beatmap = { Value = importedSet.Beatmaps[0] },
|
||||||
@ -147,7 +133,7 @@ namespace osu.Game.Tests.Visual.Playlists
|
|||||||
|
|
||||||
AddStep("create room", () =>
|
AddStep("create room", () =>
|
||||||
{
|
{
|
||||||
InputManager.MoveMouseTo(match.ChildrenOfType<PlaylistsMatchSettingsOverlay.CreateRoomButton>().Single());
|
InputManager.MoveMouseTo(match.ChildrenOfType<PlaylistsRoomSettingsOverlay.CreateRoomButton>().Single());
|
||||||
InputManager.Click(MouseButton.Left);
|
InputManager.Click(MouseButton.Left);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,65 +0,0 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
|
||||||
|
|
||||||
using System.Linq;
|
|
||||||
using NUnit.Framework;
|
|
||||||
using osu.Framework.Graphics;
|
|
||||||
using osu.Framework.Graphics.Containers;
|
|
||||||
using osu.Framework.Utils;
|
|
||||||
using osu.Game.Beatmaps;
|
|
||||||
using osu.Game.Screens.Ranking.Expanded;
|
|
||||||
using osuTK;
|
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual.Ranking
|
|
||||||
{
|
|
||||||
public class TestSceneStarRatingDisplay : OsuTestScene
|
|
||||||
{
|
|
||||||
[Test]
|
|
||||||
public void TestDisplay()
|
|
||||||
{
|
|
||||||
AddStep("load displays", () => Child = new FillFlowContainer
|
|
||||||
{
|
|
||||||
Anchor = Anchor.Centre,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
ChildrenEnumerable = new[]
|
|
||||||
{
|
|
||||||
1.23,
|
|
||||||
2.34,
|
|
||||||
3.45,
|
|
||||||
4.56,
|
|
||||||
5.67,
|
|
||||||
6.78,
|
|
||||||
10.11,
|
|
||||||
}.Select(starRating => new StarRatingDisplay(new StarDifficulty(starRating, 0))
|
|
||||||
{
|
|
||||||
Anchor = Anchor.Centre,
|
|
||||||
Origin = Anchor.Centre
|
|
||||||
})
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void TestChangingStarRatingDisplay()
|
|
||||||
{
|
|
||||||
StarRatingDisplay starRating = null;
|
|
||||||
|
|
||||||
AddStep("load display", () => Child = starRating = new StarRatingDisplay(new StarDifficulty(5.55, 1))
|
|
||||||
{
|
|
||||||
Anchor = Anchor.Centre,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
Scale = new Vector2(3f),
|
|
||||||
});
|
|
||||||
|
|
||||||
AddRepeatStep("set random value", () =>
|
|
||||||
{
|
|
||||||
starRating.Current.Value = new StarDifficulty(RNG.NextDouble(0.0, 11.0), 1);
|
|
||||||
}, 10);
|
|
||||||
|
|
||||||
AddSliderStep("set exact stars", 0.0, 11.0, 5.55, d =>
|
|
||||||
{
|
|
||||||
if (starRating != null)
|
|
||||||
starRating.Current.Value = new StarDifficulty(d, 1);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -32,6 +32,7 @@ namespace osu.Game.Tests.Visual.Settings
|
|||||||
[SetUpSteps]
|
[SetUpSteps]
|
||||||
public void SetUpSteps()
|
public void SetUpSteps()
|
||||||
{
|
{
|
||||||
|
AddUntilStep("wait for load", () => panel.ChildrenOfType<GlobalKeyBindingsSection>().Any());
|
||||||
AddStep("Scroll to top", () => panel.ChildrenOfType<SettingsPanel.SettingsSectionsContainer>().First().ScrollToTop());
|
AddStep("Scroll to top", () => panel.ChildrenOfType<SettingsPanel.SettingsSectionsContainer>().First().ScrollToTop());
|
||||||
AddWaitStep("wait for scroll", 5);
|
AddWaitStep("wait for scroll", 5);
|
||||||
}
|
}
|
||||||
|
@ -76,5 +76,23 @@ namespace osu.Game.Tests.Visual.Settings
|
|||||||
AddStep("restore default", () => sliderBar.Current.SetDefault());
|
AddStep("restore default", () => sliderBar.Current.SetDefault());
|
||||||
AddUntilStep("restore button hidden", () => restoreDefaultValueButton.Alpha == 0);
|
AddUntilStep("restore button hidden", () => restoreDefaultValueButton.Alpha == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestWarningTextVisibility()
|
||||||
|
{
|
||||||
|
SettingsNumberBox numberBox = null;
|
||||||
|
|
||||||
|
AddStep("create settings item", () => Child = numberBox = new SettingsNumberBox());
|
||||||
|
AddAssert("warning text not created", () => !numberBox.ChildrenOfType<SettingsNoticeText>().Any());
|
||||||
|
|
||||||
|
AddStep("set warning text", () => numberBox.WarningText = "this is a warning!");
|
||||||
|
AddAssert("warning text created", () => numberBox.ChildrenOfType<SettingsNoticeText>().Single().Alpha == 1);
|
||||||
|
|
||||||
|
AddStep("unset warning text", () => numberBox.WarningText = default);
|
||||||
|
AddAssert("warning text hidden", () => numberBox.ChildrenOfType<SettingsNoticeText>().Single().Alpha == 0);
|
||||||
|
|
||||||
|
AddStep("set warning text again", () => numberBox.WarningText = "another warning!");
|
||||||
|
AddAssert("warning text shown again", () => numberBox.ChildrenOfType<SettingsNoticeText>().Single().Alpha == 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual.Settings
|
namespace osu.Game.Tests.Visual.Settings
|
||||||
@ -11,27 +12,39 @@ namespace osu.Game.Tests.Visual.Settings
|
|||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class TestSceneSettingsPanel : OsuTestScene
|
public class TestSceneSettingsPanel : OsuTestScene
|
||||||
{
|
{
|
||||||
private readonly SettingsPanel settings;
|
private SettingsPanel settings;
|
||||||
private readonly DialogOverlay dialogOverlay;
|
private DialogOverlay dialogOverlay;
|
||||||
|
|
||||||
public TestSceneSettingsPanel()
|
[SetUpSteps]
|
||||||
|
public void SetUpSteps()
|
||||||
{
|
{
|
||||||
settings = new SettingsOverlay
|
AddStep("create settings", () =>
|
||||||
|
{
|
||||||
|
settings?.Expire();
|
||||||
|
|
||||||
|
Add(settings = new SettingsOverlay
|
||||||
{
|
{
|
||||||
State = { Value = Visibility.Visible }
|
State = { Value = Visibility.Visible }
|
||||||
};
|
|
||||||
Add(dialogOverlay = new DialogOverlay
|
|
||||||
{
|
|
||||||
Depth = -1
|
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ToggleVisibility()
|
||||||
|
{
|
||||||
|
AddWaitStep("wait some", 5);
|
||||||
|
AddToggleStep("toggle editor visibility", visible => settings.ToggleVisibility());
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
{
|
{
|
||||||
Dependencies.Cache(dialogOverlay);
|
Add(dialogOverlay = new DialogOverlay
|
||||||
|
{
|
||||||
|
Depth = -1
|
||||||
|
});
|
||||||
|
|
||||||
Add(settings);
|
Dependencies.Cache(dialogOverlay);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ using NUnit.Framework;
|
|||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.UserInterface;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
@ -65,6 +66,12 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
|
|
||||||
AddStep("show", () => { infoWedge.Show(); });
|
AddStep("show", () => { infoWedge.Show(); });
|
||||||
|
|
||||||
|
AddSliderStep("change star difficulty", 0, 11.9, 5.55, v =>
|
||||||
|
{
|
||||||
|
foreach (var hasCurrentValue in infoWedge.Info.ChildrenOfType<IHasCurrentValue<StarDifficulty>>())
|
||||||
|
hasCurrentValue.Current.Value = new StarDifficulty(v, 0);
|
||||||
|
});
|
||||||
|
|
||||||
foreach (var rulesetInfo in rulesets.AvailableRulesets)
|
foreach (var rulesetInfo in rulesets.AvailableRulesets)
|
||||||
{
|
{
|
||||||
var instance = rulesetInfo.CreateInstance();
|
var instance = rulesetInfo.CreateInstance();
|
||||||
|
@ -0,0 +1,71 @@
|
|||||||
|
// 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.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Utils;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Beatmaps.Drawables;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.Visual.UserInterface
|
||||||
|
{
|
||||||
|
public class TestSceneStarRatingDisplay : OsuTestScene
|
||||||
|
{
|
||||||
|
[TestCase(StarRatingDisplaySize.Regular)]
|
||||||
|
[TestCase(StarRatingDisplaySize.Small)]
|
||||||
|
public void TestDisplay(StarRatingDisplaySize size)
|
||||||
|
{
|
||||||
|
AddStep("load displays", () =>
|
||||||
|
{
|
||||||
|
Child = new FillFlowContainer
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
Spacing = new Vector2(2f),
|
||||||
|
Direction = FillDirection.Horizontal,
|
||||||
|
ChildrenEnumerable = Enumerable.Range(0, 15).Select(i => new FillFlowContainer
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
Spacing = new Vector2(2f),
|
||||||
|
Direction = FillDirection.Vertical,
|
||||||
|
ChildrenEnumerable = Enumerable.Range(0, 10).Select(j => new StarRatingDisplay(new StarDifficulty(i * (i >= 11 ? 25f : 1f) + j * 0.1f, 0), size)
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestSpectrum()
|
||||||
|
{
|
||||||
|
StarRatingDisplay starRating = null;
|
||||||
|
|
||||||
|
AddStep("load display", () => Child = starRating = new StarRatingDisplay(new StarDifficulty(5.55, 1), animated: true)
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
Scale = new Vector2(3f),
|
||||||
|
});
|
||||||
|
|
||||||
|
AddRepeatStep("set random value", () =>
|
||||||
|
{
|
||||||
|
starRating.Current.Value = new StarDifficulty(RNG.NextDouble(0.0, 11.0), 1);
|
||||||
|
}, 10);
|
||||||
|
|
||||||
|
AddSliderStep("set exact stars", 0.0, 11.0, 5.55, d =>
|
||||||
|
{
|
||||||
|
if (starRating != null)
|
||||||
|
starRating.Current.Value = new StarDifficulty(d, 1);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -14,6 +14,7 @@ using osu.Framework.Lists;
|
|||||||
using osu.Framework.Logging;
|
using osu.Framework.Logging;
|
||||||
using osu.Framework.Threading;
|
using osu.Framework.Threading;
|
||||||
using osu.Framework.Utils;
|
using osu.Framework.Utils;
|
||||||
|
using osu.Game.Configuration;
|
||||||
using osu.Game.Database;
|
using osu.Game.Database;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
@ -56,12 +57,28 @@ namespace osu.Game.Beatmaps
|
|||||||
[Resolved]
|
[Resolved]
|
||||||
private Bindable<IReadOnlyList<Mod>> currentMods { get; set; }
|
private Bindable<IReadOnlyList<Mod>> currentMods { get; set; }
|
||||||
|
|
||||||
|
private ModSettingChangeTracker modSettingChangeTracker;
|
||||||
|
private ScheduledDelegate debouncedModSettingsChange;
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
|
|
||||||
currentRuleset.BindValueChanged(_ => updateTrackedBindables());
|
currentRuleset.BindValueChanged(_ => updateTrackedBindables());
|
||||||
currentMods.BindValueChanged(_ => updateTrackedBindables(), true);
|
|
||||||
|
currentMods.BindValueChanged(mods =>
|
||||||
|
{
|
||||||
|
modSettingChangeTracker?.Dispose();
|
||||||
|
|
||||||
|
updateTrackedBindables();
|
||||||
|
|
||||||
|
modSettingChangeTracker = new ModSettingChangeTracker(mods.NewValue);
|
||||||
|
modSettingChangeTracker.SettingChanged += _ =>
|
||||||
|
{
|
||||||
|
debouncedModSettingsChange?.Cancel();
|
||||||
|
debouncedModSettingsChange = Scheduler.AddDelayed(updateTrackedBindables, 100);
|
||||||
|
};
|
||||||
|
}, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -84,7 +101,7 @@ namespace osu.Game.Beatmaps
|
|||||||
/// Retrieves a bindable containing the star difficulty of a <see cref="BeatmapInfo"/> with a given <see cref="RulesetInfo"/> and <see cref="Mod"/> combination.
|
/// Retrieves a bindable containing the star difficulty of a <see cref="BeatmapInfo"/> with a given <see cref="RulesetInfo"/> and <see cref="Mod"/> combination.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// The bindable will not update to follow the currently-selected ruleset and mods.
|
/// The bindable will not update to follow the currently-selected ruleset and mods or its settings.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
/// <param name="beatmapInfo">The <see cref="BeatmapInfo"/> to get the difficulty of.</param>
|
/// <param name="beatmapInfo">The <see cref="BeatmapInfo"/> to get the difficulty of.</param>
|
||||||
/// <param name="rulesetInfo">The <see cref="RulesetInfo"/> to get the difficulty with. If <c>null</c>, the <paramref name="beatmapInfo"/>'s ruleset is used.</param>
|
/// <param name="rulesetInfo">The <see cref="RulesetInfo"/> to get the difficulty with. If <c>null</c>, the <paramref name="beatmapInfo"/>'s ruleset is used.</param>
|
||||||
@ -275,6 +292,8 @@ namespace osu.Game.Beatmaps
|
|||||||
{
|
{
|
||||||
base.Dispose(isDisposing);
|
base.Dispose(isDisposing);
|
||||||
|
|
||||||
|
modSettingChangeTracker?.Dispose();
|
||||||
|
|
||||||
cancelTrackedBindableUpdate();
|
cancelTrackedBindableUpdate();
|
||||||
updateScheduler?.Dispose();
|
updateScheduler?.Dispose();
|
||||||
}
|
}
|
||||||
@ -297,7 +316,7 @@ namespace osu.Game.Beatmaps
|
|||||||
public bool Equals(DifficultyCacheLookup other)
|
public bool Equals(DifficultyCacheLookup other)
|
||||||
=> Beatmap.ID == other.Beatmap.ID
|
=> Beatmap.ID == other.Beatmap.ID
|
||||||
&& Ruleset.ID == other.Ruleset.ID
|
&& Ruleset.ID == other.Ruleset.ID
|
||||||
&& OrderedMods.Select(m => m.Acronym).SequenceEqual(other.OrderedMods.Select(m => m.Acronym));
|
&& OrderedMods.SequenceEqual(other.OrderedMods);
|
||||||
|
|
||||||
public override int GetHashCode()
|
public override int GetHashCode()
|
||||||
{
|
{
|
||||||
@ -307,7 +326,7 @@ namespace osu.Game.Beatmaps
|
|||||||
hashCode.Add(Ruleset.ID);
|
hashCode.Add(Ruleset.ID);
|
||||||
|
|
||||||
foreach (var mod in OrderedMods)
|
foreach (var mod in OrderedMods)
|
||||||
hashCode.Add(mod.Acronym);
|
hashCode.Add(mod);
|
||||||
|
|
||||||
return hashCode.ToHashCode();
|
return hashCode.ToHashCode();
|
||||||
}
|
}
|
||||||
|
168
osu.Game/Beatmaps/Drawables/StarRatingDisplay.cs
Normal file
168
osu.Game/Beatmaps/Drawables/StarRatingDisplay.cs
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
// 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.Bindables;
|
||||||
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Framework.Graphics.UserInterface;
|
||||||
|
using osu.Framework.Localisation;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
using osu.Game.Graphics.Sprites;
|
||||||
|
using osu.Game.Overlays;
|
||||||
|
using osuTK;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
|
||||||
|
namespace osu.Game.Beatmaps.Drawables
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A pill that displays the star rating of a beatmap.
|
||||||
|
/// </summary>
|
||||||
|
public class StarRatingDisplay : CompositeDrawable, IHasCurrentValue<StarDifficulty>
|
||||||
|
{
|
||||||
|
private readonly bool animated;
|
||||||
|
private readonly Box background;
|
||||||
|
private readonly SpriteIcon starIcon;
|
||||||
|
private readonly OsuSpriteText starsText;
|
||||||
|
|
||||||
|
private readonly BindableWithCurrent<StarDifficulty> current = new BindableWithCurrent<StarDifficulty>();
|
||||||
|
|
||||||
|
public Bindable<StarDifficulty> Current
|
||||||
|
{
|
||||||
|
get => current.Current;
|
||||||
|
set => current.Current = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly Bindable<double> displayedStars = new BindableDouble();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The currently displayed stars of this display wrapped in a bindable.
|
||||||
|
/// This bindable gets transformed on change rather than instantaneous, if animation is enabled.
|
||||||
|
/// </summary>
|
||||||
|
public IBindable<double> DisplayedStars => displayedStars;
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private OsuColour colours { get; set; }
|
||||||
|
|
||||||
|
[Resolved(canBeNull: true)]
|
||||||
|
private OverlayColourProvider colourProvider { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new <see cref="StarRatingDisplay"/> using an already computed <see cref="StarDifficulty"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="starDifficulty">The already computed <see cref="StarDifficulty"/> to display.</param>
|
||||||
|
/// <param name="size">The size of the star rating display.</param>
|
||||||
|
/// <param name="animated">Whether the star rating display will perform transforms on change rather than updating instantaneously.</param>
|
||||||
|
public StarRatingDisplay(StarDifficulty starDifficulty, StarRatingDisplaySize size = StarRatingDisplaySize.Regular, bool animated = false)
|
||||||
|
{
|
||||||
|
this.animated = animated;
|
||||||
|
|
||||||
|
Current.Value = starDifficulty;
|
||||||
|
|
||||||
|
AutoSizeAxes = Axes.Both;
|
||||||
|
|
||||||
|
MarginPadding margin = default;
|
||||||
|
|
||||||
|
switch (size)
|
||||||
|
{
|
||||||
|
case StarRatingDisplaySize.Small:
|
||||||
|
margin = new MarginPadding { Horizontal = 7f };
|
||||||
|
break;
|
||||||
|
|
||||||
|
case StarRatingDisplaySize.Range:
|
||||||
|
margin = new MarginPadding { Horizontal = 8f };
|
||||||
|
break;
|
||||||
|
|
||||||
|
case StarRatingDisplaySize.Regular:
|
||||||
|
margin = new MarginPadding { Horizontal = 8f, Vertical = 2f };
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
InternalChild = new CircularContainer
|
||||||
|
{
|
||||||
|
Masking = true,
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
background = new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
},
|
||||||
|
new GridContainer
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
Margin = margin,
|
||||||
|
ColumnDimensions = new[]
|
||||||
|
{
|
||||||
|
new Dimension(GridSizeMode.AutoSize),
|
||||||
|
new Dimension(GridSizeMode.Absolute, 3f),
|
||||||
|
new Dimension(GridSizeMode.AutoSize, minSize: 25f),
|
||||||
|
},
|
||||||
|
RowDimensions = new[] { new Dimension(GridSizeMode.AutoSize) },
|
||||||
|
Content = new[]
|
||||||
|
{
|
||||||
|
new[]
|
||||||
|
{
|
||||||
|
starIcon = new SpriteIcon
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
Icon = FontAwesome.Solid.Star,
|
||||||
|
Size = new Vector2(8f),
|
||||||
|
},
|
||||||
|
Empty(),
|
||||||
|
starsText = new OsuSpriteText
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
Margin = new MarginPadding { Bottom = 1.5f },
|
||||||
|
// todo: this should be size: 12f, but to match up with the design, it needs to be 14.4f
|
||||||
|
// see https://github.com/ppy/osu-framework/issues/3271.
|
||||||
|
Font = OsuFont.Torus.With(size: 14.4f, weight: FontWeight.Bold),
|
||||||
|
Shadow = false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
|
Current.BindValueChanged(c =>
|
||||||
|
{
|
||||||
|
if (animated)
|
||||||
|
this.TransformBindableTo(displayedStars, c.NewValue.Stars, 750, Easing.OutQuint);
|
||||||
|
else
|
||||||
|
displayedStars.Value = c.NewValue.Stars;
|
||||||
|
});
|
||||||
|
|
||||||
|
displayedStars.Value = Current.Value.Stars;
|
||||||
|
|
||||||
|
displayedStars.BindValueChanged(s =>
|
||||||
|
{
|
||||||
|
starsText.Text = s.NewValue.ToLocalisableString("0.00");
|
||||||
|
|
||||||
|
background.Colour = colours.ForStarDifficulty(s.NewValue);
|
||||||
|
|
||||||
|
starIcon.Colour = s.NewValue >= 6.5 ? colours.Orange1 : colourProvider?.Background5 ?? Color4Extensions.FromHex("303d47");
|
||||||
|
starsText.Colour = s.NewValue >= 6.5 ? colours.Orange1 : colourProvider?.Background5 ?? Color4.Black.Opacity(0.75f);
|
||||||
|
}, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum StarRatingDisplaySize
|
||||||
|
{
|
||||||
|
Small,
|
||||||
|
Range,
|
||||||
|
Regular,
|
||||||
|
}
|
||||||
|
}
|
@ -36,6 +36,11 @@ namespace osu.Game.Database
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public IQueryable<T> ConsumableItems => AddIncludesForConsumption(ContextFactory.Get().Set<T>());
|
public IQueryable<T> ConsumableItems => AddIncludesForConsumption(ContextFactory.Get().Set<T>());
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Access barebones items with no includes.
|
||||||
|
/// </summary>
|
||||||
|
public IQueryable<T> Items => ContextFactory.Get().Set<T>();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Add a <typeparamref name="T"/> to the database.
|
/// Add a <typeparamref name="T"/> to the database.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -22,7 +22,10 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
|
|
||||||
public void TakeFocus()
|
public void TakeFocus()
|
||||||
{
|
{
|
||||||
if (allowImmediateFocus) GetContainingInputManager().ChangeFocus(this);
|
if (!allowImmediateFocus)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Scheduler.Add(() => GetContainingInputManager().ChangeFocus(this), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public new void KillFocus() => base.KillFocus();
|
public new void KillFocus() => base.KillFocus();
|
||||||
|
@ -6,6 +6,7 @@ using osuTK;
|
|||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Effects;
|
using osu.Framework.Graphics.Effects;
|
||||||
@ -57,18 +58,13 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
|
|
||||||
EdgeEffect = new EdgeEffectParameters
|
EdgeEffect = new EdgeEffectParameters
|
||||||
{
|
{
|
||||||
Colour = GlowColour,
|
Colour = GlowColour.Opacity(0),
|
||||||
Type = EdgeEffectType.Glow,
|
Type = EdgeEffectType.Glow,
|
||||||
Radius = 10,
|
Radius = 10,
|
||||||
Roundness = 8,
|
Roundness = 8,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void LoadComplete()
|
|
||||||
{
|
|
||||||
FadeEdgeEffectTo(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool glowing;
|
private bool glowing;
|
||||||
|
|
||||||
public bool Glowing
|
public bool Glowing
|
||||||
|
@ -36,6 +36,7 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
|
|
||||||
public Color4 BackgroundColour
|
public Color4 BackgroundColour
|
||||||
{
|
{
|
||||||
|
get => backgroundColour ?? Color4.White;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
backgroundColour = value;
|
backgroundColour = value;
|
||||||
|
@ -69,6 +69,7 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
BackgroundColour = Color4.Black.Opacity(0.5f);
|
BackgroundColour = Color4.Black.Opacity(0.5f);
|
||||||
|
|
||||||
MaskingContainer.CornerRadius = corner_radius;
|
MaskingContainer.CornerRadius = corner_radius;
|
||||||
|
Alpha = 0;
|
||||||
|
|
||||||
// todo: this uses the same styling as OsuMenu. hopefully we can just use OsuMenu in the future with some refactoring
|
// todo: this uses the same styling as OsuMenu. hopefully we can just use OsuMenu in the future with some refactoring
|
||||||
ItemsContainer.Padding = new MarginPadding(5);
|
ItemsContainer.Padding = new MarginPadding(5);
|
||||||
@ -94,10 +95,12 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
|
|
||||||
protected override void AnimateClose()
|
protected override void AnimateClose()
|
||||||
{
|
{
|
||||||
this.FadeOut(300, Easing.OutQuint);
|
|
||||||
if (wasOpened)
|
if (wasOpened)
|
||||||
|
{
|
||||||
|
this.FadeOut(300, Easing.OutQuint);
|
||||||
sampleClose?.Play();
|
sampleClose?.Play();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// todo: this uses the same styling as OsuMenu. hopefully we can just use OsuMenu in the future with some refactoring
|
// todo: this uses the same styling as OsuMenu. hopefully we can just use OsuMenu in the future with some refactoring
|
||||||
protected override void UpdateSize(Vector2 newSize)
|
protected override void UpdateSize(Vector2 newSize)
|
||||||
|
@ -8,6 +8,5 @@ namespace osu.Game.Online.Rooms
|
|||||||
// used for osu-web deserialization so names shouldn't be changed.
|
// used for osu-web deserialization so names shouldn't be changed.
|
||||||
Normal,
|
Normal,
|
||||||
Spotlight,
|
Spotlight,
|
||||||
Realtime,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ using osu.Framework.Bindables;
|
|||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Colour;
|
||||||
using osu.Framework.Graphics.Cursor;
|
using osu.Framework.Graphics.Cursor;
|
||||||
using osu.Framework.Graphics.Effects;
|
using osu.Framework.Graphics.Effects;
|
||||||
using osu.Framework.Graphics.UserInterface;
|
using osu.Framework.Graphics.UserInterface;
|
||||||
@ -38,12 +39,12 @@ namespace osu.Game.Overlays
|
|||||||
current.ValueChanged += _ => UpdateState();
|
current.ValueChanged += _ => UpdateState();
|
||||||
current.DefaultChanged += _ => UpdateState();
|
current.DefaultChanged += _ => UpdateState();
|
||||||
current.DisabledChanged += _ => UpdateState();
|
current.DisabledChanged += _ => UpdateState();
|
||||||
|
|
||||||
|
if (IsLoaded)
|
||||||
UpdateState();
|
UpdateState();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Color4 buttonColour;
|
|
||||||
|
|
||||||
private bool hovering;
|
private bool hovering;
|
||||||
|
|
||||||
public RestoreDefaultValueButton()
|
public RestoreDefaultValueButton()
|
||||||
@ -58,12 +59,11 @@ namespace osu.Game.Overlays
|
|||||||
private void load(OsuColour colour)
|
private void load(OsuColour colour)
|
||||||
{
|
{
|
||||||
BackgroundColour = colour.Yellow;
|
BackgroundColour = colour.Yellow;
|
||||||
buttonColour = colour.Yellow;
|
|
||||||
Content.Width = 0.33f;
|
Content.Width = 0.33f;
|
||||||
Content.CornerRadius = 3;
|
Content.CornerRadius = 3;
|
||||||
Content.EdgeEffect = new EdgeEffectParameters
|
Content.EdgeEffect = new EdgeEffectParameters
|
||||||
{
|
{
|
||||||
Colour = buttonColour.Opacity(0.1f),
|
Colour = BackgroundColour.Opacity(0.1f),
|
||||||
Type = EdgeEffectType.Glow,
|
Type = EdgeEffectType.Glow,
|
||||||
Radius = 2,
|
Radius = 2,
|
||||||
};
|
};
|
||||||
@ -81,7 +81,10 @@ namespace osu.Game.Overlays
|
|||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
UpdateState();
|
|
||||||
|
// avoid unnecessary transforms on first display.
|
||||||
|
Alpha = currentAlpha;
|
||||||
|
Background.Colour = currentColour;
|
||||||
}
|
}
|
||||||
|
|
||||||
public LocalisableString TooltipText => "revert to default";
|
public LocalisableString TooltipText => "revert to default";
|
||||||
@ -101,14 +104,16 @@ namespace osu.Game.Overlays
|
|||||||
|
|
||||||
public void UpdateState() => Scheduler.AddOnce(updateState);
|
public void UpdateState() => Scheduler.AddOnce(updateState);
|
||||||
|
|
||||||
|
private float currentAlpha => current.IsDefault ? 0f : hovering && !current.Disabled ? 1f : 0.65f;
|
||||||
|
private ColourInfo currentColour => current.Disabled ? Color4.Gray : BackgroundColour;
|
||||||
|
|
||||||
private void updateState()
|
private void updateState()
|
||||||
{
|
{
|
||||||
if (current == null)
|
if (current == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this.FadeTo(current.IsDefault ? 0f :
|
this.FadeTo(currentAlpha, 200, Easing.OutQuint);
|
||||||
hovering && !current.Disabled ? 1f : 0.65f, 200, Easing.OutQuint);
|
Background.FadeColour(currentColour, 200, Easing.OutQuint);
|
||||||
this.FadeColour(current.Disabled ? Color4.Gray : buttonColour, 200, Easing.OutQuint);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,17 +21,26 @@ namespace osu.Game.Overlays.Settings.Sections.Audio
|
|||||||
|
|
||||||
private SettingsDropdown<string> dropdown;
|
private SettingsDropdown<string> dropdown;
|
||||||
|
|
||||||
protected override void Dispose(bool isDisposing)
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
{
|
{
|
||||||
base.Dispose(isDisposing);
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
dropdown = new AudioDeviceSettingsDropdown
|
||||||
|
{
|
||||||
|
Keywords = new[] { "speaker", "headphone", "output" }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if (audio != null)
|
updateItems();
|
||||||
{
|
|
||||||
audio.OnNewDevice -= onDeviceChanged;
|
audio.OnNewDevice += onDeviceChanged;
|
||||||
audio.OnLostDevice -= onDeviceChanged;
|
audio.OnLostDevice += onDeviceChanged;
|
||||||
}
|
dropdown.Current = audio.AudioDevice;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void onDeviceChanged(string name) => updateItems();
|
||||||
|
|
||||||
private void updateItems()
|
private void updateItems()
|
||||||
{
|
{
|
||||||
var deviceItems = new List<string> { string.Empty };
|
var deviceItems = new List<string> { string.Empty };
|
||||||
@ -50,26 +59,15 @@ namespace osu.Game.Overlays.Settings.Sections.Audio
|
|||||||
dropdown.Items = deviceItems.Distinct().ToList();
|
dropdown.Items = deviceItems.Distinct().ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onDeviceChanged(string name) => updateItems();
|
protected override void Dispose(bool isDisposing)
|
||||||
|
{
|
||||||
|
base.Dispose(isDisposing);
|
||||||
|
|
||||||
protected override void LoadComplete()
|
if (audio != null)
|
||||||
{
|
{
|
||||||
base.LoadComplete();
|
audio.OnNewDevice -= onDeviceChanged;
|
||||||
|
audio.OnLostDevice -= onDeviceChanged;
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
dropdown = new AudioDeviceSettingsDropdown
|
|
||||||
{
|
|
||||||
Keywords = new[] { "speaker", "headphone", "output" }
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
updateItems();
|
|
||||||
|
|
||||||
dropdown.Current = audio.AudioDevice;
|
|
||||||
|
|
||||||
audio.OnNewDevice += onDeviceChanged;
|
|
||||||
audio.OnLostDevice += onDeviceChanged;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class AudioDeviceSettingsDropdown : SettingsDropdown<string>
|
private class AudioDeviceSettingsDropdown : SettingsDropdown<string>
|
||||||
|
@ -98,8 +98,6 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
|
|||||||
Direction = FillDirection.Vertical,
|
Direction = FillDirection.Vertical,
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
AutoSizeAxes = Axes.Y,
|
AutoSizeAxes = Axes.Y,
|
||||||
AutoSizeDuration = transition_duration,
|
|
||||||
AutoSizeEasing = Easing.OutQuint,
|
|
||||||
Masking = true,
|
Masking = true,
|
||||||
Children = new[]
|
Children = new[]
|
||||||
{
|
{
|
||||||
@ -176,13 +174,14 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
|
|||||||
scalingMode.BindValueChanged(mode =>
|
scalingMode.BindValueChanged(mode =>
|
||||||
{
|
{
|
||||||
scalingSettings.ClearTransforms();
|
scalingSettings.ClearTransforms();
|
||||||
scalingSettings.AutoSizeAxes = mode.NewValue != ScalingMode.Off ? Axes.Y : Axes.None;
|
scalingSettings.AutoSizeDuration = transition_duration;
|
||||||
|
scalingSettings.AutoSizeEasing = Easing.OutQuint;
|
||||||
|
|
||||||
if (mode.NewValue == ScalingMode.Off)
|
updateScalingModeVisibility();
|
||||||
scalingSettings.ResizeHeightTo(0, transition_duration, Easing.OutQuint);
|
});
|
||||||
|
|
||||||
scalingSettings.ForEach(s => s.TransferValueOnCommit = mode.NewValue == ScalingMode.Everything);
|
// initial update bypasses transforms
|
||||||
}, true);
|
updateScalingModeVisibility();
|
||||||
|
|
||||||
void updateResolutionDropdown()
|
void updateResolutionDropdown()
|
||||||
{
|
{
|
||||||
@ -191,6 +190,15 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
|
|||||||
else
|
else
|
||||||
resolutionDropdown.Hide();
|
resolutionDropdown.Hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void updateScalingModeVisibility()
|
||||||
|
{
|
||||||
|
if (scalingMode.Value == ScalingMode.Off)
|
||||||
|
scalingSettings.ResizeHeightTo(0, transition_duration, Easing.OutQuint);
|
||||||
|
|
||||||
|
scalingSettings.AutoSizeAxes = scalingMode.Value != ScalingMode.Off ? Axes.Y : Axes.None;
|
||||||
|
scalingSettings.ForEach(s => s.TransferValueOnCommit = scalingMode.Value == ScalingMode.Everything);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void bindPreviewEvent(Bindable<float> bindable)
|
private void bindPreviewEvent(Bindable<float> bindable)
|
||||||
|
@ -65,7 +65,7 @@ namespace osu.Game.Overlays.Settings
|
|||||||
{
|
{
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
bool hasValue = string.IsNullOrWhiteSpace(value.ToString());
|
bool hasValue = !string.IsNullOrWhiteSpace(value.ToString());
|
||||||
|
|
||||||
if (warningText == null)
|
if (warningText == null)
|
||||||
{
|
{
|
||||||
@ -76,7 +76,7 @@ namespace osu.Game.Overlays.Settings
|
|||||||
FlowContent.Add(warningText = new SettingsNoticeText(colours) { Margin = new MarginPadding { Bottom = 5 } });
|
FlowContent.Add(warningText = new SettingsNoticeText(colours) { Margin = new MarginPadding { Bottom = 5 } });
|
||||||
}
|
}
|
||||||
|
|
||||||
warningText.Alpha = hasValue ? 0 : 1;
|
warningText.Alpha = hasValue ? 1 : 0;
|
||||||
warningText.Text = value.ToString(); // TODO: Remove ToString() call after TextFlowContainer supports localisation (see https://github.com/ppy/osu-framework/issues/4636).
|
warningText.Text = value.ToString(); // TODO: Remove ToString() call after TextFlowContainer supports localisation (see https://github.com/ppy/osu-framework/issues/4636).
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -93,15 +93,13 @@ namespace osu.Game.Overlays.Settings
|
|||||||
|
|
||||||
public bool MatchingFilter
|
public bool MatchingFilter
|
||||||
{
|
{
|
||||||
set => this.FadeTo(value ? 1 : 0);
|
set => Alpha = value ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool FilteringActive { get; set; }
|
public bool FilteringActive { get; set; }
|
||||||
|
|
||||||
public event Action SettingChanged;
|
public event Action SettingChanged;
|
||||||
|
|
||||||
private readonly RestoreDefaultValueButton<T> restoreDefaultButton;
|
|
||||||
|
|
||||||
protected SettingsItem()
|
protected SettingsItem()
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X;
|
RelativeSizeAxes = Axes.X;
|
||||||
@ -110,7 +108,6 @@ namespace osu.Game.Overlays.Settings
|
|||||||
|
|
||||||
InternalChildren = new Drawable[]
|
InternalChildren = new Drawable[]
|
||||||
{
|
{
|
||||||
restoreDefaultButton = new RestoreDefaultValueButton<T>(),
|
|
||||||
FlowContent = new FillFlowContainer
|
FlowContent = new FillFlowContainer
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
@ -123,7 +120,7 @@ namespace osu.Game.Overlays.Settings
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// all bindable logic is in constructor intentionally to support "CreateSettingsControls" being used in a context it is
|
// IMPORTANT: all bindable logic is in constructor intentionally to support "CreateSettingsControls" being used in a context it is
|
||||||
// never loaded, but requires bindable storage.
|
// never loaded, but requires bindable storage.
|
||||||
if (controlWithCurrent == null)
|
if (controlWithCurrent == null)
|
||||||
throw new ArgumentException(@$"Control created via {nameof(CreateControl)} must implement {nameof(IHasCurrentValue<T>)}");
|
throw new ArgumentException(@$"Control created via {nameof(CreateControl)} must implement {nameof(IHasCurrentValue<T>)}");
|
||||||
@ -132,12 +129,17 @@ namespace osu.Game.Overlays.Settings
|
|||||||
controlWithCurrent.Current.DisabledChanged += _ => updateDisabled();
|
controlWithCurrent.Current.DisabledChanged += _ => updateDisabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void LoadComplete()
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
{
|
{
|
||||||
base.LoadComplete();
|
// intentionally done before LoadComplete to avoid overhead.
|
||||||
|
|
||||||
if (ShowsDefaultIndicator)
|
if (ShowsDefaultIndicator)
|
||||||
restoreDefaultButton.Current = controlWithCurrent.Current;
|
{
|
||||||
|
AddInternal(new RestoreDefaultValueButton<T>
|
||||||
|
{
|
||||||
|
Current = controlWithCurrent.Current,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateDisabled()
|
private void updateDisabled()
|
||||||
|
@ -22,6 +22,9 @@ namespace osu.Game.Overlays.Settings
|
|||||||
private readonly Box selectionIndicator;
|
private readonly Box selectionIndicator;
|
||||||
private readonly Container text;
|
private readonly Container text;
|
||||||
|
|
||||||
|
// always consider as part of flow, even when not visible (for the sake of the initial animation).
|
||||||
|
public override bool IsPresent => true;
|
||||||
|
|
||||||
private SettingsSection section;
|
private SettingsSection section;
|
||||||
|
|
||||||
public SettingsSection Section
|
public SettingsSection Section
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
@ -58,6 +59,12 @@ namespace osu.Game.Overlays
|
|||||||
|
|
||||||
private readonly bool showSidebar;
|
private readonly bool showSidebar;
|
||||||
|
|
||||||
|
private LoadingLayer loading;
|
||||||
|
|
||||||
|
private readonly List<SettingsSection> loadableSections = new List<SettingsSection>();
|
||||||
|
|
||||||
|
private Task sectionsLoadingTask;
|
||||||
|
|
||||||
protected SettingsPanel(bool showSidebar)
|
protected SettingsPanel(bool showSidebar)
|
||||||
{
|
{
|
||||||
this.showSidebar = showSidebar;
|
this.showSidebar = showSidebar;
|
||||||
@ -86,7 +93,14 @@ namespace osu.Game.Overlays
|
|||||||
Colour = OsuColour.Gray(0.05f),
|
Colour = OsuColour.Gray(0.05f),
|
||||||
Alpha = 1,
|
Alpha = 1,
|
||||||
},
|
},
|
||||||
SectionsContainer = new SettingsSectionsContainer
|
loading = new LoadingLayer
|
||||||
|
{
|
||||||
|
State = { Value = Visibility.Visible }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Add(SectionsContainer = new SettingsSectionsContainer
|
||||||
{
|
{
|
||||||
Masking = true,
|
Masking = true,
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
@ -103,52 +117,24 @@ namespace osu.Game.Overlays
|
|||||||
Bottom = 20
|
Bottom = 20
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Footer = CreateFooter()
|
Footer = CreateFooter().With(f => f.Alpha = 0)
|
||||||
},
|
});
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (showSidebar)
|
if (showSidebar)
|
||||||
{
|
{
|
||||||
AddInternal(Sidebar = new Sidebar { Width = sidebar_width });
|
AddInternal(Sidebar = new Sidebar { Width = sidebar_width });
|
||||||
|
|
||||||
SectionsContainer.SelectedSection.ValueChanged += section =>
|
|
||||||
{
|
|
||||||
selectedSidebarButton.Selected = false;
|
|
||||||
selectedSidebarButton = Sidebar.Children.Single(b => b.Section == section.NewValue);
|
|
||||||
selectedSidebarButton.Selected = true;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
searchTextBox.Current.ValueChanged += term => SectionsContainer.SearchContainer.SearchTerm = term.NewValue;
|
|
||||||
|
|
||||||
CreateSections()?.ForEach(AddSection);
|
CreateSections()?.ForEach(AddSection);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void AddSection(SettingsSection section)
|
protected void AddSection(SettingsSection section)
|
||||||
{
|
{
|
||||||
SectionsContainer.Add(section);
|
if (IsLoaded)
|
||||||
|
// just to keep things simple. can be accommodated for if we ever need it.
|
||||||
|
throw new InvalidOperationException("All sections must be added before the panel is loaded.");
|
||||||
|
|
||||||
if (Sidebar != null)
|
loadableSections.Add(section);
|
||||||
{
|
|
||||||
var button = new SidebarButton
|
|
||||||
{
|
|
||||||
Section = section,
|
|
||||||
Action = () =>
|
|
||||||
{
|
|
||||||
SectionsContainer.ScrollTo(section);
|
|
||||||
Sidebar.State = ExpandedState.Contracted;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
Sidebar.Add(button);
|
|
||||||
|
|
||||||
if (selectedSidebarButton == null)
|
|
||||||
{
|
|
||||||
selectedSidebarButton = Sidebar.Children.First();
|
|
||||||
selectedSidebarButton.Selected = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual Drawable CreateHeader() => new Container();
|
protected virtual Drawable CreateHeader() => new Container();
|
||||||
@ -161,6 +147,12 @@ namespace osu.Game.Overlays
|
|||||||
|
|
||||||
ContentContainer.MoveToX(ExpandedPosition, TRANSITION_LENGTH, Easing.OutQuint);
|
ContentContainer.MoveToX(ExpandedPosition, TRANSITION_LENGTH, Easing.OutQuint);
|
||||||
|
|
||||||
|
// delay load enough to ensure it doesn't overlap with the initial animation.
|
||||||
|
// this is done as there is still a brief stutter during load completion which is more visible if the transition is in progress.
|
||||||
|
// the eventual goal would be to remove the need for this by splitting up load into smaller work pieces, or fixing the remaining
|
||||||
|
// load complete overheads.
|
||||||
|
Scheduler.AddDelayed(loadSections, TRANSITION_LENGTH / 3);
|
||||||
|
|
||||||
Sidebar?.MoveToX(0, TRANSITION_LENGTH, Easing.OutQuint);
|
Sidebar?.MoveToX(0, TRANSITION_LENGTH, Easing.OutQuint);
|
||||||
this.FadeTo(1, TRANSITION_LENGTH, Easing.OutQuint);
|
this.FadeTo(1, TRANSITION_LENGTH, Easing.OutQuint);
|
||||||
|
|
||||||
@ -199,6 +191,78 @@ namespace osu.Game.Overlays
|
|||||||
Padding = new MarginPadding { Top = GetToolbarHeight?.Invoke() ?? 0 };
|
Padding = new MarginPadding { Top = GetToolbarHeight?.Invoke() ?? 0 };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private const double fade_in_duration = 1000;
|
||||||
|
|
||||||
|
private void loadSections()
|
||||||
|
{
|
||||||
|
if (sectionsLoadingTask != null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
sectionsLoadingTask = LoadComponentsAsync(loadableSections, sections =>
|
||||||
|
{
|
||||||
|
SectionsContainer.AddRange(sections);
|
||||||
|
SectionsContainer.Footer.FadeInFromZero(fade_in_duration, Easing.OutQuint);
|
||||||
|
SectionsContainer.SearchContainer.FadeInFromZero(fade_in_duration, Easing.OutQuint);
|
||||||
|
|
||||||
|
loading.Hide();
|
||||||
|
|
||||||
|
searchTextBox.Current.BindValueChanged(term => SectionsContainer.SearchContainer.SearchTerm = term.NewValue, true);
|
||||||
|
searchTextBox.TakeFocus();
|
||||||
|
|
||||||
|
loadSidebarButtons();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadSidebarButtons()
|
||||||
|
{
|
||||||
|
if (Sidebar == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
LoadComponentsAsync(createSidebarButtons(), buttons =>
|
||||||
|
{
|
||||||
|
float delay = 0;
|
||||||
|
|
||||||
|
foreach (var button in buttons)
|
||||||
|
{
|
||||||
|
Sidebar.Add(button);
|
||||||
|
|
||||||
|
button.FadeOut()
|
||||||
|
.Delay(delay)
|
||||||
|
.FadeInFromZero(fade_in_duration, Easing.OutQuint);
|
||||||
|
|
||||||
|
delay += 40;
|
||||||
|
}
|
||||||
|
|
||||||
|
SectionsContainer.SelectedSection.BindValueChanged(section =>
|
||||||
|
{
|
||||||
|
if (selectedSidebarButton != null)
|
||||||
|
selectedSidebarButton.Selected = false;
|
||||||
|
|
||||||
|
selectedSidebarButton = Sidebar.Children.Single(b => b.Section == section.NewValue);
|
||||||
|
selectedSidebarButton.Selected = true;
|
||||||
|
}, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerable<SidebarButton> createSidebarButtons()
|
||||||
|
{
|
||||||
|
foreach (var section in SectionsContainer)
|
||||||
|
{
|
||||||
|
yield return new SidebarButton
|
||||||
|
{
|
||||||
|
Section = section,
|
||||||
|
Action = () =>
|
||||||
|
{
|
||||||
|
if (!SectionsContainer.IsLoaded)
|
||||||
|
return;
|
||||||
|
|
||||||
|
SectionsContainer.ScrollTo(section);
|
||||||
|
Sidebar.State = ExpandedState.Contracted;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private class NonMaskedContent : Container<Drawable>
|
private class NonMaskedContent : Container<Drawable>
|
||||||
{
|
{
|
||||||
// masking breaks the pan-out transform with nested sub-settings panels.
|
// masking breaks the pan-out transform with nested sub-settings panels.
|
||||||
|
@ -41,7 +41,7 @@ namespace osu.Game.Rulesets.Mods
|
|||||||
{
|
{
|
||||||
// Intercept and extract the internal number bindable from DifficultyBindable.
|
// Intercept and extract the internal number bindable from DifficultyBindable.
|
||||||
// This will provide bounds and precision specifications for the slider bar.
|
// This will provide bounds and precision specifications for the slider bar.
|
||||||
difficultyBindable = ((DifficultyBindable)value).GetBoundCopy();
|
difficultyBindable = (DifficultyBindable)value.GetBoundCopy();
|
||||||
sliderDisplayCurrent.BindTo(difficultyBindable.CurrentNumber);
|
sliderDisplayCurrent.BindTo(difficultyBindable.CurrentNumber);
|
||||||
|
|
||||||
base.Current = difficultyBindable;
|
base.Current = difficultyBindable;
|
||||||
|
@ -128,6 +128,6 @@ namespace osu.Game.Rulesets.Mods
|
|||||||
ExtendedLimits.UnbindFrom(otherDifficultyBindable.ExtendedLimits);
|
ExtendedLimits.UnbindFrom(otherDifficultyBindable.ExtendedLimits);
|
||||||
}
|
}
|
||||||
|
|
||||||
public new DifficultyBindable GetBoundCopy() => new DifficultyBindable { BindTarget = this };
|
protected override Bindable<float?> CreateInstance() => new DifficultyBindable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -129,6 +129,17 @@ namespace osu.Game.Rulesets.Mods
|
|||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public virtual Type[] IncompatibleMods => Array.Empty<Type>();
|
public virtual Type[] IncompatibleMods => Array.Empty<Type>();
|
||||||
|
|
||||||
|
private IReadOnlyList<IBindable> settingsBacking;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A list of the all <see cref="IBindable"/> settings within this mod.
|
||||||
|
/// </summary>
|
||||||
|
internal IReadOnlyList<IBindable> Settings =>
|
||||||
|
settingsBacking ??= this.GetSettingsSourceProperties()
|
||||||
|
.Select(p => p.Item2.GetValue(this))
|
||||||
|
.Cast<IBindable>()
|
||||||
|
.ToList();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a copy of this <see cref="Mod"/> initialised to a default state.
|
/// Creates a copy of this <see cref="Mod"/> initialised to a default state.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -191,15 +202,39 @@ namespace osu.Game.Rulesets.Mods
|
|||||||
if (ReferenceEquals(this, other)) return true;
|
if (ReferenceEquals(this, other)) return true;
|
||||||
|
|
||||||
return GetType() == other.GetType() &&
|
return GetType() == other.GetType() &&
|
||||||
this.GetSettingsSourceProperties().All(pair =>
|
Settings.SequenceEqual(other.Settings, ModSettingsEqualityComparer.Default);
|
||||||
EqualityComparer<object>.Default.Equals(
|
}
|
||||||
ModUtils.GetSettingUnderlyingValue(pair.Item2.GetValue(this)),
|
|
||||||
ModUtils.GetSettingUnderlyingValue(pair.Item2.GetValue(other))));
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
var hashCode = new HashCode();
|
||||||
|
|
||||||
|
hashCode.Add(GetType());
|
||||||
|
|
||||||
|
foreach (var setting in Settings)
|
||||||
|
hashCode.Add(ModUtils.GetSettingUnderlyingValue(setting));
|
||||||
|
|
||||||
|
return hashCode.ToHashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Reset all custom settings for this mod back to their defaults.
|
/// Reset all custom settings for this mod back to their defaults.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual void ResetSettingsToDefaults() => CopyFrom((Mod)Activator.CreateInstance(GetType()));
|
public virtual void ResetSettingsToDefaults() => CopyFrom((Mod)Activator.CreateInstance(GetType()));
|
||||||
|
|
||||||
|
private class ModSettingsEqualityComparer : IEqualityComparer<IBindable>
|
||||||
|
{
|
||||||
|
public static ModSettingsEqualityComparer Default { get; } = new ModSettingsEqualityComparer();
|
||||||
|
|
||||||
|
public bool Equals(IBindable x, IBindable y)
|
||||||
|
{
|
||||||
|
object xValue = x == null ? null : ModUtils.GetSettingUnderlyingValue(x);
|
||||||
|
object yValue = y == null ? null : ModUtils.GetSettingUnderlyingValue(y);
|
||||||
|
|
||||||
|
return EqualityComparer<object>.Default.Equals(xValue, yValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int GetHashCode(IBindable obj) => ModUtils.GetSettingUnderlyingValue(obj).GetHashCode();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,6 +41,8 @@ namespace osu.Game.Screens.Edit
|
|||||||
protected override int DefaultMaxValue => VALID_DIVISORS.Last();
|
protected override int DefaultMaxValue => VALID_DIVISORS.Last();
|
||||||
protected override int DefaultPrecision => 1;
|
protected override int DefaultPrecision => 1;
|
||||||
|
|
||||||
|
protected override Bindable<int> CreateInstance() => new BindableBeatDivisor();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Retrieves the appropriate colour for a beat divisor.
|
/// Retrieves the appropriate colour for a beat divisor.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -10,8 +10,8 @@ using osu.Framework.Graphics.Containers;
|
|||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Utils;
|
using osu.Framework.Utils;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Beatmaps.Drawables;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Screens.Ranking.Expanded;
|
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
|
||||||
namespace osu.Game.Screens.OnlinePlay.Components
|
namespace osu.Game.Screens.OnlinePlay.Components
|
||||||
@ -64,8 +64,8 @@ namespace osu.Game.Screens.OnlinePlay.Components
|
|||||||
AutoSizeAxes = Axes.Both,
|
AutoSizeAxes = Axes.Both,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
minDisplay = new StarRatingDisplay(default),
|
minDisplay = new StarRatingDisplay(default, StarRatingDisplaySize.Range),
|
||||||
maxDisplay = new StarRatingDisplay(default)
|
maxDisplay = new StarRatingDisplay(default, StarRatingDisplaySize.Range)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1,32 +1,19 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using osu.Framework;
|
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Audio;
|
|
||||||
using osu.Framework.Audio.Sample;
|
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Extensions;
|
|
||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Colour;
|
using osu.Framework.Graphics.Colour;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Cursor;
|
|
||||||
using osu.Framework.Graphics.Effects;
|
using osu.Framework.Graphics.Effects;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Graphics.UserInterface;
|
|
||||||
using osu.Framework.Input.Bindings;
|
|
||||||
using osu.Framework.Input.Events;
|
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Graphics.Containers;
|
using osu.Game.Graphics.Containers;
|
||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
using osu.Game.Graphics.UserInterface;
|
|
||||||
using osu.Game.Graphics.UserInterfaceV2;
|
|
||||||
using osu.Game.Input.Bindings;
|
|
||||||
using osu.Game.Online.Rooms;
|
using osu.Game.Online.Rooms;
|
||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
using osu.Game.Screens.OnlinePlay.Components;
|
using osu.Game.Screens.OnlinePlay.Components;
|
||||||
@ -35,105 +22,26 @@ using osuTK.Graphics;
|
|||||||
|
|
||||||
namespace osu.Game.Screens.OnlinePlay.Lounge.Components
|
namespace osu.Game.Screens.OnlinePlay.Lounge.Components
|
||||||
{
|
{
|
||||||
public class DrawableRoom : OsuClickableContainer, IStateful<SelectionState>, IFilterable, IHasContextMenu, IHasPopover, IKeyBindingHandler<GlobalAction>
|
public class DrawableRoom : CompositeDrawable
|
||||||
{
|
{
|
||||||
public const float SELECTION_BORDER_WIDTH = 4;
|
protected const float CORNER_RADIUS = 10;
|
||||||
private const float corner_radius = 10;
|
|
||||||
private const float transition_duration = 60;
|
|
||||||
private const float height = 100;
|
private const float height = 100;
|
||||||
|
|
||||||
public event Action<SelectionState> StateChanged;
|
public readonly Room Room;
|
||||||
|
|
||||||
protected override HoverSounds CreateHoverSounds(HoverSampleSet sampleSet) => new HoverSounds();
|
|
||||||
|
|
||||||
private Drawable selectionBox;
|
|
||||||
|
|
||||||
[Resolved(canBeNull: true)]
|
|
||||||
private LoungeSubScreen loungeScreen { get; set; }
|
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private BeatmapManager beatmaps { get; set; }
|
private BeatmapManager beatmaps { get; set; }
|
||||||
|
|
||||||
[Resolved(canBeNull: true)]
|
protected Container ButtonsContainer { get; private set; }
|
||||||
private Bindable<Room> selectedRoom { get; set; }
|
|
||||||
|
|
||||||
[Resolved(canBeNull: true)]
|
|
||||||
private LoungeSubScreen lounge { get; set; }
|
|
||||||
|
|
||||||
public readonly Room Room;
|
|
||||||
|
|
||||||
private SelectionState state;
|
|
||||||
|
|
||||||
private Sample sampleSelect;
|
|
||||||
private Sample sampleJoin;
|
|
||||||
|
|
||||||
public SelectionState State
|
|
||||||
{
|
|
||||||
get => state;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (value == state)
|
|
||||||
return;
|
|
||||||
|
|
||||||
state = value;
|
|
||||||
|
|
||||||
if (selectionBox != null)
|
|
||||||
{
|
|
||||||
if (state == SelectionState.Selected)
|
|
||||||
selectionBox.FadeIn(transition_duration);
|
|
||||||
else
|
|
||||||
selectionBox.FadeOut(transition_duration);
|
|
||||||
}
|
|
||||||
|
|
||||||
StateChanged?.Invoke(State);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<string> FilterTerms => new[] { Room.Name.Value };
|
|
||||||
|
|
||||||
private bool matchingFilter;
|
|
||||||
|
|
||||||
public bool MatchingFilter
|
|
||||||
{
|
|
||||||
get => matchingFilter;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
matchingFilter = value;
|
|
||||||
|
|
||||||
if (!IsLoaded)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (matchingFilter)
|
|
||||||
this.FadeIn(200);
|
|
||||||
else
|
|
||||||
Hide();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private int numberOfAvatars = 7;
|
|
||||||
|
|
||||||
public int NumberOfAvatars
|
|
||||||
{
|
|
||||||
get => numberOfAvatars;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
numberOfAvatars = value;
|
|
||||||
|
|
||||||
if (recentParticipantsList != null)
|
|
||||||
recentParticipantsList.NumberOfCircles = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
private readonly Bindable<MatchType> roomType = new Bindable<MatchType>();
|
||||||
private readonly Bindable<RoomCategory> roomCategory = new Bindable<RoomCategory>();
|
private readonly Bindable<RoomCategory> roomCategory = new Bindable<RoomCategory>();
|
||||||
|
private readonly Bindable<bool> hasPassword = new Bindable<bool>();
|
||||||
|
|
||||||
private RecentParticipantsList recentParticipantsList;
|
private RecentParticipantsList recentParticipantsList;
|
||||||
private RoomSpecialCategoryPill specialCategoryPill;
|
private RoomSpecialCategoryPill specialCategoryPill;
|
||||||
|
|
||||||
public bool FilteringActive { get; set; }
|
|
||||||
|
|
||||||
private PasswordProtectedIcon passwordIcon;
|
private PasswordProtectedIcon passwordIcon;
|
||||||
|
private EndDateInfo endDateInfo;
|
||||||
private readonly Bindable<bool> hasPassword = new Bindable<bool>();
|
|
||||||
|
|
||||||
public DrawableRoom(Room room)
|
public DrawableRoom(Room room)
|
||||||
{
|
{
|
||||||
@ -143,7 +51,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
|
|||||||
Height = height;
|
Height = height;
|
||||||
|
|
||||||
Masking = true;
|
Masking = true;
|
||||||
CornerRadius = corner_radius + SELECTION_BORDER_WIDTH / 2;
|
CornerRadius = CORNER_RADIUS;
|
||||||
EdgeEffect = new EdgeEffectParameters
|
EdgeEffect = new EdgeEffectParameters
|
||||||
{
|
{
|
||||||
Type = EdgeEffectType.Shadow,
|
Type = EdgeEffectType.Shadow,
|
||||||
@ -153,9 +61,9 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
|
|||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OverlayColourProvider colours, AudioManager audio)
|
private void load(OverlayColourProvider colours)
|
||||||
{
|
{
|
||||||
Children = new Drawable[]
|
InternalChildren = new[]
|
||||||
{
|
{
|
||||||
// This resolves internal 1px gaps due to applying the (parenting) corner radius and masking across multiple filling background sprites.
|
// This resolves internal 1px gaps due to applying the (parenting) corner radius and masking across multiple filling background sprites.
|
||||||
new Box
|
new Box
|
||||||
@ -163,10 +71,10 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
|
|||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Colour = colours.Background5,
|
Colour = colours.Background5,
|
||||||
},
|
},
|
||||||
new OnlinePlayBackgroundSprite
|
CreateBackground().With(d =>
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both
|
d.RelativeSizeAxes = Axes.Both;
|
||||||
},
|
}),
|
||||||
new Container
|
new Container
|
||||||
{
|
{
|
||||||
Name = @"Room content",
|
Name = @"Room content",
|
||||||
@ -177,7 +85,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
|
|||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Masking = true,
|
Masking = true,
|
||||||
CornerRadius = corner_radius,
|
CornerRadius = CORNER_RADIUS,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new GridContainer
|
new GridContainer
|
||||||
@ -238,10 +146,10 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
|
|||||||
Anchor = Anchor.CentreLeft,
|
Anchor = Anchor.CentreLeft,
|
||||||
Origin = Anchor.CentreLeft
|
Origin = Anchor.CentreLeft
|
||||||
},
|
},
|
||||||
new EndDateInfo
|
endDateInfo = new EndDateInfo
|
||||||
{
|
{
|
||||||
Anchor = Anchor.CentreLeft,
|
Anchor = Anchor.CentreLeft,
|
||||||
Origin = Anchor.CentreLeft
|
Origin = Anchor.CentreLeft,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -289,13 +197,21 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
|
|||||||
Origin = Anchor.CentreRight,
|
Origin = Anchor.CentreRight,
|
||||||
AutoSizeAxes = Axes.X,
|
AutoSizeAxes = Axes.X,
|
||||||
RelativeSizeAxes = Axes.Y,
|
RelativeSizeAxes = Axes.Y,
|
||||||
|
Spacing = new Vector2(5),
|
||||||
Padding = new MarginPadding
|
Padding = new MarginPadding
|
||||||
{
|
{
|
||||||
Right = 10,
|
Right = 10,
|
||||||
Vertical = 5
|
Vertical = 20,
|
||||||
},
|
},
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
|
ButtonsContainer = new Container
|
||||||
|
{
|
||||||
|
Anchor = Anchor.CentreRight,
|
||||||
|
Origin = Anchor.CentreRight,
|
||||||
|
RelativeSizeAxes = Axes.Y,
|
||||||
|
AutoSizeAxes = Axes.X
|
||||||
|
},
|
||||||
recentParticipantsList = new RecentParticipantsList
|
recentParticipantsList = new RecentParticipantsList
|
||||||
{
|
{
|
||||||
Anchor = Anchor.CentreRight,
|
Anchor = Anchor.CentreRight,
|
||||||
@ -308,36 +224,6 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
new StatusColouredContainer(transition_duration)
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Child = selectionBox = new Container
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Alpha = state == SelectionState.Selected ? 1 : 0,
|
|
||||||
Masking = true,
|
|
||||||
CornerRadius = corner_radius,
|
|
||||||
BorderThickness = SELECTION_BORDER_WIDTH,
|
|
||||||
BorderColour = Color4.White,
|
|
||||||
Child = new Box
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Alpha = 0,
|
|
||||||
AlwaysPresent = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
sampleSelect = audio.Samples.Get($@"UI/{HoverSampleSet.Default.GetDescription()}-select");
|
|
||||||
sampleJoin = audio.Samples.Get($@"UI/{HoverSampleSet.Submit.GetDescription()}-select");
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
|
|
||||||
{
|
|
||||||
return new CachedModelDependencyContainer<Room>(base.CreateChildDependencies(parent))
|
|
||||||
{
|
|
||||||
Model = { Value = Room }
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -345,11 +231,6 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
|
|||||||
{
|
{
|
||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
|
|
||||||
if (matchingFilter)
|
|
||||||
this.FadeInFromZero(transition_duration);
|
|
||||||
else
|
|
||||||
Alpha = 0;
|
|
||||||
|
|
||||||
roomCategory.BindTo(Room.Category);
|
roomCategory.BindTo(Room.Category);
|
||||||
roomCategory.BindValueChanged(c =>
|
roomCategory.BindValueChanged(c =>
|
||||||
{
|
{
|
||||||
@ -359,62 +240,39 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
|
|||||||
specialCategoryPill.Hide();
|
specialCategoryPill.Hide();
|
||||||
}, true);
|
}, true);
|
||||||
|
|
||||||
|
roomType.BindTo(Room.Type);
|
||||||
|
roomType.BindValueChanged(t =>
|
||||||
|
{
|
||||||
|
endDateInfo.Alpha = t.NewValue == MatchType.Playlists ? 1 : 0;
|
||||||
|
}, true);
|
||||||
|
|
||||||
hasPassword.BindTo(Room.HasPassword);
|
hasPassword.BindTo(Room.HasPassword);
|
||||||
hasPassword.BindValueChanged(v => passwordIcon.Alpha = v.NewValue ? 1 : 0, true);
|
hasPassword.BindValueChanged(v => passwordIcon.Alpha = v.NewValue ? 1 : 0, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Popover GetPopover() => new PasswordEntryPopover(Room) { JoinRequested = lounge.Join };
|
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
|
||||||
|
|
||||||
public MenuItem[] ContextMenuItems => new MenuItem[]
|
|
||||||
{
|
{
|
||||||
new OsuMenuItem("Create copy", MenuItemType.Standard, () =>
|
return new CachedModelDependencyContainer<Room>(base.CreateChildDependencies(parent))
|
||||||
{
|
{
|
||||||
lounge?.Open(Room.DeepClone());
|
Model = { Value = Room }
|
||||||
})
|
|
||||||
};
|
};
|
||||||
|
|
||||||
public bool OnPressed(GlobalAction action)
|
|
||||||
{
|
|
||||||
if (selectedRoom.Value != Room)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
switch (action)
|
|
||||||
{
|
|
||||||
case GlobalAction.Select:
|
|
||||||
TriggerClick();
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
private int numberOfAvatars = 7;
|
||||||
}
|
|
||||||
|
|
||||||
public void OnReleased(GlobalAction action)
|
public int NumberOfAvatars
|
||||||
{
|
{
|
||||||
}
|
get => numberOfAvatars;
|
||||||
|
set
|
||||||
protected override bool ShouldBeConsideredForInput(Drawable child) => state == SelectionState.Selected || child is HoverSounds;
|
|
||||||
|
|
||||||
protected override bool OnClick(ClickEvent e)
|
|
||||||
{
|
{
|
||||||
if (Room != selectedRoom.Value)
|
numberOfAvatars = value;
|
||||||
{
|
|
||||||
sampleSelect?.Play();
|
if (recentParticipantsList != null)
|
||||||
selectedRoom.Value = Room;
|
recentParticipantsList.NumberOfCircles = value;
|
||||||
return true;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Room.HasPassword.Value)
|
protected virtual Drawable CreateBackground() => new OnlinePlayBackgroundSprite();
|
||||||
{
|
|
||||||
sampleJoin?.Play();
|
|
||||||
this.ShowPopover();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
sampleJoin?.Play();
|
|
||||||
lounge?.Join(Room, null);
|
|
||||||
|
|
||||||
return base.OnClick(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
private class RoomNameText : OsuSpriteText
|
private class RoomNameText : OsuSpriteText
|
||||||
{
|
{
|
||||||
@ -500,52 +358,5 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class PasswordEntryPopover : OsuPopover
|
|
||||||
{
|
|
||||||
private readonly Room room;
|
|
||||||
|
|
||||||
public Action<Room, string> JoinRequested;
|
|
||||||
|
|
||||||
public PasswordEntryPopover(Room room)
|
|
||||||
{
|
|
||||||
this.room = room;
|
|
||||||
}
|
|
||||||
|
|
||||||
private OsuPasswordTextBox passwordTextbox;
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
|
||||||
private void load()
|
|
||||||
{
|
|
||||||
Child = new FillFlowContainer
|
|
||||||
{
|
|
||||||
Margin = new MarginPadding(10),
|
|
||||||
Spacing = new Vector2(5),
|
|
||||||
AutoSizeAxes = Axes.Both,
|
|
||||||
Direction = FillDirection.Horizontal,
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
passwordTextbox = new OsuPasswordTextBox
|
|
||||||
{
|
|
||||||
Width = 200,
|
|
||||||
},
|
|
||||||
new TriangleButton
|
|
||||||
{
|
|
||||||
Width = 80,
|
|
||||||
Text = "Join Room",
|
|
||||||
Action = () => JoinRequested?.Invoke(room, passwordTextbox.Text)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void LoadComplete()
|
|
||||||
{
|
|
||||||
base.LoadComplete();
|
|
||||||
|
|
||||||
Schedule(() => GetContainingInputManager().ChangeFocus(passwordTextbox));
|
|
||||||
passwordTextbox.OnCommit += (_, __) => JoinRequested?.Invoke(room, passwordTextbox.Text);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,6 @@ using osu.Framework.Input.Events;
|
|||||||
using osu.Framework.Threading;
|
using osu.Framework.Threading;
|
||||||
using osu.Game.Extensions;
|
using osu.Game.Extensions;
|
||||||
using osu.Game.Graphics.Cursor;
|
using osu.Game.Graphics.Cursor;
|
||||||
using osu.Game.Graphics.UserInterface;
|
|
||||||
using osu.Game.Input.Bindings;
|
using osu.Game.Input.Bindings;
|
||||||
using osu.Game.Online.Rooms;
|
using osu.Game.Online.Rooms;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
@ -26,7 +25,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
|
|||||||
{
|
{
|
||||||
private readonly IBindableList<Room> rooms = new BindableList<Room>();
|
private readonly IBindableList<Room> rooms = new BindableList<Room>();
|
||||||
|
|
||||||
private readonly FillFlowContainer<DrawableRoom> roomFlow;
|
private readonly FillFlowContainer<DrawableLoungeRoom> roomFlow;
|
||||||
|
|
||||||
public IReadOnlyList<DrawableRoom> Rooms => roomFlow.FlowingChildren.Cast<DrawableRoom>().ToArray();
|
public IReadOnlyList<DrawableRoom> Rooms => roomFlow.FlowingChildren.Cast<DrawableRoom>().ToArray();
|
||||||
|
|
||||||
@ -56,7 +55,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
|
|||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
AutoSizeAxes = Axes.Y,
|
AutoSizeAxes = Axes.Y,
|
||||||
Child = roomFlow = new FillFlowContainer<DrawableRoom>
|
Child = roomFlow = new FillFlowContainer<DrawableLoungeRoom>
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
AutoSizeAxes = Axes.Y,
|
AutoSizeAxes = Axes.Y,
|
||||||
@ -74,16 +73,8 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
|
|||||||
rooms.BindTo(roomManager.Rooms);
|
rooms.BindTo(roomManager.Rooms);
|
||||||
|
|
||||||
Filter?.BindValueChanged(criteria => applyFilterCriteria(criteria.NewValue), true);
|
Filter?.BindValueChanged(criteria => applyFilterCriteria(criteria.NewValue), true);
|
||||||
|
|
||||||
selectedRoom.BindValueChanged(selection =>
|
|
||||||
{
|
|
||||||
updateSelection();
|
|
||||||
}, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateSelection() =>
|
|
||||||
roomFlow.Children.ForEach(r => r.State = r.Room == selectedRoom.Value ? SelectionState.Selected : SelectionState.NotSelected);
|
|
||||||
|
|
||||||
private void applyFilterCriteria(FilterCriteria criteria)
|
private void applyFilterCriteria(FilterCriteria criteria)
|
||||||
{
|
{
|
||||||
roomFlow.Children.ForEach(r =>
|
roomFlow.Children.ForEach(r =>
|
||||||
@ -122,22 +113,17 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
|
|||||||
{
|
{
|
||||||
foreach (var room in rooms)
|
foreach (var room in rooms)
|
||||||
{
|
{
|
||||||
roomFlow.Add(new DrawableRoom(room));
|
roomFlow.Add(new DrawableLoungeRoom(room));
|
||||||
}
|
}
|
||||||
|
|
||||||
applyFilterCriteria(Filter?.Value);
|
applyFilterCriteria(Filter?.Value);
|
||||||
|
|
||||||
updateSelection();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void removeRooms(IEnumerable<Room> rooms)
|
private void removeRooms(IEnumerable<Room> rooms)
|
||||||
{
|
{
|
||||||
foreach (var r in rooms)
|
foreach (var r in rooms)
|
||||||
{
|
{
|
||||||
var toRemove = roomFlow.Single(d => d.Room == r);
|
roomFlow.RemoveAll(d => d.Room == r);
|
||||||
toRemove.Action = null;
|
|
||||||
|
|
||||||
roomFlow.Remove(toRemove);
|
|
||||||
|
|
||||||
// selection may have a lease due to being in a sub screen.
|
// selection may have a lease due to being in a sub screen.
|
||||||
if (!selectedRoom.Disabled)
|
if (!selectedRoom.Disabled)
|
||||||
|
226
osu.Game/Screens/OnlinePlay/Lounge/DrawableLoungeRoom.cs
Normal file
226
osu.Game/Screens/OnlinePlay/Lounge/DrawableLoungeRoom.cs
Normal file
@ -0,0 +1,226 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Audio;
|
||||||
|
using osu.Framework.Audio.Sample;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Extensions;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Cursor;
|
||||||
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Framework.Graphics.UserInterface;
|
||||||
|
using osu.Framework.Input.Bindings;
|
||||||
|
using osu.Framework.Input.Events;
|
||||||
|
using osu.Game.Graphics.UserInterface;
|
||||||
|
using osu.Game.Graphics.UserInterfaceV2;
|
||||||
|
using osu.Game.Input.Bindings;
|
||||||
|
using osu.Game.Online.Rooms;
|
||||||
|
using osu.Game.Screens.OnlinePlay.Components;
|
||||||
|
using osu.Game.Screens.OnlinePlay.Lounge.Components;
|
||||||
|
using osuTK;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
|
||||||
|
namespace osu.Game.Screens.OnlinePlay.Lounge
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A <see cref="DrawableRoom"/> with lounge-specific interactions such as selection and hover sounds.
|
||||||
|
/// </summary>
|
||||||
|
public class DrawableLoungeRoom : DrawableRoom, IFilterable, IHasContextMenu, IHasPopover, IKeyBindingHandler<GlobalAction>
|
||||||
|
{
|
||||||
|
private const float transition_duration = 60;
|
||||||
|
private const float selection_border_width = 4;
|
||||||
|
|
||||||
|
[Resolved(canBeNull: true)]
|
||||||
|
private LoungeSubScreen lounge { get; set; }
|
||||||
|
|
||||||
|
[Resolved(canBeNull: true)]
|
||||||
|
private Bindable<Room> selectedRoom { get; set; }
|
||||||
|
|
||||||
|
private Sample sampleSelect;
|
||||||
|
private Sample sampleJoin;
|
||||||
|
private Drawable selectionBox;
|
||||||
|
|
||||||
|
public DrawableLoungeRoom(Room room)
|
||||||
|
: base(room)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(AudioManager audio)
|
||||||
|
{
|
||||||
|
sampleSelect = audio.Samples.Get($@"UI/{HoverSampleSet.Default.GetDescription()}-select");
|
||||||
|
sampleJoin = audio.Samples.Get($@"UI/{HoverSampleSet.Submit.GetDescription()}-select");
|
||||||
|
|
||||||
|
AddRangeInternal(new Drawable[]
|
||||||
|
{
|
||||||
|
new StatusColouredContainer(transition_duration)
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Child = selectionBox = new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Alpha = 0,
|
||||||
|
Masking = true,
|
||||||
|
CornerRadius = CORNER_RADIUS,
|
||||||
|
BorderThickness = selection_border_width,
|
||||||
|
BorderColour = Color4.White,
|
||||||
|
Child = new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Alpha = 0,
|
||||||
|
AlwaysPresent = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new HoverSounds()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
|
if (matchingFilter)
|
||||||
|
this.FadeInFromZero(transition_duration);
|
||||||
|
else
|
||||||
|
Alpha = 0;
|
||||||
|
|
||||||
|
selectedRoom.BindValueChanged(updateSelectedRoom, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateSelectedRoom(ValueChangedEvent<Room> selected)
|
||||||
|
{
|
||||||
|
if (selected.NewValue == Room)
|
||||||
|
selectionBox.FadeIn(transition_duration);
|
||||||
|
else
|
||||||
|
selectionBox.FadeOut(transition_duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool FilteringActive { get; set; }
|
||||||
|
|
||||||
|
public IEnumerable<string> FilterTerms => new[] { Room.Name.Value };
|
||||||
|
|
||||||
|
private bool matchingFilter;
|
||||||
|
|
||||||
|
public bool MatchingFilter
|
||||||
|
{
|
||||||
|
get => matchingFilter;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
matchingFilter = value;
|
||||||
|
|
||||||
|
if (!IsLoaded)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (matchingFilter)
|
||||||
|
this.FadeIn(200);
|
||||||
|
else
|
||||||
|
Hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Popover GetPopover() => new PasswordEntryPopover(Room) { JoinRequested = lounge.Join };
|
||||||
|
|
||||||
|
public MenuItem[] ContextMenuItems => new MenuItem[]
|
||||||
|
{
|
||||||
|
new OsuMenuItem("Create copy", MenuItemType.Standard, () =>
|
||||||
|
{
|
||||||
|
lounge?.Open(Room.DeepClone());
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
public bool OnPressed(GlobalAction action)
|
||||||
|
{
|
||||||
|
if (selectedRoom.Value != Room)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
switch (action)
|
||||||
|
{
|
||||||
|
case GlobalAction.Select:
|
||||||
|
TriggerClick();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnReleased(GlobalAction action)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool ShouldBeConsideredForInput(Drawable child) => selectedRoom.Value == Room || child is HoverSounds;
|
||||||
|
|
||||||
|
protected override bool OnClick(ClickEvent e)
|
||||||
|
{
|
||||||
|
if (Room != selectedRoom.Value)
|
||||||
|
{
|
||||||
|
sampleSelect?.Play();
|
||||||
|
selectedRoom.Value = Room;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Room.HasPassword.Value)
|
||||||
|
{
|
||||||
|
sampleJoin?.Play();
|
||||||
|
this.ShowPopover();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
sampleJoin?.Play();
|
||||||
|
lounge?.Join(Room, null);
|
||||||
|
|
||||||
|
return base.OnClick(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PasswordEntryPopover : OsuPopover
|
||||||
|
{
|
||||||
|
private readonly Room room;
|
||||||
|
|
||||||
|
public Action<Room, string> JoinRequested;
|
||||||
|
|
||||||
|
public PasswordEntryPopover(Room room)
|
||||||
|
{
|
||||||
|
this.room = room;
|
||||||
|
}
|
||||||
|
|
||||||
|
private OsuPasswordTextBox passwordTextbox;
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
Child = new FillFlowContainer
|
||||||
|
{
|
||||||
|
Margin = new MarginPadding(10),
|
||||||
|
Spacing = new Vector2(5),
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
Direction = FillDirection.Horizontal,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
passwordTextbox = new OsuPasswordTextBox
|
||||||
|
{
|
||||||
|
Width = 200,
|
||||||
|
},
|
||||||
|
new TriangleButton
|
||||||
|
{
|
||||||
|
Width = 80,
|
||||||
|
Text = "Join Room",
|
||||||
|
Action = () => JoinRequested?.Invoke(room, passwordTextbox.Text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
|
Schedule(() => GetContainingInputManager().ChangeFocus(passwordTextbox));
|
||||||
|
passwordTextbox.OnCommit += (_, __) => JoinRequested?.Invoke(room, passwordTextbox.Text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -76,6 +76,8 @@ namespace osu.Game.Screens.OnlinePlay.Lounge
|
|||||||
[BackgroundDependencyLoader(true)]
|
[BackgroundDependencyLoader(true)]
|
||||||
private void load([CanBeNull] IdleTracker idleTracker)
|
private void load([CanBeNull] IdleTracker idleTracker)
|
||||||
{
|
{
|
||||||
|
const float controls_area_height = 25f;
|
||||||
|
|
||||||
if (idleTracker != null)
|
if (idleTracker != null)
|
||||||
isIdle.BindTo(idleTracker.IsIdle);
|
isIdle.BindTo(idleTracker.IsIdle);
|
||||||
|
|
||||||
@ -84,29 +86,40 @@ namespace osu.Game.Screens.OnlinePlay.Lounge
|
|||||||
InternalChildren = new Drawable[]
|
InternalChildren = new Drawable[]
|
||||||
{
|
{
|
||||||
ListingPollingComponent = CreatePollingComponent().With(c => c.Filter.BindTarget = filter),
|
ListingPollingComponent = CreatePollingComponent().With(c => c.Filter.BindTarget = filter),
|
||||||
loadingLayer = new LoadingLayer(true),
|
|
||||||
new Container
|
new Container
|
||||||
{
|
{
|
||||||
|
Name = @"Rooms area",
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Padding = new MarginPadding
|
Padding = new MarginPadding
|
||||||
{
|
{
|
||||||
Left = WaveOverlayContainer.WIDTH_PADDING,
|
Horizontal = WaveOverlayContainer.WIDTH_PADDING,
|
||||||
Right = WaveOverlayContainer.WIDTH_PADDING,
|
Top = Header.HEIGHT + controls_area_height + 20,
|
||||||
},
|
},
|
||||||
Child = new GridContainer
|
Child = scrollContainer = new OsuScrollContainer
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
RowDimensions = new[]
|
ScrollbarOverlapsContent = false,
|
||||||
|
Child = roomsContainer = new RoomsContainer
|
||||||
{
|
{
|
||||||
new Dimension(GridSizeMode.Absolute, Header.HEIGHT),
|
Filter = { BindTarget = filter }
|
||||||
new Dimension(GridSizeMode.Absolute, 25),
|
}
|
||||||
new Dimension(GridSizeMode.Absolute, 20)
|
|
||||||
},
|
},
|
||||||
Content = new[]
|
},
|
||||||
|
loadingLayer = new LoadingLayer(true),
|
||||||
|
new FillFlowContainer
|
||||||
{
|
{
|
||||||
new Drawable[]
|
Name = @"Header area flow",
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
|
Padding = new MarginPadding { Horizontal = WaveOverlayContainer.WIDTH_PADDING },
|
||||||
|
Direction = FillDirection.Vertical,
|
||||||
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
searchTextBox = new LoungeSearchTextBox
|
new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
Height = Header.HEIGHT,
|
||||||
|
Child = searchTextBox = new LoungeSearchTextBox
|
||||||
{
|
{
|
||||||
Anchor = Anchor.CentreRight,
|
Anchor = Anchor.CentreRight,
|
||||||
Origin = Anchor.CentreRight,
|
Origin = Anchor.CentreRight,
|
||||||
@ -114,12 +127,10 @@ namespace osu.Game.Screens.OnlinePlay.Lounge
|
|||||||
Width = 0.6f,
|
Width = 0.6f,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
new Drawable[]
|
|
||||||
{
|
|
||||||
new Container
|
new Container
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.X,
|
||||||
Depth = float.MinValue, // Contained filters should appear over the top of rooms.
|
Height = controls_area_height,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
Buttons.WithChild(CreateNewRoomButton().With(d =>
|
Buttons.WithChild(CreateNewRoomButton().With(d =>
|
||||||
@ -145,28 +156,6 @@ namespace osu.Game.Screens.OnlinePlay.Lounge
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
null,
|
|
||||||
new Drawable[]
|
|
||||||
{
|
|
||||||
new Container
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
scrollContainer = new OsuScrollContainer
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
ScrollbarOverlapsContent = false,
|
|
||||||
Child = roomsContainer = new RoomsContainer
|
|
||||||
{
|
|
||||||
Filter = { BindTarget = filter }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,48 +0,0 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using osu.Framework.Allocation;
|
|
||||||
using osu.Framework.Extensions.Color4Extensions;
|
|
||||||
using osu.Framework.Graphics;
|
|
||||||
using osu.Framework.Graphics.Containers;
|
|
||||||
using osu.Framework.Graphics.Shapes;
|
|
||||||
using osu.Game.Graphics;
|
|
||||||
using osu.Game.Screens.OnlinePlay.Playlists;
|
|
||||||
using osuTK;
|
|
||||||
|
|
||||||
namespace osu.Game.Screens.OnlinePlay.Match.Components
|
|
||||||
{
|
|
||||||
public class Footer : CompositeDrawable
|
|
||||||
{
|
|
||||||
public const float HEIGHT = 50;
|
|
||||||
|
|
||||||
public Action OnStart;
|
|
||||||
|
|
||||||
private readonly Drawable background;
|
|
||||||
|
|
||||||
public Footer()
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.X;
|
|
||||||
Height = HEIGHT;
|
|
||||||
|
|
||||||
InternalChildren = new[]
|
|
||||||
{
|
|
||||||
background = new Box { RelativeSizeAxes = Axes.Both },
|
|
||||||
new PlaylistsReadyButton
|
|
||||||
{
|
|
||||||
Anchor = Anchor.Centre,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
Size = new Vector2(600, 50),
|
|
||||||
Action = () => OnStart?.Invoke()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
|
||||||
private void load(OsuColour colours)
|
|
||||||
{
|
|
||||||
background.Colour = Color4Extensions.FromHex(@"28242d");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,79 +0,0 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
|
||||||
|
|
||||||
using osu.Framework.Allocation;
|
|
||||||
using osu.Framework.Graphics;
|
|
||||||
using osu.Framework.Graphics.Containers;
|
|
||||||
using osu.Game.Graphics;
|
|
||||||
using osu.Game.Graphics.Containers;
|
|
||||||
using osu.Game.Graphics.Sprites;
|
|
||||||
using osu.Game.Users.Drawables;
|
|
||||||
using osuTK;
|
|
||||||
|
|
||||||
namespace osu.Game.Screens.OnlinePlay.Match.Components
|
|
||||||
{
|
|
||||||
public class Header : OnlinePlayComposite
|
|
||||||
{
|
|
||||||
public const float HEIGHT = 50;
|
|
||||||
|
|
||||||
private UpdateableAvatar avatar;
|
|
||||||
private LinkFlowContainer hostText;
|
|
||||||
|
|
||||||
public Header()
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.X;
|
|
||||||
Height = HEIGHT;
|
|
||||||
}
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
|
||||||
private void load(OsuColour colours)
|
|
||||||
{
|
|
||||||
InternalChild = new FillFlowContainer
|
|
||||||
{
|
|
||||||
AutoSizeAxes = Axes.Both,
|
|
||||||
Direction = FillDirection.Horizontal,
|
|
||||||
Spacing = new Vector2(10, 0),
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
avatar = new UpdateableAvatar
|
|
||||||
{
|
|
||||||
Size = new Vector2(50),
|
|
||||||
Masking = true,
|
|
||||||
CornerRadius = 10,
|
|
||||||
},
|
|
||||||
new FillFlowContainer
|
|
||||||
{
|
|
||||||
AutoSizeAxes = Axes.Both,
|
|
||||||
Direction = FillDirection.Vertical,
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
new OsuSpriteText
|
|
||||||
{
|
|
||||||
Font = OsuFont.GetFont(size: 30),
|
|
||||||
Current = { BindTarget = RoomName }
|
|
||||||
},
|
|
||||||
hostText = new LinkFlowContainer(s => s.Font = OsuFont.GetFont(size: 20))
|
|
||||||
{
|
|
||||||
AutoSizeAxes = Axes.Both,
|
|
||||||
Direction = FillDirection.Horizontal,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Host.BindValueChanged(host =>
|
|
||||||
{
|
|
||||||
avatar.User = host.NewValue;
|
|
||||||
|
|
||||||
hostText.Clear();
|
|
||||||
|
|
||||||
if (host.NewValue != null)
|
|
||||||
{
|
|
||||||
hostText.AddText("hosted by ");
|
|
||||||
hostText.AddUserLink(host.NewValue, s => s.Font = s.Font.With(weight: FontWeight.SemiBold));
|
|
||||||
}
|
|
||||||
}, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -14,10 +14,10 @@ using osuTK.Graphics;
|
|||||||
|
|
||||||
namespace osu.Game.Screens.OnlinePlay.Match.Components
|
namespace osu.Game.Screens.OnlinePlay.Match.Components
|
||||||
{
|
{
|
||||||
public abstract class MatchSettingsOverlay : FocusedOverlayContainer, IKeyBindingHandler<GlobalAction>
|
public abstract class RoomSettingsOverlay : FocusedOverlayContainer, IKeyBindingHandler<GlobalAction>
|
||||||
{
|
{
|
||||||
protected const float TRANSITION_DURATION = 350;
|
protected const float TRANSITION_DURATION = 350;
|
||||||
protected const float FIELD_PADDING = 45;
|
protected const float FIELD_PADDING = 25;
|
||||||
|
|
||||||
protected OnlinePlayComposite Settings { get; set; }
|
protected OnlinePlayComposite Settings { get; set; }
|
||||||
|
|
||||||
@ -27,11 +27,16 @@ namespace osu.Game.Screens.OnlinePlay.Match.Components
|
|||||||
|
|
||||||
protected abstract bool IsLoading { get; }
|
protected abstract bool IsLoading { get; }
|
||||||
|
|
||||||
|
protected RoomSettingsOverlay()
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both;
|
||||||
|
Masking = true;
|
||||||
|
CornerRadius = 10;
|
||||||
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
{
|
{
|
||||||
Masking = true;
|
|
||||||
|
|
||||||
Add(Settings = CreateSettings());
|
Add(Settings = CreateSettings());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,12 +48,14 @@ namespace osu.Game.Screens.OnlinePlay.Match.Components
|
|||||||
{
|
{
|
||||||
base.PopIn();
|
base.PopIn();
|
||||||
Settings.MoveToY(0, TRANSITION_DURATION, Easing.OutQuint);
|
Settings.MoveToY(0, TRANSITION_DURATION, Easing.OutQuint);
|
||||||
|
Settings.FadeIn(TRANSITION_DURATION / 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void PopOut()
|
protected override void PopOut()
|
||||||
{
|
{
|
||||||
base.PopOut();
|
base.PopOut();
|
||||||
Settings.MoveToY(-1, TRANSITION_DURATION, Easing.InSine);
|
Settings.MoveToY(-1, TRANSITION_DURATION, Easing.InSine);
|
||||||
|
Settings.Delay(TRANSITION_DURATION / 2).FadeOut(TRANSITION_DURATION / 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool OnPressed(GlobalAction action)
|
public bool OnPressed(GlobalAction action)
|
64
osu.Game/Screens/OnlinePlay/Match/DrawableMatchRoom.cs
Normal file
64
osu.Game/Screens/OnlinePlay/Match/DrawableMatchRoom.cs
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using JetBrains.Annotations;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Game.Online.API;
|
||||||
|
using osu.Game.Online.Rooms;
|
||||||
|
using osu.Game.Screens.OnlinePlay.Lounge.Components;
|
||||||
|
using osu.Game.Screens.OnlinePlay.Match.Components;
|
||||||
|
using osu.Game.Users;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Screens.OnlinePlay.Match
|
||||||
|
{
|
||||||
|
public class DrawableMatchRoom : DrawableRoom
|
||||||
|
{
|
||||||
|
public Action OnEdit;
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private IAPIProvider api { get; set; }
|
||||||
|
|
||||||
|
private readonly IBindable<User> host = new Bindable<User>();
|
||||||
|
private readonly bool allowEdit;
|
||||||
|
|
||||||
|
[CanBeNull]
|
||||||
|
private Drawable editButton;
|
||||||
|
|
||||||
|
public DrawableMatchRoom(Room room, bool allowEdit = true)
|
||||||
|
: base(room)
|
||||||
|
{
|
||||||
|
this.allowEdit = allowEdit;
|
||||||
|
|
||||||
|
host.BindTo(room.Host);
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
if (allowEdit)
|
||||||
|
{
|
||||||
|
ButtonsContainer.Add(editButton = new PurpleTriangleButton
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Y,
|
||||||
|
Size = new Vector2(100, 1),
|
||||||
|
Text = "Edit",
|
||||||
|
Action = () => OnEdit?.Invoke()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
|
if (editButton != null)
|
||||||
|
host.BindValueChanged(h => editButton.Alpha = h.NewValue?.Equals(api.LocalUser.Value) == true ? 1 : 0, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Drawable CreateBackground() => new RoomBackgroundSprite();
|
||||||
|
}
|
||||||
|
}
|
33
osu.Game/Screens/OnlinePlay/Match/RoomBackgroundSprite.cs
Normal file
33
osu.Game/Screens/OnlinePlay/Match/RoomBackgroundSprite.cs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Game.Beatmaps.Drawables;
|
||||||
|
|
||||||
|
namespace osu.Game.Screens.OnlinePlay.Match
|
||||||
|
{
|
||||||
|
public class RoomBackgroundSprite : RoomSubScreenComposite
|
||||||
|
{
|
||||||
|
protected readonly BeatmapSetCoverType BeatmapSetCoverType;
|
||||||
|
private UpdateableBeatmapBackgroundSprite sprite;
|
||||||
|
|
||||||
|
public RoomBackgroundSprite(BeatmapSetCoverType beatmapSetCoverType = BeatmapSetCoverType.Cover)
|
||||||
|
{
|
||||||
|
BeatmapSetCoverType = beatmapSetCoverType;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
InternalChild = sprite = new UpdateableBeatmapBackgroundSprite(BeatmapSetCoverType) { RelativeSizeAxes = Axes.Both };
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
|
SelectedItem.BindValueChanged(item => sprite.Beatmap.Value = item.NewValue?.Beatmap.Value, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -31,8 +31,6 @@ namespace osu.Game.Screens.OnlinePlay.Match
|
|||||||
|
|
||||||
public override bool DisallowExternalBeatmapRulesetChanges => true;
|
public override bool DisallowExternalBeatmapRulesetChanges => true;
|
||||||
|
|
||||||
private readonly ModSelectOverlay userModsSelectOverlay;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A container that provides controls for selection of user mods.
|
/// A container that provides controls for selection of user mods.
|
||||||
/// This will be shown/hidden automatically when applicable.
|
/// This will be shown/hidden automatically when applicable.
|
||||||
@ -46,6 +44,8 @@ namespace osu.Game.Screens.OnlinePlay.Match
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
protected readonly Bindable<IReadOnlyList<Mod>> UserMods = new Bindable<IReadOnlyList<Mod>>(Array.Empty<Mod>());
|
protected readonly Bindable<IReadOnlyList<Mod>> UserMods = new Bindable<IReadOnlyList<Mod>>(Array.Empty<Mod>());
|
||||||
|
|
||||||
|
protected readonly IBindable<long?> RoomId = new Bindable<long?>();
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private MusicController music { get; set; }
|
private MusicController music { get; set; }
|
||||||
|
|
||||||
@ -58,55 +58,184 @@ namespace osu.Game.Screens.OnlinePlay.Match
|
|||||||
private IBindable<WeakReference<BeatmapSetInfo>> managerUpdated;
|
private IBindable<WeakReference<BeatmapSetInfo>> managerUpdated;
|
||||||
|
|
||||||
[Cached]
|
[Cached]
|
||||||
protected OnlinePlayBeatmapAvailabilityTracker BeatmapAvailabilityTracker { get; }
|
protected OnlinePlayBeatmapAvailabilityTracker BeatmapAvailabilityTracker { get; private set; }
|
||||||
|
|
||||||
protected IBindable<BeatmapAvailability> BeatmapAvailability => BeatmapAvailabilityTracker.Availability;
|
protected IBindable<BeatmapAvailability> BeatmapAvailability => BeatmapAvailabilityTracker.Availability;
|
||||||
|
|
||||||
protected RoomSubScreen()
|
public readonly Room Room;
|
||||||
|
private readonly bool allowEdit;
|
||||||
|
|
||||||
|
private ModSelectOverlay userModsSelectOverlay;
|
||||||
|
private RoomSettingsOverlay settingsOverlay;
|
||||||
|
private Drawable mainContent;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new <see cref="RoomSubScreen"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="room">The <see cref="Room"/>.</param>
|
||||||
|
/// <param name="allowEdit">Whether to allow editing room settings post-creation.</param>
|
||||||
|
protected RoomSubScreen(Room room, bool allowEdit = true)
|
||||||
{
|
{
|
||||||
|
Room = room;
|
||||||
|
this.allowEdit = allowEdit;
|
||||||
|
|
||||||
Padding = new MarginPadding { Top = Header.HEIGHT };
|
Padding = new MarginPadding { Top = Header.HEIGHT };
|
||||||
|
|
||||||
AddRangeInternal(new Drawable[]
|
|
||||||
{
|
|
||||||
new Box
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Colour = Color4Extensions.FromHex(@"3e3a44") // This is super temporary.
|
|
||||||
},
|
|
||||||
BeatmapAvailabilityTracker = new OnlinePlayBeatmapAvailabilityTracker
|
BeatmapAvailabilityTracker = new OnlinePlayBeatmapAvailabilityTracker
|
||||||
{
|
{
|
||||||
SelectedItem = { BindTarget = SelectedItem }
|
SelectedItem = { BindTarget = SelectedItem }
|
||||||
|
};
|
||||||
|
|
||||||
|
RoomId.BindTo(room.RoomID);
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(AudioManager audio)
|
||||||
|
{
|
||||||
|
sampleStart = audio.Samples.Get(@"SongSelect/confirm-selection");
|
||||||
|
|
||||||
|
InternalChildren = new Drawable[]
|
||||||
|
{
|
||||||
|
BeatmapAvailabilityTracker,
|
||||||
|
new GridContainer
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
RowDimensions = new[]
|
||||||
|
{
|
||||||
|
new Dimension(),
|
||||||
|
new Dimension(GridSizeMode.Absolute, 50)
|
||||||
|
},
|
||||||
|
Content = new[]
|
||||||
|
{
|
||||||
|
// Padded main content (drawable room + main content)
|
||||||
|
new Drawable[]
|
||||||
|
{
|
||||||
|
new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Padding = new MarginPadding
|
||||||
|
{
|
||||||
|
Horizontal = WaveOverlayContainer.WIDTH_PADDING,
|
||||||
|
Bottom = 30
|
||||||
|
},
|
||||||
|
Children = new[]
|
||||||
|
{
|
||||||
|
mainContent = new GridContainer
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
RowDimensions = new[]
|
||||||
|
{
|
||||||
|
new Dimension(GridSizeMode.AutoSize),
|
||||||
|
new Dimension(GridSizeMode.Absolute, 10)
|
||||||
|
},
|
||||||
|
Content = new[]
|
||||||
|
{
|
||||||
|
new Drawable[]
|
||||||
|
{
|
||||||
|
new DrawableMatchRoom(Room, allowEdit)
|
||||||
|
{
|
||||||
|
OnEdit = () => settingsOverlay.Show()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
null,
|
||||||
|
new Drawable[]
|
||||||
|
{
|
||||||
|
new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Children = new[]
|
||||||
|
{
|
||||||
|
new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Masking = true,
|
||||||
|
CornerRadius = 10,
|
||||||
|
Child = new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Colour = Color4Extensions.FromHex(@"3e3a44") // Temporary.
|
||||||
|
},
|
||||||
|
},
|
||||||
|
new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Padding = new MarginPadding(20),
|
||||||
|
Child = CreateMainContent(),
|
||||||
},
|
},
|
||||||
new Container
|
new Container
|
||||||
{
|
{
|
||||||
Anchor = Anchor.BottomLeft,
|
Anchor = Anchor.BottomLeft,
|
||||||
Origin = Anchor.BottomLeft,
|
Origin = Anchor.BottomLeft,
|
||||||
Depth = float.MinValue,
|
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
AutoSizeAxes = Axes.Y,
|
AutoSizeAxes = Axes.Y,
|
||||||
Padding = new MarginPadding { Horizontal = HORIZONTAL_OVERFLOW_PADDING },
|
|
||||||
Child = userModsSelectOverlay = new UserModSelectOverlay
|
Child = userModsSelectOverlay = new UserModSelectOverlay
|
||||||
{
|
{
|
||||||
SelectedMods = { BindTarget = UserMods },
|
SelectedMods = { BindTarget = UserMods },
|
||||||
IsValidMod = _ => false
|
IsValidMod = _ => false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
protected override void ClearInternal(bool disposeChildren = true) =>
|
}
|
||||||
throw new InvalidOperationException($"{nameof(RoomSubScreen)}'s children should not be cleared as it will remove required components");
|
}
|
||||||
|
},
|
||||||
[BackgroundDependencyLoader]
|
new Container
|
||||||
private void load(AudioManager audio)
|
|
||||||
{
|
{
|
||||||
sampleStart = audio.Samples.Get(@"SongSelect/confirm-selection");
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
// Resolves 1px masking errors between the settings overlay and the room panel.
|
||||||
|
Padding = new MarginPadding(-1),
|
||||||
|
Child = settingsOverlay = CreateRoomSettingsOverlay()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// Footer
|
||||||
|
new Drawable[]
|
||||||
|
{
|
||||||
|
new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Colour = Color4Extensions.FromHex(@"28242d") // Temporary.
|
||||||
|
},
|
||||||
|
new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Padding = new MarginPadding(5),
|
||||||
|
Child = CreateFooter()
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
|
|
||||||
|
RoomId.BindValueChanged(id =>
|
||||||
|
{
|
||||||
|
if (id.NewValue == null)
|
||||||
|
{
|
||||||
|
// A new room is being created.
|
||||||
|
// The main content should be hidden until the settings overlay is hidden, signaling the room is ready to be displayed.
|
||||||
|
mainContent.Hide();
|
||||||
|
settingsOverlay.Show();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mainContent.Show();
|
||||||
|
settingsOverlay.Hide();
|
||||||
|
}
|
||||||
|
}, true);
|
||||||
|
|
||||||
SelectedItem.BindValueChanged(_ => Scheduler.AddOnce(selectedItemChanged));
|
SelectedItem.BindValueChanged(_ => Scheduler.AddOnce(selectedItemChanged));
|
||||||
|
|
||||||
managerUpdated = beatmapManager.ItemUpdated.GetBoundCopy();
|
managerUpdated = beatmapManager.ItemUpdated.GetBoundCopy();
|
||||||
@ -117,12 +246,25 @@ namespace osu.Game.Screens.OnlinePlay.Match
|
|||||||
|
|
||||||
public override bool OnBackButton()
|
public override bool OnBackButton()
|
||||||
{
|
{
|
||||||
|
if (Room.RoomID.Value == null)
|
||||||
|
{
|
||||||
|
// room has not been created yet; exit immediately.
|
||||||
|
settingsOverlay.Hide();
|
||||||
|
return base.OnBackButton();
|
||||||
|
}
|
||||||
|
|
||||||
if (userModsSelectOverlay.State.Value == Visibility.Visible)
|
if (userModsSelectOverlay.State.Value == Visibility.Visible)
|
||||||
{
|
{
|
||||||
userModsSelectOverlay.Hide();
|
userModsSelectOverlay.Hide();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (settingsOverlay.State.Value == Visibility.Visible)
|
||||||
|
{
|
||||||
|
settingsOverlay.Hide();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return base.OnBackButton();
|
return base.OnBackButton();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -257,6 +399,21 @@ namespace osu.Game.Screens.OnlinePlay.Match
|
|||||||
track.Looping = false;
|
track.Looping = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates the main centred content.
|
||||||
|
/// </summary>
|
||||||
|
protected abstract Drawable CreateMainContent();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates the footer content.
|
||||||
|
/// </summary>
|
||||||
|
protected abstract Drawable CreateFooter();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates the room settings overlay.
|
||||||
|
/// </summary>
|
||||||
|
protected abstract RoomSettingsOverlay CreateRoomSettingsOverlay();
|
||||||
|
|
||||||
private class UserModSelectOverlay : LocalPlayerModSelectOverlay
|
private class UserModSelectOverlay : LocalPlayerModSelectOverlay
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ using osu.Framework.Graphics.UserInterface;
|
|||||||
using osu.Framework.Screens;
|
using osu.Framework.Screens;
|
||||||
using osu.Game.Online.API;
|
using osu.Game.Online.API;
|
||||||
using osu.Game.Screens.OnlinePlay.Match.Components;
|
using osu.Game.Screens.OnlinePlay.Match.Components;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match
|
namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match
|
||||||
{
|
{
|
||||||
@ -35,6 +36,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match
|
|||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
AutoSizeAxes = Axes.Y,
|
AutoSizeAxes = Axes.Y,
|
||||||
Direction = FillDirection.Vertical,
|
Direction = FillDirection.Vertical,
|
||||||
|
Spacing = new Vector2(5),
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
beatmapPanelContainer = new Container
|
beatmapPanelContainer = new Container
|
||||||
|
@ -2,18 +2,13 @@
|
|||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using osu.Framework.Allocation;
|
|
||||||
using osu.Framework.Extensions.Color4Extensions;
|
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Shapes;
|
|
||||||
using osu.Game.Graphics;
|
|
||||||
|
|
||||||
namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match
|
namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match
|
||||||
{
|
{
|
||||||
public class MultiplayerMatchFooter : CompositeDrawable
|
public class MultiplayerMatchFooter : CompositeDrawable
|
||||||
{
|
{
|
||||||
public const float HEIGHT = 50;
|
|
||||||
private const float ready_button_width = 600;
|
private const float ready_button_width = 600;
|
||||||
private const float spectate_button_width = 200;
|
private const float spectate_button_width = 200;
|
||||||
|
|
||||||
@ -27,19 +22,14 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match
|
|||||||
set => spectateButton.OnSpectateClick = value;
|
set => spectateButton.OnSpectateClick = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly Drawable background;
|
|
||||||
private readonly MultiplayerReadyButton readyButton;
|
private readonly MultiplayerReadyButton readyButton;
|
||||||
private readonly MultiplayerSpectateButton spectateButton;
|
private readonly MultiplayerSpectateButton spectateButton;
|
||||||
|
|
||||||
public MultiplayerMatchFooter()
|
public MultiplayerMatchFooter()
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X;
|
RelativeSizeAxes = Axes.Both;
|
||||||
Height = HEIGHT;
|
|
||||||
|
|
||||||
InternalChildren = new[]
|
InternalChild = new GridContainer
|
||||||
{
|
|
||||||
background = new Box { RelativeSizeAxes = Axes.Both },
|
|
||||||
new GridContainer
|
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Content = new[]
|
Content = new[]
|
||||||
@ -63,18 +53,11 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match
|
|||||||
{
|
{
|
||||||
new Dimension(),
|
new Dimension(),
|
||||||
new Dimension(maxSize: spectate_button_width),
|
new Dimension(maxSize: spectate_button_width),
|
||||||
new Dimension(GridSizeMode.Absolute, 10),
|
new Dimension(GridSizeMode.Absolute, 5),
|
||||||
new Dimension(maxSize: ready_button_width),
|
new Dimension(maxSize: ready_button_width),
|
||||||
new Dimension()
|
new Dimension()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
|
||||||
private void load(OsuColour colours)
|
|
||||||
{
|
|
||||||
background.Colour = Color4Extensions.FromHex(@"28242d");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,106 +0,0 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using osu.Framework.Allocation;
|
|
||||||
using osu.Framework.Graphics;
|
|
||||||
using osu.Framework.Graphics.Containers;
|
|
||||||
using osu.Framework.Graphics.UserInterface;
|
|
||||||
using osu.Game.Graphics;
|
|
||||||
using osu.Game.Graphics.Containers;
|
|
||||||
using osu.Game.Graphics.Sprites;
|
|
||||||
using osu.Game.Online.API;
|
|
||||||
using osu.Game.Screens.OnlinePlay.Match.Components;
|
|
||||||
using osu.Game.Users.Drawables;
|
|
||||||
using osuTK;
|
|
||||||
using FontWeight = osu.Game.Graphics.FontWeight;
|
|
||||||
using OsuColour = osu.Game.Graphics.OsuColour;
|
|
||||||
using OsuFont = osu.Game.Graphics.OsuFont;
|
|
||||||
|
|
||||||
namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match
|
|
||||||
{
|
|
||||||
public class MultiplayerMatchHeader : OnlinePlayComposite
|
|
||||||
{
|
|
||||||
public const float HEIGHT = 50;
|
|
||||||
|
|
||||||
public Action OpenSettings;
|
|
||||||
|
|
||||||
private UpdateableAvatar avatar;
|
|
||||||
private LinkFlowContainer hostText;
|
|
||||||
private Button openSettingsButton;
|
|
||||||
|
|
||||||
[Resolved]
|
|
||||||
private IAPIProvider api { get; set; }
|
|
||||||
|
|
||||||
public MultiplayerMatchHeader()
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.X;
|
|
||||||
Height = HEIGHT;
|
|
||||||
}
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
|
||||||
private void load(OsuColour colours)
|
|
||||||
{
|
|
||||||
InternalChildren = new Drawable[]
|
|
||||||
{
|
|
||||||
new FillFlowContainer
|
|
||||||
{
|
|
||||||
AutoSizeAxes = Axes.Both,
|
|
||||||
Direction = FillDirection.Horizontal,
|
|
||||||
Spacing = new Vector2(10, 0),
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
avatar = new UpdateableAvatar
|
|
||||||
{
|
|
||||||
Size = new Vector2(50),
|
|
||||||
Masking = true,
|
|
||||||
CornerRadius = 10,
|
|
||||||
},
|
|
||||||
new FillFlowContainer
|
|
||||||
{
|
|
||||||
AutoSizeAxes = Axes.Both,
|
|
||||||
Direction = FillDirection.Vertical,
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
new OsuSpriteText
|
|
||||||
{
|
|
||||||
Font = OsuFont.GetFont(size: 30),
|
|
||||||
Current = { BindTarget = RoomName }
|
|
||||||
},
|
|
||||||
hostText = new LinkFlowContainer(s => s.Font = OsuFont.GetFont(size: 20))
|
|
||||||
{
|
|
||||||
AutoSizeAxes = Axes.Both,
|
|
||||||
Direction = FillDirection.Horizontal,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
openSettingsButton = new PurpleTriangleButton
|
|
||||||
{
|
|
||||||
Anchor = Anchor.CentreRight,
|
|
||||||
Origin = Anchor.CentreRight,
|
|
||||||
Size = new Vector2(150, HEIGHT),
|
|
||||||
Text = "Open settings",
|
|
||||||
Action = () => OpenSettings?.Invoke(),
|
|
||||||
Alpha = 0
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Host.BindValueChanged(host =>
|
|
||||||
{
|
|
||||||
avatar.User = host.NewValue;
|
|
||||||
|
|
||||||
hostText.Clear();
|
|
||||||
|
|
||||||
if (host.NewValue != null)
|
|
||||||
{
|
|
||||||
hostText.AddText("hosted by ");
|
|
||||||
hostText.AddUserLink(host.NewValue, s => s.Font = s.Font.With(weight: FontWeight.SemiBold));
|
|
||||||
}
|
|
||||||
|
|
||||||
openSettingsButton.Alpha = host.NewValue?.Equals(api.LocalUser.Value) == true ? 1 : 0;
|
|
||||||
}, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -26,7 +26,7 @@ using osuTK;
|
|||||||
|
|
||||||
namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match
|
namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match
|
||||||
{
|
{
|
||||||
public class MultiplayerMatchSettingsOverlay : MatchSettingsOverlay
|
public class MultiplayerMatchSettingsOverlay : RoomSettingsOverlay
|
||||||
{
|
{
|
||||||
private MatchSettings settings;
|
private MatchSettings settings;
|
||||||
|
|
||||||
@ -150,6 +150,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match
|
|||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
TabbableContentContainer = this,
|
TabbableContentContainer = this,
|
||||||
|
LengthLimit = 100,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
new Section("Room visibility")
|
new Section("Room visibility")
|
||||||
@ -207,6 +208,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match
|
|||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
TabbableContentContainer = this,
|
TabbableContentContainer = this,
|
||||||
|
LengthLimit = 255,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
|
|||||||
protected override Room CreateNewRoom() => new Room
|
protected override Room CreateNewRoom() => new Room
|
||||||
{
|
{
|
||||||
Name = { Value = $"{api.LocalUser}'s awesome room" },
|
Name = { Value = $"{api.LocalUser}'s awesome room" },
|
||||||
Category = { Value = RoomCategory.Realtime },
|
|
||||||
Type = { Value = MatchType.HeadToHead },
|
Type = { Value = MatchType.HeadToHead },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -42,8 +42,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
|
|||||||
|
|
||||||
public override string ShortTitle => "room";
|
public override string ShortTitle => "room";
|
||||||
|
|
||||||
public readonly Room Room;
|
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private MultiplayerClient client { get; set; }
|
private MultiplayerClient client { get; set; }
|
||||||
|
|
||||||
@ -58,54 +56,49 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
|
|||||||
[CanBeNull]
|
[CanBeNull]
|
||||||
private IDisposable readyClickOperation;
|
private IDisposable readyClickOperation;
|
||||||
|
|
||||||
private GridContainer mainContent;
|
|
||||||
private MultiplayerMatchSettingsOverlay settingsOverlay;
|
|
||||||
|
|
||||||
public MultiplayerMatchSubScreen(Room room)
|
public MultiplayerMatchSubScreen(Room room)
|
||||||
|
: base(room)
|
||||||
{
|
{
|
||||||
Room = room;
|
|
||||||
|
|
||||||
Title = room.RoomID.Value == null ? "New room" : room.Name.Value;
|
Title = room.RoomID.Value == null ? "New room" : room.Name.Value;
|
||||||
Activity.Value = new UserActivity.InLobby(room);
|
Activity.Value = new UserActivity.InLobby(room);
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
protected override void LoadComplete()
|
||||||
private void load()
|
|
||||||
{
|
{
|
||||||
AddRangeInternal(new Drawable[]
|
base.LoadComplete();
|
||||||
|
|
||||||
|
SelectedItem.BindTo(client.CurrentMatchPlayingItem);
|
||||||
|
|
||||||
|
BeatmapAvailability.BindValueChanged(updateBeatmapAvailability, true);
|
||||||
|
UserMods.BindValueChanged(onUserModsChanged);
|
||||||
|
|
||||||
|
client.LoadRequested += onLoadRequested;
|
||||||
|
client.RoomUpdated += onRoomUpdated;
|
||||||
|
|
||||||
|
isConnected.BindTo(client.IsConnected);
|
||||||
|
isConnected.BindValueChanged(connected =>
|
||||||
{
|
{
|
||||||
mainContent = new GridContainer
|
if (!connected.NewValue)
|
||||||
|
handleRoomLost();
|
||||||
|
}, true);
|
||||||
|
|
||||||
|
currentRoom.BindValueChanged(room =>
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
if (room.NewValue == null)
|
||||||
Content = new[]
|
|
||||||
{
|
{
|
||||||
new Drawable[]
|
// the room has gone away.
|
||||||
{
|
// this could mean something happened during the join process, or an external connection issue occurred.
|
||||||
new Container
|
// one specific scenario is where the underlying room is created, but the signalr server returns an error during the join process. this triggers a PartRoom operation (see https://github.com/ppy/osu/blob/7654df94f6f37b8382be7dfcb4f674e03bd35427/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerRoomManager.cs#L97)
|
||||||
{
|
handleRoomLost();
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Padding = new MarginPadding
|
|
||||||
{
|
|
||||||
Horizontal = HORIZONTAL_OVERFLOW_PADDING + 55,
|
|
||||||
Vertical = 20
|
|
||||||
},
|
|
||||||
Child = new GridContainer
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
RowDimensions = new[]
|
|
||||||
{
|
|
||||||
new Dimension(GridSizeMode.AutoSize),
|
|
||||||
new Dimension(),
|
|
||||||
},
|
|
||||||
Content = new[]
|
|
||||||
{
|
|
||||||
new Drawable[]
|
|
||||||
{
|
|
||||||
new MultiplayerMatchHeader
|
|
||||||
{
|
|
||||||
OpenSettings = () => settingsOverlay.Show()
|
|
||||||
}
|
}
|
||||||
},
|
}, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Drawable CreateMainContent() => new GridContainer
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Content = new[]
|
||||||
|
{
|
||||||
new Drawable[]
|
new Drawable[]
|
||||||
{
|
{
|
||||||
new Container
|
new Container
|
||||||
@ -148,27 +141,21 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
|
|||||||
// Spacer
|
// Spacer
|
||||||
null,
|
null,
|
||||||
// Main right column
|
// Main right column
|
||||||
new FillFlowContainer
|
new GridContainer
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.Both,
|
||||||
AutoSizeAxes = Axes.Y,
|
Content = new[]
|
||||||
Children = new[]
|
|
||||||
{
|
{
|
||||||
new FillFlowContainer
|
new Drawable[] { new OverlinedHeader("Beatmap") },
|
||||||
|
new Drawable[] { new BeatmapSelectionControl { RelativeSizeAxes = Axes.X } },
|
||||||
|
new[]
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X,
|
|
||||||
AutoSizeAxes = Axes.Y,
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
new OverlinedHeader("Beatmap"),
|
|
||||||
new BeatmapSelectionControl { RelativeSizeAxes = Axes.X }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
UserModsSection = new FillFlowContainer
|
UserModsSection = new FillFlowContainer
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
AutoSizeAxes = Axes.Y,
|
AutoSizeAxes = Axes.Y,
|
||||||
Margin = new MarginPadding { Top = 10 },
|
Margin = new MarginPadding { Top = 10 },
|
||||||
|
Alpha = 0,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new OverlinedHeader("Extra mods"),
|
new OverlinedHeader("Extra mods"),
|
||||||
@ -195,102 +182,37 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
|
|||||||
Scale = new Vector2(0.8f),
|
Scale = new Vector2(0.8f),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
new Drawable[]
|
},
|
||||||
{
|
new Drawable[] { new OverlinedHeader("Chat") { Margin = new MarginPadding { Vertical = 5 }, }, },
|
||||||
new GridContainer
|
new Drawable[] { new MatchChatDisplay { RelativeSizeAxes = Axes.Both } }
|
||||||
{
|
},
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
RowDimensions = new[]
|
RowDimensions = new[]
|
||||||
{
|
{
|
||||||
new Dimension(GridSizeMode.AutoSize)
|
new Dimension(GridSizeMode.AutoSize),
|
||||||
},
|
new Dimension(GridSizeMode.AutoSize),
|
||||||
Content = new[]
|
new Dimension(GridSizeMode.AutoSize),
|
||||||
{
|
new Dimension(GridSizeMode.AutoSize),
|
||||||
new Drawable[] { new OverlinedHeader("Chat") },
|
new Dimension(),
|
||||||
new Drawable[] { new MatchChatDisplay { RelativeSizeAxes = Axes.Both } }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
new Drawable[]
|
},
|
||||||
{
|
};
|
||||||
new MultiplayerMatchFooter
|
|
||||||
|
protected override Drawable CreateFooter() => new MultiplayerMatchFooter
|
||||||
{
|
{
|
||||||
OnReadyClick = onReadyClick,
|
OnReadyClick = onReadyClick,
|
||||||
OnSpectateClick = onSpectateClick
|
OnSpectateClick = onSpectateClick
|
||||||
}
|
};
|
||||||
}
|
|
||||||
},
|
|
||||||
RowDimensions = new[]
|
|
||||||
{
|
|
||||||
new Dimension(),
|
|
||||||
new Dimension(GridSizeMode.AutoSize),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
settingsOverlay = new MultiplayerMatchSettingsOverlay
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
State = { Value = client.Room == null ? Visibility.Visible : Visibility.Hidden }
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (client.Room == null)
|
protected override RoomSettingsOverlay CreateRoomSettingsOverlay() => new MultiplayerMatchSettingsOverlay();
|
||||||
{
|
|
||||||
// A new room is being created.
|
|
||||||
// The main content should be hidden until the settings overlay is hidden, signaling the room is ready to be displayed.
|
|
||||||
mainContent.Hide();
|
|
||||||
|
|
||||||
settingsOverlay.State.BindValueChanged(visibility =>
|
|
||||||
{
|
|
||||||
if (visibility.NewValue == Visibility.Hidden)
|
|
||||||
mainContent.Show();
|
|
||||||
}, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void LoadComplete()
|
|
||||||
{
|
|
||||||
base.LoadComplete();
|
|
||||||
|
|
||||||
SelectedItem.BindTo(client.CurrentMatchPlayingItem);
|
|
||||||
|
|
||||||
BeatmapAvailability.BindValueChanged(updateBeatmapAvailability, true);
|
|
||||||
UserMods.BindValueChanged(onUserModsChanged);
|
|
||||||
|
|
||||||
client.LoadRequested += onLoadRequested;
|
|
||||||
client.RoomUpdated += onRoomUpdated;
|
|
||||||
|
|
||||||
isConnected.BindTo(client.IsConnected);
|
|
||||||
isConnected.BindValueChanged(connected =>
|
|
||||||
{
|
|
||||||
if (!connected.NewValue)
|
|
||||||
handleRoomLost();
|
|
||||||
}, true);
|
|
||||||
|
|
||||||
currentRoom.BindValueChanged(room =>
|
|
||||||
{
|
|
||||||
if (room.NewValue == null)
|
|
||||||
{
|
|
||||||
// the room has gone away.
|
|
||||||
// this could mean something happened during the join process, or an external connection issue occurred.
|
|
||||||
// one specific scenario is where the underlying room is created, but the signalr server returns an error during the join process. this triggers a PartRoom operation (see https://github.com/ppy/osu/blob/7654df94f6f37b8382be7dfcb4f674e03bd35427/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerRoomManager.cs#L97)
|
|
||||||
handleRoomLost();
|
|
||||||
}
|
|
||||||
}, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void UpdateMods()
|
protected override void UpdateMods()
|
||||||
{
|
{
|
||||||
@ -308,23 +230,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
|
|||||||
|
|
||||||
private bool exitConfirmed;
|
private bool exitConfirmed;
|
||||||
|
|
||||||
public override bool OnBackButton()
|
|
||||||
{
|
|
||||||
if (client.Room == null)
|
|
||||||
{
|
|
||||||
// room has not been created yet; exit immediately.
|
|
||||||
return base.OnBackButton();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (settingsOverlay.State.Value == Visibility.Visible)
|
|
||||||
{
|
|
||||||
settingsOverlay.Hide();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return base.OnBackButton();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool OnExiting(IScreen next)
|
public override bool OnExiting(IScreen next)
|
||||||
{
|
{
|
||||||
// the room may not be left immediately after a disconnection due to async flow,
|
// the room may not be left immediately after a disconnection due to async flow,
|
||||||
@ -508,19 +413,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Dispose(bool isDisposing)
|
|
||||||
{
|
|
||||||
base.Dispose(isDisposing);
|
|
||||||
|
|
||||||
if (client != null)
|
|
||||||
{
|
|
||||||
client.RoomUpdated -= onRoomUpdated;
|
|
||||||
client.LoadRequested -= onLoadRequested;
|
|
||||||
}
|
|
||||||
|
|
||||||
modSettingChangeTracker?.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void PresentBeatmap(WorkingBeatmap beatmap, RulesetInfo ruleset)
|
public void PresentBeatmap(WorkingBeatmap beatmap, RulesetInfo ruleset)
|
||||||
{
|
{
|
||||||
if (!this.IsCurrentScreen())
|
if (!this.IsCurrentScreen())
|
||||||
@ -536,5 +428,18 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
|
|||||||
|
|
||||||
this.Push(new MultiplayerMatchSongSelect(beatmap, ruleset));
|
this.Push(new MultiplayerMatchSongSelect(beatmap, ruleset));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void Dispose(bool isDisposing)
|
||||||
|
{
|
||||||
|
base.Dispose(isDisposing);
|
||||||
|
|
||||||
|
if (client != null)
|
||||||
|
{
|
||||||
|
client.RoomUpdated -= onRoomUpdated;
|
||||||
|
client.LoadRequested -= onLoadRequested;
|
||||||
|
}
|
||||||
|
|
||||||
|
modSettingChangeTracker?.Dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,12 +23,6 @@ namespace osu.Game.Screens.OnlinePlay
|
|||||||
RelativeSizeAxes = Axes.Both;
|
RelativeSizeAxes = Axes.Both;
|
||||||
}
|
}
|
||||||
|
|
||||||
public const float X_SHIFT = 200;
|
|
||||||
|
|
||||||
public const double X_MOVE_DURATION = 800;
|
|
||||||
|
|
||||||
public const double RESUME_TRANSITION_DELAY = DISAPPEAR_DURATION / 2;
|
|
||||||
|
|
||||||
public const double APPEAR_DURATION = 800;
|
public const double APPEAR_DURATION = 800;
|
||||||
|
|
||||||
public const double DISAPPEAR_DURATION = 500;
|
public const double DISAPPEAR_DURATION = 500;
|
||||||
@ -36,28 +30,23 @@ namespace osu.Game.Screens.OnlinePlay
|
|||||||
public override void OnEntering(IScreen last)
|
public override void OnEntering(IScreen last)
|
||||||
{
|
{
|
||||||
this.FadeInFromZero(APPEAR_DURATION, Easing.OutQuint);
|
this.FadeInFromZero(APPEAR_DURATION, Easing.OutQuint);
|
||||||
this.FadeInFromZero(APPEAR_DURATION, Easing.OutQuint);
|
|
||||||
this.MoveToX(X_SHIFT).MoveToX(0, X_MOVE_DURATION, Easing.OutQuint);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool OnExiting(IScreen next)
|
public override bool OnExiting(IScreen next)
|
||||||
{
|
{
|
||||||
this.FadeOut(DISAPPEAR_DURATION, Easing.OutQuint);
|
this.FadeOut(DISAPPEAR_DURATION, Easing.OutQuint);
|
||||||
this.MoveToX(X_SHIFT, X_MOVE_DURATION, Easing.OutQuint);
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnResuming(IScreen last)
|
public override void OnResuming(IScreen last)
|
||||||
{
|
{
|
||||||
this.Delay(RESUME_TRANSITION_DELAY).FadeIn(APPEAR_DURATION, Easing.OutQuint);
|
this.FadeIn(APPEAR_DURATION, Easing.OutQuint);
|
||||||
this.MoveToX(0, X_MOVE_DURATION, Easing.OutQuint);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnSuspending(IScreen next)
|
public override void OnSuspending(IScreen next)
|
||||||
{
|
{
|
||||||
this.FadeOut(DISAPPEAR_DURATION, Easing.OutQuint);
|
this.FadeOut(DISAPPEAR_DURATION, Easing.OutQuint);
|
||||||
this.MoveToX(-X_SHIFT, X_MOVE_DURATION, Easing.OutQuint);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string ToString() => Title;
|
public override string ToString() => Title;
|
||||||
|
32
osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomFooter.cs
Normal file
32
osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomFooter.cs
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Screens.OnlinePlay.Playlists
|
||||||
|
{
|
||||||
|
public class PlaylistsRoomFooter : CompositeDrawable
|
||||||
|
{
|
||||||
|
public Action OnStart;
|
||||||
|
|
||||||
|
public PlaylistsRoomFooter()
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both;
|
||||||
|
|
||||||
|
InternalChildren = new[]
|
||||||
|
{
|
||||||
|
new PlaylistsReadyButton
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
RelativeSizeAxes = Axes.Y,
|
||||||
|
Size = new Vector2(600, 1),
|
||||||
|
Action = () => OnStart?.Invoke()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -22,7 +22,7 @@ using osuTK;
|
|||||||
|
|
||||||
namespace osu.Game.Screens.OnlinePlay.Playlists
|
namespace osu.Game.Screens.OnlinePlay.Playlists
|
||||||
{
|
{
|
||||||
public class PlaylistsMatchSettingsOverlay : MatchSettingsOverlay
|
public class PlaylistsRoomSettingsOverlay : RoomSettingsOverlay
|
||||||
{
|
{
|
||||||
public Action EditPlaylist;
|
public Action EditPlaylist;
|
||||||
|
|
||||||
@ -193,7 +193,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
|
|||||||
Child = new GridContainer
|
Child = new GridContainer
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
Height = 500,
|
Height = 448,
|
||||||
Content = new[]
|
Content = new[]
|
||||||
{
|
{
|
||||||
new Drawable[]
|
new Drawable[]
|
@ -20,7 +20,6 @@ using osu.Game.Screens.Play;
|
|||||||
using osu.Game.Screens.Play.HUD;
|
using osu.Game.Screens.Play.HUD;
|
||||||
using osu.Game.Users;
|
using osu.Game.Users;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using Footer = osu.Game.Screens.OnlinePlay.Match.Components.Footer;
|
|
||||||
|
|
||||||
namespace osu.Game.Screens.OnlinePlay.Playlists
|
namespace osu.Game.Screens.OnlinePlay.Playlists
|
||||||
{
|
{
|
||||||
@ -30,21 +29,16 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
|
|||||||
|
|
||||||
public override string ShortTitle => "playlist";
|
public override string ShortTitle => "playlist";
|
||||||
|
|
||||||
[Resolved(typeof(Room), nameof(Room.RoomID))]
|
[Resolved]
|
||||||
private Bindable<long?> roomId { get; set; }
|
private IAPIProvider api { get; set; }
|
||||||
|
|
||||||
[Resolved(typeof(Room), nameof(Room.Playlist))]
|
|
||||||
private BindableList<PlaylistItem> playlist { get; set; }
|
|
||||||
|
|
||||||
private readonly IBindable<bool> isIdle = new BindableBool();
|
private readonly IBindable<bool> isIdle = new BindableBool();
|
||||||
|
|
||||||
private MatchSettingsOverlay settingsOverlay;
|
|
||||||
private MatchLeaderboard leaderboard;
|
private MatchLeaderboard leaderboard;
|
||||||
private OverlinedHeader participantsHeader;
|
|
||||||
private GridContainer mainContent;
|
|
||||||
private SelectionPollingComponent selectionPollingComponent;
|
private SelectionPollingComponent selectionPollingComponent;
|
||||||
|
|
||||||
public PlaylistsRoomSubScreen(Room room)
|
public PlaylistsRoomSubScreen(Room room)
|
||||||
|
: base(room, false) // Editing is temporarily not allowed.
|
||||||
{
|
{
|
||||||
Title = room.RoomID.Value == null ? "New playlist" : room.Name.Value;
|
Title = room.RoomID.Value == null ? "New playlist" : room.Name.Value;
|
||||||
Activity.Value = new UserActivity.InLobby(room);
|
Activity.Value = new UserActivity.InLobby(room);
|
||||||
@ -56,60 +50,26 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
|
|||||||
if (idleTracker != null)
|
if (idleTracker != null)
|
||||||
isIdle.BindTo(idleTracker.IsIdle);
|
isIdle.BindTo(idleTracker.IsIdle);
|
||||||
|
|
||||||
AddRangeInternal(new Drawable[]
|
AddInternal(selectionPollingComponent = new SelectionPollingComponent());
|
||||||
{
|
|
||||||
selectionPollingComponent = new SelectionPollingComponent(),
|
|
||||||
mainContent = new GridContainer
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Content = new[]
|
|
||||||
{
|
|
||||||
new Drawable[]
|
|
||||||
{
|
|
||||||
new Container
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Padding = new MarginPadding
|
|
||||||
{
|
|
||||||
Horizontal = 105,
|
|
||||||
Vertical = 20
|
|
||||||
},
|
|
||||||
Child = new GridContainer
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
RowDimensions = new[]
|
|
||||||
{
|
|
||||||
new Dimension(GridSizeMode.AutoSize),
|
|
||||||
new Dimension(GridSizeMode.AutoSize),
|
|
||||||
new Dimension(GridSizeMode.AutoSize),
|
|
||||||
new Dimension(),
|
|
||||||
},
|
|
||||||
Content = new[]
|
|
||||||
{
|
|
||||||
new Drawable[] { new Match.Components.Header() },
|
|
||||||
new Drawable[]
|
|
||||||
{
|
|
||||||
participantsHeader = new OverlinedHeader("Participants")
|
|
||||||
{
|
|
||||||
ShowLine = false
|
|
||||||
}
|
}
|
||||||
},
|
|
||||||
new Drawable[]
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
new Container
|
base.LoadComplete();
|
||||||
|
|
||||||
|
isIdle.BindValueChanged(_ => updatePollingRate(), true);
|
||||||
|
RoomId.BindValueChanged(id =>
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X,
|
if (id.NewValue != null)
|
||||||
AutoSizeAxes = Axes.Y,
|
|
||||||
Margin = new MarginPadding { Top = 5 },
|
|
||||||
Child = new ParticipantsDisplay(Direction.Horizontal)
|
|
||||||
{
|
{
|
||||||
Details = { BindTarget = participantsHeader.Details }
|
// Set the first playlist item.
|
||||||
|
// This is scheduled since updating the room and playlist may happen in an arbitrary order (via Room.CopyFrom()).
|
||||||
|
Schedule(() => SelectedItem.Value = Room.Playlist.FirstOrDefault());
|
||||||
}
|
}
|
||||||
|
}, true);
|
||||||
}
|
}
|
||||||
},
|
|
||||||
new Drawable[]
|
protected override Drawable CreateMainContent() => new GridContainer
|
||||||
{
|
|
||||||
new GridContainer
|
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Content = new[]
|
Content = new[]
|
||||||
@ -131,12 +91,12 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
|
|||||||
new DrawableRoomPlaylistWithResults
|
new DrawableRoomPlaylistWithResults
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Items = { BindTarget = playlist },
|
Items = { BindTarget = Room.Playlist },
|
||||||
SelectedItem = { BindTarget = SelectedItem },
|
SelectedItem = { BindTarget = SelectedItem },
|
||||||
RequestShowResults = item =>
|
RequestShowResults = item =>
|
||||||
{
|
{
|
||||||
Debug.Assert(roomId.Value != null);
|
Debug.Assert(RoomId.Value != null);
|
||||||
ParentScreen?.Push(new PlaylistsResultsScreen(null, roomId.Value.Value, item, false));
|
ParentScreen?.Push(new PlaylistsResultsScreen(null, RoomId.Value.Value, item, false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -160,6 +120,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
|
|||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
AutoSizeAxes = Axes.Y,
|
AutoSizeAxes = Axes.Y,
|
||||||
|
Alpha = 0,
|
||||||
Margin = new MarginPadding { Bottom = 10 },
|
Margin = new MarginPadding { Bottom = 10 },
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
@ -208,7 +169,6 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
|
|||||||
new Dimension(GridSizeMode.Relative, size: 0.4f, minSize: 120),
|
new Dimension(GridSizeMode.Relative, size: 0.4f, minSize: 120),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
null
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ColumnDimensions = new[]
|
ColumnDimensions = new[]
|
||||||
@ -216,74 +176,22 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
|
|||||||
new Dimension(GridSizeMode.Relative, size: 0.5f, maxSize: 400),
|
new Dimension(GridSizeMode.Relative, size: 0.5f, maxSize: 400),
|
||||||
new Dimension(),
|
new Dimension(),
|
||||||
new Dimension(GridSizeMode.Relative, size: 0.5f, maxSize: 600),
|
new Dimension(GridSizeMode.Relative, size: 0.5f, maxSize: 600),
|
||||||
new Dimension(),
|
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}
|
|
||||||
},
|
protected override Drawable CreateFooter() => new PlaylistsRoomFooter
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
new Drawable[]
|
|
||||||
{
|
{
|
||||||
new Footer { OnStart = StartPlay }
|
OnStart = StartPlay
|
||||||
}
|
};
|
||||||
},
|
|
||||||
RowDimensions = new[]
|
protected override RoomSettingsOverlay CreateRoomSettingsOverlay() => new PlaylistsRoomSettingsOverlay
|
||||||
{
|
{
|
||||||
new Dimension(),
|
|
||||||
new Dimension(GridSizeMode.AutoSize),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
settingsOverlay = new PlaylistsMatchSettingsOverlay
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
EditPlaylist = () =>
|
EditPlaylist = () =>
|
||||||
{
|
{
|
||||||
if (this.IsCurrentScreen())
|
if (this.IsCurrentScreen())
|
||||||
this.Push(new PlaylistsSongSelect());
|
this.Push(new PlaylistsSongSelect());
|
||||||
},
|
},
|
||||||
State = { Value = roomId.Value == null ? Visibility.Visible : Visibility.Hidden }
|
};
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (roomId.Value == null)
|
|
||||||
{
|
|
||||||
// A new room is being created.
|
|
||||||
// The main content should be hidden until the settings overlay is hidden, signaling the room is ready to be displayed.
|
|
||||||
mainContent.Hide();
|
|
||||||
|
|
||||||
settingsOverlay.State.BindValueChanged(visibility =>
|
|
||||||
{
|
|
||||||
if (visibility.NewValue == Visibility.Hidden)
|
|
||||||
mainContent.Show();
|
|
||||||
}, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Resolved]
|
|
||||||
private IAPIProvider api { get; set; }
|
|
||||||
|
|
||||||
protected override void LoadComplete()
|
|
||||||
{
|
|
||||||
base.LoadComplete();
|
|
||||||
|
|
||||||
isIdle.BindValueChanged(_ => updatePollingRate(), true);
|
|
||||||
|
|
||||||
roomId.BindValueChanged(id =>
|
|
||||||
{
|
|
||||||
if (id.NewValue == null)
|
|
||||||
settingsOverlay.Show();
|
|
||||||
else
|
|
||||||
{
|
|
||||||
settingsOverlay.Hide();
|
|
||||||
|
|
||||||
// Set the first playlist item.
|
|
||||||
// This is scheduled since updating the room and playlist may happen in an arbitrary order (via Room.CopyFrom()).
|
|
||||||
Schedule(() => SelectedItem.Value = playlist.FirstOrDefault());
|
|
||||||
}
|
|
||||||
}, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updatePollingRate()
|
private void updatePollingRate()
|
||||||
{
|
{
|
||||||
|
@ -10,12 +10,12 @@ using osu.Framework.Graphics.Containers;
|
|||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Localisation;
|
using osu.Framework.Localisation;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Beatmaps.Drawables;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Screens.Play.HUD;
|
using osu.Game.Screens.Play.HUD;
|
||||||
using osu.Game.Screens.Ranking.Expanded;
|
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
|
||||||
namespace osu.Game.Screens.Play
|
namespace osu.Game.Screens.Play
|
||||||
|
@ -9,6 +9,7 @@ using osu.Framework.Graphics;
|
|||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Localisation;
|
using osu.Framework.Localisation;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Beatmaps.Drawables;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Graphics.Containers;
|
using osu.Game.Graphics.Containers;
|
||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
|
@ -1,129 +0,0 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
|
||||||
|
|
||||||
using System.Globalization;
|
|
||||||
using osu.Framework.Allocation;
|
|
||||||
using osu.Framework.Bindables;
|
|
||||||
using osu.Framework.Graphics;
|
|
||||||
using osu.Framework.Graphics.Containers;
|
|
||||||
using osu.Framework.Graphics.Shapes;
|
|
||||||
using osu.Framework.Graphics.Sprites;
|
|
||||||
using osu.Framework.Graphics.UserInterface;
|
|
||||||
using osu.Game.Beatmaps;
|
|
||||||
using osu.Game.Graphics;
|
|
||||||
using osu.Game.Graphics.Containers;
|
|
||||||
using osuTK;
|
|
||||||
using osuTK.Graphics;
|
|
||||||
|
|
||||||
namespace osu.Game.Screens.Ranking.Expanded
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// A pill that displays the star rating of a <see cref="BeatmapInfo"/>.
|
|
||||||
/// </summary>
|
|
||||||
public class StarRatingDisplay : CompositeDrawable, IHasCurrentValue<StarDifficulty>
|
|
||||||
{
|
|
||||||
private Box background;
|
|
||||||
private FillFlowContainer content;
|
|
||||||
private OsuTextFlowContainer textFlow;
|
|
||||||
|
|
||||||
[Resolved]
|
|
||||||
private OsuColour colours { get; set; }
|
|
||||||
|
|
||||||
private readonly BindableWithCurrent<StarDifficulty> current = new BindableWithCurrent<StarDifficulty>();
|
|
||||||
|
|
||||||
public Bindable<StarDifficulty> Current
|
|
||||||
{
|
|
||||||
get => current.Current;
|
|
||||||
set => current.Current = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a new <see cref="StarRatingDisplay"/> using an already computed <see cref="StarDifficulty"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="starDifficulty">The already computed <see cref="StarDifficulty"/> to display the star difficulty of.</param>
|
|
||||||
public StarRatingDisplay(StarDifficulty starDifficulty)
|
|
||||||
{
|
|
||||||
Current.Value = starDifficulty;
|
|
||||||
}
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
|
||||||
private void load(OsuColour colours, BeatmapDifficultyCache difficultyCache)
|
|
||||||
{
|
|
||||||
AutoSizeAxes = Axes.Both;
|
|
||||||
|
|
||||||
InternalChildren = new Drawable[]
|
|
||||||
{
|
|
||||||
new CircularContainer
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Masking = true,
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
background = new Box
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
content = new FillFlowContainer
|
|
||||||
{
|
|
||||||
AutoSizeAxes = Axes.Both,
|
|
||||||
Padding = new MarginPadding { Horizontal = 8, Vertical = 4 },
|
|
||||||
Direction = FillDirection.Horizontal,
|
|
||||||
Spacing = new Vector2(2, 0),
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
new SpriteIcon
|
|
||||||
{
|
|
||||||
Anchor = Anchor.CentreLeft,
|
|
||||||
Origin = Anchor.CentreLeft,
|
|
||||||
Size = new Vector2(7),
|
|
||||||
Icon = FontAwesome.Solid.Star,
|
|
||||||
},
|
|
||||||
textFlow = new OsuTextFlowContainer(s => s.Font = OsuFont.Numeric.With(weight: FontWeight.Black))
|
|
||||||
{
|
|
||||||
Anchor = Anchor.CentreLeft,
|
|
||||||
Origin = Anchor.CentreLeft,
|
|
||||||
AutoSizeAxes = Axes.Both,
|
|
||||||
Direction = FillDirection.Horizontal,
|
|
||||||
TextAnchor = Anchor.BottomLeft,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void LoadComplete()
|
|
||||||
{
|
|
||||||
base.LoadComplete();
|
|
||||||
|
|
||||||
Current.BindValueChanged(_ => updateDisplay(), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateDisplay()
|
|
||||||
{
|
|
||||||
var starRatingParts = Current.Value.Stars.ToString("0.00", CultureInfo.InvariantCulture).Split('.');
|
|
||||||
string wholePart = starRatingParts[0];
|
|
||||||
string fractionPart = starRatingParts[1];
|
|
||||||
string separator = CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator;
|
|
||||||
|
|
||||||
var stars = Current.Value.Stars;
|
|
||||||
|
|
||||||
background.Colour = colours.ForStarDifficulty(stars);
|
|
||||||
content.Colour = stars >= 6.5 ? colours.Orange1 : Color4.Black;
|
|
||||||
|
|
||||||
textFlow.Clear();
|
|
||||||
textFlow.AddText($"{wholePart}", s =>
|
|
||||||
{
|
|
||||||
s.Font = s.Font.With(size: 14);
|
|
||||||
s.UseFullGlyphHeight = false;
|
|
||||||
});
|
|
||||||
|
|
||||||
textFlow.AddText($"{separator}{fractionPart}", s =>
|
|
||||||
{
|
|
||||||
s.Font = s.Font.With(size: 7);
|
|
||||||
s.UseFullGlyphHeight = false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -28,7 +28,6 @@ using osu.Game.Extensions;
|
|||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.UI;
|
using osu.Game.Rulesets.UI;
|
||||||
using osu.Game.Screens.Ranking.Expanded;
|
|
||||||
using osu.Game.Graphics.Containers;
|
using osu.Game.Graphics.Containers;
|
||||||
|
|
||||||
namespace osu.Game.Screens.Select
|
namespace osu.Game.Screens.Select
|
||||||
@ -38,6 +37,8 @@ namespace osu.Game.Screens.Select
|
|||||||
public const float BORDER_THICKNESS = 2.5f;
|
public const float BORDER_THICKNESS = 2.5f;
|
||||||
private const float shear_width = 36.75f;
|
private const float shear_width = 36.75f;
|
||||||
|
|
||||||
|
private const float transition_duration = 250;
|
||||||
|
|
||||||
private static readonly Vector2 wedged_container_shear = new Vector2(shear_width / SongSelect.WEDGE_HEIGHT, 0);
|
private static readonly Vector2 wedged_container_shear = new Vector2(shear_width / SongSelect.WEDGE_HEIGHT, 0);
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
@ -46,11 +47,6 @@ namespace osu.Game.Screens.Select
|
|||||||
[Resolved]
|
[Resolved]
|
||||||
private IBindable<IReadOnlyList<Mod>> mods { get; set; }
|
private IBindable<IReadOnlyList<Mod>> mods { get; set; }
|
||||||
|
|
||||||
[Resolved]
|
|
||||||
private BeatmapDifficultyCache difficultyCache { get; set; }
|
|
||||||
|
|
||||||
private IBindable<StarDifficulty?> beatmapDifficulty;
|
|
||||||
|
|
||||||
protected Container DisplayedContent { get; private set; }
|
protected Container DisplayedContent { get; private set; }
|
||||||
|
|
||||||
protected WedgeInfoText Info { get; private set; }
|
protected WedgeInfoText Info { get; private set; }
|
||||||
@ -77,24 +73,24 @@ namespace osu.Game.Screens.Select
|
|||||||
ruleset.BindValueChanged(_ => updateDisplay());
|
ruleset.BindValueChanged(_ => updateDisplay());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private const double animation_duration = 800;
|
||||||
|
|
||||||
protected override void PopIn()
|
protected override void PopIn()
|
||||||
{
|
{
|
||||||
this.MoveToX(0, 800, Easing.OutQuint);
|
this.MoveToX(0, animation_duration, Easing.OutQuint);
|
||||||
this.RotateTo(0, 800, Easing.OutQuint);
|
this.RotateTo(0, animation_duration, Easing.OutQuint);
|
||||||
this.FadeIn(250);
|
this.FadeIn(transition_duration);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void PopOut()
|
protected override void PopOut()
|
||||||
{
|
{
|
||||||
this.MoveToX(-100, 800, Easing.In);
|
this.MoveToX(-100, animation_duration, Easing.In);
|
||||||
this.RotateTo(10, 800, Easing.In);
|
this.RotateTo(10, animation_duration, Easing.In);
|
||||||
this.FadeOut(500, Easing.In);
|
this.FadeOut(transition_duration * 2, Easing.In);
|
||||||
}
|
}
|
||||||
|
|
||||||
private WorkingBeatmap beatmap;
|
private WorkingBeatmap beatmap;
|
||||||
|
|
||||||
private CancellationTokenSource cancellationSource;
|
|
||||||
|
|
||||||
public WorkingBeatmap Beatmap
|
public WorkingBeatmap Beatmap
|
||||||
{
|
{
|
||||||
get => beatmap;
|
get => beatmap;
|
||||||
@ -103,12 +99,6 @@ namespace osu.Game.Screens.Select
|
|||||||
if (beatmap == value) return;
|
if (beatmap == value) return;
|
||||||
|
|
||||||
beatmap = value;
|
beatmap = value;
|
||||||
cancellationSource?.Cancel();
|
|
||||||
cancellationSource = new CancellationTokenSource();
|
|
||||||
|
|
||||||
beatmapDifficulty?.UnbindAll();
|
|
||||||
beatmapDifficulty = difficultyCache.GetBindableDifficulty(beatmap.BeatmapInfo, cancellationSource.Token);
|
|
||||||
beatmapDifficulty.BindValueChanged(_ => updateDisplay());
|
|
||||||
|
|
||||||
updateDisplay();
|
updateDisplay();
|
||||||
}
|
}
|
||||||
@ -128,7 +118,7 @@ namespace osu.Game.Screens.Select
|
|||||||
{
|
{
|
||||||
State.Value = beatmap == null ? Visibility.Hidden : Visibility.Visible;
|
State.Value = beatmap == null ? Visibility.Hidden : Visibility.Visible;
|
||||||
|
|
||||||
DisplayedContent?.FadeOut(250);
|
DisplayedContent?.FadeOut(transition_duration);
|
||||||
DisplayedContent?.Expire();
|
DisplayedContent?.Expire();
|
||||||
DisplayedContent = null;
|
DisplayedContent = null;
|
||||||
}
|
}
|
||||||
@ -147,7 +137,7 @@ namespace osu.Game.Screens.Select
|
|||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new BeatmapInfoWedgeBackground(beatmap),
|
new BeatmapInfoWedgeBackground(beatmap),
|
||||||
Info = new WedgeInfoText(beatmap, ruleset.Value, mods.Value, beatmapDifficulty.Value ?? new StarDifficulty()),
|
Info = new WedgeInfoText(beatmap, ruleset.Value, mods.Value),
|
||||||
}
|
}
|
||||||
}, loaded =>
|
}, loaded =>
|
||||||
{
|
{
|
||||||
@ -160,12 +150,6 @@ namespace osu.Game.Screens.Select
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Dispose(bool isDisposing)
|
|
||||||
{
|
|
||||||
base.Dispose(isDisposing);
|
|
||||||
cancellationSource?.Cancel();
|
|
||||||
}
|
|
||||||
|
|
||||||
public class WedgeInfoText : Container
|
public class WedgeInfoText : Container
|
||||||
{
|
{
|
||||||
public OsuSpriteText VersionLabel { get; private set; }
|
public OsuSpriteText VersionLabel { get; private set; }
|
||||||
@ -174,6 +158,9 @@ namespace osu.Game.Screens.Select
|
|||||||
public BeatmapSetOnlineStatusPill StatusPill { get; private set; }
|
public BeatmapSetOnlineStatusPill StatusPill { get; private set; }
|
||||||
public FillFlowContainer MapperContainer { get; private set; }
|
public FillFlowContainer MapperContainer { get; private set; }
|
||||||
|
|
||||||
|
private Container difficultyColourBar;
|
||||||
|
private StarRatingDisplay starRatingDisplay;
|
||||||
|
|
||||||
private ILocalisedBindableString titleBinding;
|
private ILocalisedBindableString titleBinding;
|
||||||
private ILocalisedBindableString artistBinding;
|
private ILocalisedBindableString artistBinding;
|
||||||
private FillFlowContainer infoLabelContainer;
|
private FillFlowContainer infoLabelContainer;
|
||||||
@ -182,20 +169,21 @@ namespace osu.Game.Screens.Select
|
|||||||
private readonly WorkingBeatmap beatmap;
|
private readonly WorkingBeatmap beatmap;
|
||||||
private readonly RulesetInfo ruleset;
|
private readonly RulesetInfo ruleset;
|
||||||
private readonly IReadOnlyList<Mod> mods;
|
private readonly IReadOnlyList<Mod> mods;
|
||||||
private readonly StarDifficulty starDifficulty;
|
|
||||||
|
|
||||||
private ModSettingChangeTracker settingChangeTracker;
|
private ModSettingChangeTracker settingChangeTracker;
|
||||||
|
|
||||||
public WedgeInfoText(WorkingBeatmap beatmap, RulesetInfo userRuleset, IReadOnlyList<Mod> mods, StarDifficulty difficulty)
|
public WedgeInfoText(WorkingBeatmap beatmap, RulesetInfo userRuleset, IReadOnlyList<Mod> mods)
|
||||||
{
|
{
|
||||||
this.beatmap = beatmap;
|
this.beatmap = beatmap;
|
||||||
ruleset = userRuleset ?? beatmap.BeatmapInfo.Ruleset;
|
ruleset = userRuleset ?? beatmap.BeatmapInfo.Ruleset;
|
||||||
this.mods = mods;
|
this.mods = mods;
|
||||||
starDifficulty = difficulty;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private CancellationTokenSource cancellationSource;
|
||||||
|
private IBindable<StarDifficulty?> starDifficulty;
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(LocalisationManager localisation)
|
private void load(OsuColour colours, LocalisationManager localisation, BeatmapDifficultyCache difficultyCache)
|
||||||
{
|
{
|
||||||
var beatmapInfo = beatmap.BeatmapInfo;
|
var beatmapInfo = beatmap.BeatmapInfo;
|
||||||
var metadata = beatmapInfo.Metadata ?? beatmap.BeatmapSetInfo?.Metadata ?? new BeatmapMetadata();
|
var metadata = beatmapInfo.Metadata ?? beatmap.BeatmapSetInfo?.Metadata ?? new BeatmapMetadata();
|
||||||
@ -205,12 +193,30 @@ namespace osu.Game.Screens.Select
|
|||||||
titleBinding = localisation.GetLocalisedString(new RomanisableString(metadata.TitleUnicode, metadata.Title));
|
titleBinding = localisation.GetLocalisedString(new RomanisableString(metadata.TitleUnicode, metadata.Title));
|
||||||
artistBinding = localisation.GetLocalisedString(new RomanisableString(metadata.ArtistUnicode, metadata.Artist));
|
artistBinding = localisation.GetLocalisedString(new RomanisableString(metadata.ArtistUnicode, metadata.Artist));
|
||||||
|
|
||||||
|
const float top_height = 0.7f;
|
||||||
|
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new DifficultyColourBar(starDifficulty)
|
difficultyColourBar = new Container
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Y,
|
RelativeSizeAxes = Axes.Y,
|
||||||
Width = 20,
|
Width = 20f,
|
||||||
|
Children = new[]
|
||||||
|
{
|
||||||
|
new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Width = top_height,
|
||||||
|
},
|
||||||
|
new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
RelativePositionAxes = Axes.Both,
|
||||||
|
Alpha = 0.5f,
|
||||||
|
X = top_height,
|
||||||
|
Width = 1 - top_height,
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
new FillFlowContainer
|
new FillFlowContainer
|
||||||
{
|
{
|
||||||
@ -241,14 +247,16 @@ namespace osu.Game.Screens.Select
|
|||||||
Padding = new MarginPadding { Top = 14, Right = shear_width / 2 },
|
Padding = new MarginPadding { Top = 14, Right = shear_width / 2 },
|
||||||
AutoSizeAxes = Axes.Both,
|
AutoSizeAxes = Axes.Both,
|
||||||
Shear = wedged_container_shear,
|
Shear = wedged_container_shear,
|
||||||
Children = new[]
|
Spacing = new Vector2(0f, 5f),
|
||||||
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
createStarRatingDisplay(starDifficulty).With(display =>
|
starRatingDisplay = new StarRatingDisplay(default, animated: true)
|
||||||
{
|
{
|
||||||
display.Anchor = Anchor.TopRight;
|
Anchor = Anchor.TopRight,
|
||||||
display.Origin = Anchor.TopRight;
|
Origin = Anchor.TopRight,
|
||||||
display.Shear = -wedged_container_shear;
|
Shear = -wedged_container_shear,
|
||||||
}),
|
Alpha = 0f,
|
||||||
|
},
|
||||||
StatusPill = new BeatmapSetOnlineStatusPill
|
StatusPill = new BeatmapSetOnlineStatusPill
|
||||||
{
|
{
|
||||||
Anchor = Anchor.TopRight,
|
Anchor = Anchor.TopRight,
|
||||||
@ -304,6 +312,18 @@ namespace osu.Game.Screens.Select
|
|||||||
titleBinding.BindValueChanged(_ => setMetadata(metadata.Source));
|
titleBinding.BindValueChanged(_ => setMetadata(metadata.Source));
|
||||||
artistBinding.BindValueChanged(_ => setMetadata(metadata.Source), true);
|
artistBinding.BindValueChanged(_ => setMetadata(metadata.Source), true);
|
||||||
|
|
||||||
|
starRatingDisplay.DisplayedStars.BindValueChanged(s =>
|
||||||
|
{
|
||||||
|
difficultyColourBar.Colour = colours.ForStarDifficulty(s.NewValue);
|
||||||
|
}, true);
|
||||||
|
|
||||||
|
starDifficulty = difficultyCache.GetBindableDifficulty(beatmapInfo, (cancellationSource = new CancellationTokenSource()).Token);
|
||||||
|
starDifficulty.BindValueChanged(s =>
|
||||||
|
{
|
||||||
|
starRatingDisplay.FadeIn(transition_duration);
|
||||||
|
starRatingDisplay.Current.Value = s.NewValue ?? default;
|
||||||
|
});
|
||||||
|
|
||||||
// no difficulty means it can't have a status to show
|
// no difficulty means it can't have a status to show
|
||||||
if (beatmapInfo.Version == null)
|
if (beatmapInfo.Version == null)
|
||||||
StatusPill.Hide();
|
StatusPill.Hide();
|
||||||
@ -311,13 +331,6 @@ namespace osu.Game.Screens.Select
|
|||||||
addInfoLabels();
|
addInfoLabels();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Drawable createStarRatingDisplay(StarDifficulty difficulty) => difficulty.Stars > 0
|
|
||||||
? new StarRatingDisplay(difficulty)
|
|
||||||
{
|
|
||||||
Margin = new MarginPadding { Bottom = 5 }
|
|
||||||
}
|
|
||||||
: Empty();
|
|
||||||
|
|
||||||
private void setMetadata(string source)
|
private void setMetadata(string source)
|
||||||
{
|
{
|
||||||
ArtistLabel.Text = artistBinding.Value;
|
ArtistLabel.Text = artistBinding.Value;
|
||||||
@ -429,6 +442,7 @@ namespace osu.Game.Screens.Select
|
|||||||
{
|
{
|
||||||
base.Dispose(isDisposing);
|
base.Dispose(isDisposing);
|
||||||
settingChangeTracker?.Dispose();
|
settingChangeTracker?.Dispose();
|
||||||
|
cancellationSource?.Cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
public class InfoLabel : Container, IHasTooltip
|
public class InfoLabel : Container, IHasTooltip
|
||||||
@ -489,43 +503,6 @@ namespace osu.Game.Screens.Select
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class DifficultyColourBar : Container
|
|
||||||
{
|
|
||||||
private readonly StarDifficulty difficulty;
|
|
||||||
|
|
||||||
public DifficultyColourBar(StarDifficulty difficulty)
|
|
||||||
{
|
|
||||||
this.difficulty = difficulty;
|
|
||||||
}
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
|
||||||
private void load(OsuColour colours)
|
|
||||||
{
|
|
||||||
const float full_opacity_ratio = 0.7f;
|
|
||||||
|
|
||||||
var difficultyColour = colours.ForStarDifficulty(difficulty.Stars);
|
|
||||||
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
new Box
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Colour = difficultyColour,
|
|
||||||
Width = full_opacity_ratio,
|
|
||||||
},
|
|
||||||
new Box
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
RelativePositionAxes = Axes.Both,
|
|
||||||
Colour = difficultyColour,
|
|
||||||
Alpha = 0.5f,
|
|
||||||
X = full_opacity_ratio,
|
|
||||||
Width = 1 - full_opacity_ratio,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -105,12 +105,18 @@ namespace osu.Game.Skinning
|
|||||||
/// Returns a list of all usable <see cref="SkinInfo"/>s that have been loaded by the user.
|
/// Returns a list of all usable <see cref="SkinInfo"/>s that have been loaded by the user.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>A newly allocated list of available <see cref="SkinInfo"/>.</returns>
|
/// <returns>A newly allocated list of available <see cref="SkinInfo"/>.</returns>
|
||||||
public List<SkinInfo> GetAllUserSkins() => ModelStore.ConsumableItems.Where(s => !s.DeletePending).ToList();
|
public List<SkinInfo> GetAllUserSkins(bool includeFiles = false)
|
||||||
|
{
|
||||||
|
if (includeFiles)
|
||||||
|
return ModelStore.ConsumableItems.Where(s => !s.DeletePending).ToList();
|
||||||
|
|
||||||
|
return ModelStore.Items.Where(s => !s.DeletePending).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
public void SelectRandomSkin()
|
public void SelectRandomSkin()
|
||||||
{
|
{
|
||||||
// choose from only user skins, removing the current selection to ensure a new one is chosen.
|
// choose from only user skins, removing the current selection to ensure a new one is chosen.
|
||||||
var randomChoices = GetAllUsableSkins().Where(s => s.ID != CurrentSkinInfo.Value.ID).ToArray();
|
var randomChoices = ModelStore.Items.Where(s => !s.DeletePending && s.ID != CurrentSkinInfo.Value.ID).ToArray();
|
||||||
|
|
||||||
if (randomChoices.Length == 0)
|
if (randomChoices.Length == 0)
|
||||||
{
|
{
|
||||||
@ -118,7 +124,8 @@ namespace osu.Game.Skinning
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
CurrentSkinInfo.Value = randomChoices.ElementAt(RNG.Next(0, randomChoices.Length));
|
var chosen = randomChoices.ElementAt(RNG.Next(0, randomChoices.Length));
|
||||||
|
CurrentSkinInfo.Value = ModelStore.ConsumableItems.Single(i => i.ID == chosen.ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override SkinInfo CreateModel(ArchiveReader archive) => new SkinInfo { Name = archive.Name };
|
protected override SkinInfo CreateModel(ArchiveReader archive) => new SkinInfo { Name = archive.Name };
|
||||||
|
@ -1,150 +1,36 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Game.Online.API;
|
using osu.Game.Online.API;
|
||||||
using osu.Game.Online.API.Requests;
|
|
||||||
using osu.Game.Online.Rooms;
|
using osu.Game.Online.Rooms;
|
||||||
using osu.Game.Rulesets.Scoring;
|
|
||||||
using osu.Game.Scoring;
|
|
||||||
using osu.Game.Screens.OnlinePlay.Components;
|
using osu.Game.Screens.OnlinePlay.Components;
|
||||||
using osu.Game.Screens.OnlinePlay.Multiplayer;
|
using osu.Game.Screens.OnlinePlay.Multiplayer;
|
||||||
|
using osu.Game.Tests.Visual.OnlinePlay;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual.Multiplayer
|
namespace osu.Game.Tests.Visual.Multiplayer
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A <see cref="RoomManager"/> for use in multiplayer test scenes. Should generally not be used by itself outside of a <see cref="MultiplayerTestScene"/>.
|
/// A <see cref="RoomManager"/> for use in multiplayer test scenes, backed by a <see cref="TestRoomRequestsHandler"/>.
|
||||||
|
/// Should generally not be used by itself outside of a <see cref="MultiplayerTestScene"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
|
||||||
/// This implementation will pretend to be a server, handling room retrieval and manipulation requests
|
|
||||||
/// and returning a roughly expected state, without the need for a server to be running.
|
|
||||||
/// </remarks>
|
|
||||||
public class TestRequestHandlingMultiplayerRoomManager : MultiplayerRoomManager
|
public class TestRequestHandlingMultiplayerRoomManager : MultiplayerRoomManager
|
||||||
{
|
{
|
||||||
[Resolved]
|
public IReadOnlyList<Room> ServerSideRooms => handler.ServerSideRooms;
|
||||||
private IAPIProvider api { get; set; }
|
|
||||||
|
|
||||||
[Resolved]
|
private readonly TestRoomRequestsHandler handler = new TestRoomRequestsHandler();
|
||||||
private OsuGameBase game { get; set; }
|
|
||||||
|
|
||||||
public IReadOnlyList<Room> ServerSideRooms => serverSideRooms;
|
|
||||||
private readonly List<Room> serverSideRooms = new List<Room>();
|
|
||||||
|
|
||||||
private int currentRoomId;
|
|
||||||
private int currentPlaylistItemId;
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load(IAPIProvider api, OsuGameBase game)
|
||||||
{
|
{
|
||||||
int currentScoreId = 0;
|
((DummyAPIAccess)api).HandleRequest = request => handler.HandleRequest(request, api.LocalUser.Value, game);
|
||||||
|
|
||||||
// Handling here is pretending to be a server, while also updating the local state to match
|
|
||||||
// how the server would eventually respond and update the RoomManager.
|
|
||||||
((DummyAPIAccess)api).HandleRequest = req =>
|
|
||||||
{
|
|
||||||
switch (req)
|
|
||||||
{
|
|
||||||
case CreateRoomRequest createRoomRequest:
|
|
||||||
var apiRoom = new Room();
|
|
||||||
|
|
||||||
apiRoom.CopyFrom(createRoomRequest.Room);
|
|
||||||
|
|
||||||
// Passwords are explicitly not copied between rooms.
|
|
||||||
apiRoom.HasPassword.Value = !string.IsNullOrEmpty(createRoomRequest.Room.Password.Value);
|
|
||||||
apiRoom.Password.Value = createRoomRequest.Room.Password.Value;
|
|
||||||
|
|
||||||
AddServerSideRoom(apiRoom);
|
|
||||||
|
|
||||||
var responseRoom = new APICreatedRoom();
|
|
||||||
responseRoom.CopyFrom(createResponseRoom(apiRoom, false));
|
|
||||||
|
|
||||||
createRoomRequest.TriggerSuccess(responseRoom);
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case JoinRoomRequest joinRoomRequest:
|
|
||||||
{
|
|
||||||
var room = ServerSideRooms.Single(r => r.RoomID.Value == joinRoomRequest.Room.RoomID.Value);
|
|
||||||
|
|
||||||
if (joinRoomRequest.Password != room.Password.Value)
|
|
||||||
{
|
|
||||||
joinRoomRequest.TriggerFailure(new InvalidOperationException("Invalid password."));
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
joinRoomRequest.TriggerSuccess();
|
/// <summary>
|
||||||
return true;
|
/// Adds a room to a local "server-side" list that's returned when a <see cref="GetRoomsRequest"/> is fired.
|
||||||
}
|
/// </summary>
|
||||||
|
/// <param name="room">The room.</param>
|
||||||
case PartRoomRequest partRoomRequest:
|
public void AddServerSideRoom(Room room) => handler.AddServerSideRoom(room);
|
||||||
partRoomRequest.TriggerSuccess();
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case GetRoomsRequest getRoomsRequest:
|
|
||||||
var roomsWithoutParticipants = new List<Room>();
|
|
||||||
|
|
||||||
foreach (var r in ServerSideRooms)
|
|
||||||
roomsWithoutParticipants.Add(createResponseRoom(r, false));
|
|
||||||
|
|
||||||
getRoomsRequest.TriggerSuccess(roomsWithoutParticipants);
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case GetRoomRequest getRoomRequest:
|
|
||||||
getRoomRequest.TriggerSuccess(createResponseRoom(ServerSideRooms.Single(r => r.RoomID.Value == getRoomRequest.RoomId), true));
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case GetBeatmapSetRequest getBeatmapSetRequest:
|
|
||||||
var onlineReq = new GetBeatmapSetRequest(getBeatmapSetRequest.ID, getBeatmapSetRequest.Type);
|
|
||||||
onlineReq.Success += res => getBeatmapSetRequest.TriggerSuccess(res);
|
|
||||||
onlineReq.Failure += e => getBeatmapSetRequest.TriggerFailure(e);
|
|
||||||
|
|
||||||
// Get the online API from the game's dependencies.
|
|
||||||
game.Dependencies.Get<IAPIProvider>().Queue(onlineReq);
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case CreateRoomScoreRequest createRoomScoreRequest:
|
|
||||||
createRoomScoreRequest.TriggerSuccess(new APIScoreToken { ID = 1 });
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case SubmitRoomScoreRequest submitRoomScoreRequest:
|
|
||||||
submitRoomScoreRequest.TriggerSuccess(new MultiplayerScore
|
|
||||||
{
|
|
||||||
ID = currentScoreId++,
|
|
||||||
Accuracy = 1,
|
|
||||||
EndedAt = DateTimeOffset.Now,
|
|
||||||
Passed = true,
|
|
||||||
Rank = ScoreRank.S,
|
|
||||||
MaxCombo = 1000,
|
|
||||||
TotalScore = 1000000,
|
|
||||||
User = api.LocalUser.Value,
|
|
||||||
Statistics = new Dictionary<HitResult, int>()
|
|
||||||
});
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddServerSideRoom(Room room)
|
|
||||||
{
|
|
||||||
room.RoomID.Value ??= currentRoomId++;
|
|
||||||
for (int i = 0; i < room.Playlist.Count; i++)
|
|
||||||
room.Playlist[i].ID = currentPlaylistItemId++;
|
|
||||||
|
|
||||||
serverSideRooms.Add(room);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Room createResponseRoom(Room room, bool withParticipants)
|
|
||||||
{
|
|
||||||
var responseRoom = new Room();
|
|
||||||
responseRoom.CopyFrom(room);
|
|
||||||
responseRoom.Password.Value = null;
|
|
||||||
if (!withParticipants)
|
|
||||||
responseRoom.RecentParticipants.Clear();
|
|
||||||
return responseRoom;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,111 +0,0 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Linq;
|
|
||||||
using osu.Framework.Bindables;
|
|
||||||
using osu.Game.Beatmaps;
|
|
||||||
using osu.Game.Online.Rooms;
|
|
||||||
using osu.Game.Rulesets;
|
|
||||||
using osu.Game.Screens.OnlinePlay;
|
|
||||||
using osu.Game.Screens.OnlinePlay.Components;
|
|
||||||
using osu.Game.Users;
|
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual.OnlinePlay
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// A very simple <see cref="RoomManager"/> for use in online play test scenes.
|
|
||||||
/// </summary>
|
|
||||||
public class BasicTestRoomManager : IRoomManager
|
|
||||||
{
|
|
||||||
public event Action RoomsUpdated;
|
|
||||||
|
|
||||||
public readonly BindableList<Room> Rooms = new BindableList<Room>();
|
|
||||||
|
|
||||||
public Action<Room, string> JoinRoomRequested;
|
|
||||||
|
|
||||||
public IBindable<bool> InitialRoomsReceived { get; } = new Bindable<bool>(true);
|
|
||||||
|
|
||||||
IBindableList<Room> IRoomManager.Rooms => Rooms;
|
|
||||||
|
|
||||||
private int currentRoomId;
|
|
||||||
|
|
||||||
public void CreateRoom(Room room, Action<Room> onSuccess = null, Action<string> onError = null)
|
|
||||||
{
|
|
||||||
room.RoomID.Value ??= Rooms.Select(r => r.RoomID.Value).Where(id => id != null).Select(id => id.Value).DefaultIfEmpty().Max() + 1;
|
|
||||||
onSuccess?.Invoke(room);
|
|
||||||
|
|
||||||
AddOrUpdateRoom(room);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddOrUpdateRoom(Room room)
|
|
||||||
{
|
|
||||||
var existing = Rooms.FirstOrDefault(r => r.RoomID.Value != null && r.RoomID.Value == room.RoomID.Value);
|
|
||||||
|
|
||||||
if (existing != null)
|
|
||||||
existing.CopyFrom(room);
|
|
||||||
else
|
|
||||||
Rooms.Add(room);
|
|
||||||
|
|
||||||
RoomsUpdated?.Invoke();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RemoveRoom(Room room)
|
|
||||||
{
|
|
||||||
Rooms.Remove(room);
|
|
||||||
RoomsUpdated?.Invoke();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ClearRooms()
|
|
||||||
{
|
|
||||||
Rooms.Clear();
|
|
||||||
RoomsUpdated?.Invoke();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void JoinRoom(Room room, string password, Action<Room> onSuccess = null, Action<string> onError = null)
|
|
||||||
{
|
|
||||||
JoinRoomRequested?.Invoke(room, password);
|
|
||||||
onSuccess?.Invoke(room);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void PartRoom()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddRooms(int count, RulesetInfo ruleset = null, bool withPassword = false)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < count; i++)
|
|
||||||
{
|
|
||||||
var room = new Room
|
|
||||||
{
|
|
||||||
RoomID = { Value = currentRoomId },
|
|
||||||
Position = { Value = currentRoomId },
|
|
||||||
Name = { Value = $"Room {currentRoomId}" },
|
|
||||||
Host = { Value = new User { Username = "Host" } },
|
|
||||||
EndDate = { Value = DateTimeOffset.Now + TimeSpan.FromSeconds(10) },
|
|
||||||
Category = { Value = i % 2 == 0 ? RoomCategory.Spotlight : RoomCategory.Normal },
|
|
||||||
Password = { Value = withPassword ? "password" : string.Empty }
|
|
||||||
};
|
|
||||||
|
|
||||||
if (ruleset != null)
|
|
||||||
{
|
|
||||||
room.Playlist.Add(new PlaylistItem
|
|
||||||
{
|
|
||||||
Ruleset = { Value = ruleset },
|
|
||||||
Beatmap =
|
|
||||||
{
|
|
||||||
Value = new BeatmapInfo
|
|
||||||
{
|
|
||||||
Metadata = new BeatmapMetadata()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
CreateRoom(room);
|
|
||||||
|
|
||||||
currentRoomId++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -71,6 +71,6 @@ namespace osu.Game.Tests.Visual.OnlinePlay
|
|||||||
drawableComponents.Add(drawable);
|
drawableComponents.Add(drawable);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual IRoomManager CreateRoomManager() => new BasicTestRoomManager();
|
protected virtual IRoomManager CreateRoomManager() => new TestRequestHandlingRoomManager();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,75 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Online.API;
|
||||||
|
using osu.Game.Online.Rooms;
|
||||||
|
using osu.Game.Rulesets;
|
||||||
|
using osu.Game.Screens.OnlinePlay.Components;
|
||||||
|
using osu.Game.Users;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.Visual.OnlinePlay
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A very simple <see cref="RoomManager"/> for use in online play test scenes.
|
||||||
|
/// </summary>
|
||||||
|
public class TestRequestHandlingRoomManager : RoomManager
|
||||||
|
{
|
||||||
|
public Action<Room, string> JoinRoomRequested;
|
||||||
|
|
||||||
|
private int currentRoomId;
|
||||||
|
|
||||||
|
private readonly TestRoomRequestsHandler handler = new TestRoomRequestsHandler();
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(IAPIProvider api, OsuGameBase game)
|
||||||
|
{
|
||||||
|
((DummyAPIAccess)api).HandleRequest = request => handler.HandleRequest(request, api.LocalUser.Value, game);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void JoinRoom(Room room, string password = null, Action<Room> onSuccess = null, Action<string> onError = null)
|
||||||
|
{
|
||||||
|
JoinRoomRequested?.Invoke(room, password);
|
||||||
|
base.JoinRoom(room, password, onSuccess, onError);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddRooms(int count, RulesetInfo ruleset = null, bool withPassword = false)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
var room = new Room
|
||||||
|
{
|
||||||
|
RoomID = { Value = -currentRoomId },
|
||||||
|
Name = { Value = $@"Room {currentRoomId}" },
|
||||||
|
Host = { Value = new User { Username = @"Host" } },
|
||||||
|
EndDate = { Value = DateTimeOffset.Now + TimeSpan.FromSeconds(10) },
|
||||||
|
Category = { Value = i % 2 == 0 ? RoomCategory.Spotlight : RoomCategory.Normal },
|
||||||
|
};
|
||||||
|
|
||||||
|
if (withPassword)
|
||||||
|
room.Password.Value = @"password";
|
||||||
|
|
||||||
|
if (ruleset != null)
|
||||||
|
{
|
||||||
|
room.Playlist.Add(new PlaylistItem
|
||||||
|
{
|
||||||
|
Ruleset = { Value = ruleset },
|
||||||
|
Beatmap =
|
||||||
|
{
|
||||||
|
Value = new BeatmapInfo
|
||||||
|
{
|
||||||
|
Metadata = new BeatmapMetadata()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
CreateRoom(room);
|
||||||
|
|
||||||
|
currentRoomId++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
147
osu.Game/Tests/Visual/OnlinePlay/TestRoomRequestsHandler.cs
Normal file
147
osu.Game/Tests/Visual/OnlinePlay/TestRoomRequestsHandler.cs
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Game.Online.API;
|
||||||
|
using osu.Game.Online.API.Requests;
|
||||||
|
using osu.Game.Online.Rooms;
|
||||||
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
using osu.Game.Scoring;
|
||||||
|
using osu.Game.Screens.OnlinePlay.Components;
|
||||||
|
using osu.Game.Users;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.Visual.OnlinePlay
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a handler which pretends to be a server, handling room retrieval and manipulation requests
|
||||||
|
/// and returning a roughly expected state, without the need for a server to be running.
|
||||||
|
/// </summary>
|
||||||
|
public class TestRoomRequestsHandler
|
||||||
|
{
|
||||||
|
public IReadOnlyList<Room> ServerSideRooms => serverSideRooms;
|
||||||
|
|
||||||
|
private readonly List<Room> serverSideRooms = new List<Room>();
|
||||||
|
|
||||||
|
private int currentRoomId;
|
||||||
|
private int currentPlaylistItemId;
|
||||||
|
private int currentScoreId;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles an API request, while also updating the local state to match
|
||||||
|
/// how the server would eventually respond and update an <see cref="RoomManager"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="request">The API request to handle.</param>
|
||||||
|
/// <param name="localUser">The local user to store in responses where required.</param>
|
||||||
|
/// <param name="game">The game base for cases where actual online requests need to be sent.</param>
|
||||||
|
/// <returns>Whether the request was successfully handled.</returns>
|
||||||
|
public bool HandleRequest(APIRequest request, User localUser, OsuGameBase game)
|
||||||
|
{
|
||||||
|
switch (request)
|
||||||
|
{
|
||||||
|
case CreateRoomRequest createRoomRequest:
|
||||||
|
var apiRoom = new Room();
|
||||||
|
|
||||||
|
apiRoom.CopyFrom(createRoomRequest.Room);
|
||||||
|
|
||||||
|
// Passwords are explicitly not copied between rooms.
|
||||||
|
apiRoom.HasPassword.Value = !string.IsNullOrEmpty(createRoomRequest.Room.Password.Value);
|
||||||
|
apiRoom.Password.Value = createRoomRequest.Room.Password.Value;
|
||||||
|
|
||||||
|
AddServerSideRoom(apiRoom);
|
||||||
|
|
||||||
|
var responseRoom = new APICreatedRoom();
|
||||||
|
responseRoom.CopyFrom(createResponseRoom(apiRoom, false));
|
||||||
|
|
||||||
|
createRoomRequest.TriggerSuccess(responseRoom);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case JoinRoomRequest joinRoomRequest:
|
||||||
|
{
|
||||||
|
var room = ServerSideRooms.Single(r => r.RoomID.Value == joinRoomRequest.Room.RoomID.Value);
|
||||||
|
|
||||||
|
if (joinRoomRequest.Password != room.Password.Value)
|
||||||
|
{
|
||||||
|
joinRoomRequest.TriggerFailure(new InvalidOperationException("Invalid password."));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
joinRoomRequest.TriggerSuccess();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
case PartRoomRequest partRoomRequest:
|
||||||
|
partRoomRequest.TriggerSuccess();
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case GetRoomsRequest getRoomsRequest:
|
||||||
|
var roomsWithoutParticipants = new List<Room>();
|
||||||
|
|
||||||
|
foreach (var r in ServerSideRooms)
|
||||||
|
roomsWithoutParticipants.Add(createResponseRoom(r, false));
|
||||||
|
|
||||||
|
getRoomsRequest.TriggerSuccess(roomsWithoutParticipants);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case GetRoomRequest getRoomRequest:
|
||||||
|
getRoomRequest.TriggerSuccess(createResponseRoom(ServerSideRooms.Single(r => r.RoomID.Value == getRoomRequest.RoomId), true));
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case GetBeatmapSetRequest getBeatmapSetRequest:
|
||||||
|
var onlineReq = new GetBeatmapSetRequest(getBeatmapSetRequest.ID, getBeatmapSetRequest.Type);
|
||||||
|
onlineReq.Success += res => getBeatmapSetRequest.TriggerSuccess(res);
|
||||||
|
onlineReq.Failure += e => getBeatmapSetRequest.TriggerFailure(e);
|
||||||
|
|
||||||
|
// Get the online API from the game's dependencies.
|
||||||
|
game.Dependencies.Get<IAPIProvider>().Queue(onlineReq);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case CreateRoomScoreRequest createRoomScoreRequest:
|
||||||
|
createRoomScoreRequest.TriggerSuccess(new APIScoreToken { ID = 1 });
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case SubmitRoomScoreRequest submitRoomScoreRequest:
|
||||||
|
submitRoomScoreRequest.TriggerSuccess(new MultiplayerScore
|
||||||
|
{
|
||||||
|
ID = currentScoreId++,
|
||||||
|
Accuracy = 1,
|
||||||
|
EndedAt = DateTimeOffset.Now,
|
||||||
|
Passed = true,
|
||||||
|
Rank = ScoreRank.S,
|
||||||
|
MaxCombo = 1000,
|
||||||
|
TotalScore = 1000000,
|
||||||
|
User = localUser,
|
||||||
|
Statistics = new Dictionary<HitResult, int>()
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a room to a local "server-side" list that's returned when a <see cref="GetRoomsRequest"/> is fired.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="room">The room.</param>
|
||||||
|
public void AddServerSideRoom(Room room)
|
||||||
|
{
|
||||||
|
room.RoomID.Value ??= currentRoomId++;
|
||||||
|
for (int i = 0; i < room.Playlist.Count; i++)
|
||||||
|
room.Playlist[i].ID = currentPlaylistItemId++;
|
||||||
|
|
||||||
|
serverSideRooms.Add(room);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Room createResponseRoom(Room room, bool withParticipants)
|
||||||
|
{
|
||||||
|
var responseRoom = new Room();
|
||||||
|
responseRoom.CopyFrom(room);
|
||||||
|
responseRoom.Password.Value = null;
|
||||||
|
if (!withParticipants)
|
||||||
|
responseRoom.RecentParticipants.Clear();
|
||||||
|
return responseRoom;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -36,7 +36,7 @@
|
|||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Realm" Version="10.3.0" />
|
<PackageReference Include="Realm" Version="10.3.0" />
|
||||||
<PackageReference Include="ppy.osu.Framework" Version="2021.813.0" />
|
<PackageReference Include="ppy.osu.Framework" Version="2021.818.0" />
|
||||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.813.0" />
|
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.813.0" />
|
||||||
<PackageReference Include="Sentry" Version="3.8.3" />
|
<PackageReference Include="Sentry" Version="3.8.3" />
|
||||||
<PackageReference Include="SharpCompress" Version="0.28.3" />
|
<PackageReference Include="SharpCompress" Version="0.28.3" />
|
||||||
|
@ -70,7 +70,7 @@
|
|||||||
<Reference Include="System.Net.Http" />
|
<Reference Include="System.Net.Http" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup Label="Package References">
|
<ItemGroup Label="Package References">
|
||||||
<PackageReference Include="ppy.osu.Framework.iOS" Version="2021.813.0" />
|
<PackageReference Include="ppy.osu.Framework.iOS" Version="2021.818.0" />
|
||||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.813.0" />
|
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.813.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<!-- See https://github.com/dotnet/runtime/issues/35988 (can be removed after Xamarin uses net5.0 / net6.0) -->
|
<!-- 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" Version="2.2.6" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||||
<PackageReference Include="ppy.osu.Framework" Version="2021.813.0" />
|
<PackageReference Include="ppy.osu.Framework" Version="2021.818.0" />
|
||||||
<PackageReference Include="SharpCompress" Version="0.28.3" />
|
<PackageReference Include="SharpCompress" Version="0.28.3" />
|
||||||
<PackageReference Include="NUnit" Version="3.13.2" />
|
<PackageReference Include="NUnit" Version="3.13.2" />
|
||||||
<PackageReference Include="SharpRaven" Version="2.4.0" />
|
<PackageReference Include="SharpRaven" Version="2.4.0" />
|
||||||
|
Reference in New Issue
Block a user