mirror of
https://github.com/ppy/osu.git
synced 2025-02-21 03:02:54 +08:00
Merge branch 'master' into fix-password-popover-back-button
This commit is contained in:
commit
addba43e7d
@ -4,6 +4,7 @@
|
|||||||
using BenchmarkDotNet.Attributes;
|
using BenchmarkDotNet.Attributes;
|
||||||
using BenchmarkDotNet.Engines;
|
using BenchmarkDotNet.Engines;
|
||||||
using osu.Game.Online.API;
|
using osu.Game.Online.API;
|
||||||
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.Osu;
|
using osu.Game.Rulesets.Osu;
|
||||||
|
|
||||||
namespace osu.Game.Benchmarks
|
namespace osu.Game.Benchmarks
|
||||||
@ -37,7 +38,25 @@ namespace osu.Game.Benchmarks
|
|||||||
[Benchmark]
|
[Benchmark]
|
||||||
public void BenchmarkGetAllMods()
|
public void BenchmarkGetAllMods()
|
||||||
{
|
{
|
||||||
ruleset.GetAllMods().Consume(new Consumer());
|
ruleset.CreateAllMods().Consume(new Consumer());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public void BenchmarkGetAllModsForReference()
|
||||||
|
{
|
||||||
|
ruleset.AllMods.Consume(new Consumer());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public void BenchmarkGetForAcronym()
|
||||||
|
{
|
||||||
|
ruleset.CreateModFromAcronym("DT");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public void BenchmarkGetForType()
|
||||||
|
{
|
||||||
|
ruleset.CreateMod<ModDoubleTime>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Game.Online.API;
|
using osu.Game.Online.API;
|
||||||
|
using osu.Game.Rulesets.Osu;
|
||||||
using osu.Game.Rulesets.Osu.Mods;
|
using osu.Game.Rulesets.Osu.Mods;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Mods
|
namespace osu.Game.Tests.Mods
|
||||||
@ -11,26 +12,42 @@ namespace osu.Game.Tests.Mods
|
|||||||
public class ModSettingsEqualityComparison
|
public class ModSettingsEqualityComparison
|
||||||
{
|
{
|
||||||
[Test]
|
[Test]
|
||||||
public void Test()
|
public void TestAPIMod()
|
||||||
{
|
{
|
||||||
|
var apiMod1 = new APIMod(new OsuModDoubleTime { SpeedChange = { Value = 1.25 } });
|
||||||
|
var apiMod2 = new APIMod(new OsuModDoubleTime { SpeedChange = { Value = 1.26 } });
|
||||||
|
var apiMod3 = new APIMod(new OsuModDoubleTime { SpeedChange = { Value = 1.26 } });
|
||||||
|
|
||||||
|
Assert.That(apiMod1, Is.Not.EqualTo(apiMod2));
|
||||||
|
Assert.That(apiMod2, Is.EqualTo(apiMod2));
|
||||||
|
Assert.That(apiMod2, Is.EqualTo(apiMod3));
|
||||||
|
Assert.That(apiMod3, Is.EqualTo(apiMod2));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestMod()
|
||||||
|
{
|
||||||
|
var ruleset = new OsuRuleset();
|
||||||
|
|
||||||
var mod1 = new OsuModDoubleTime { SpeedChange = { Value = 1.25 } };
|
var mod1 = new OsuModDoubleTime { SpeedChange = { Value = 1.25 } };
|
||||||
var mod2 = new OsuModDoubleTime { SpeedChange = { Value = 1.26 } };
|
var mod2 = new OsuModDoubleTime { SpeedChange = { Value = 1.26 } };
|
||||||
var mod3 = new OsuModDoubleTime { SpeedChange = { Value = 1.26 } };
|
var mod3 = new OsuModDoubleTime { SpeedChange = { Value = 1.26 } };
|
||||||
var apiMod1 = new APIMod(mod1);
|
|
||||||
var apiMod2 = new APIMod(mod2);
|
var doubleConvertedMod1 = new APIMod(mod1).ToMod(ruleset);
|
||||||
var apiMod3 = new APIMod(mod3);
|
var doulbeConvertedMod2 = new APIMod(mod2).ToMod(ruleset);
|
||||||
|
var doulbeConvertedMod3 = new APIMod(mod3).ToMod(ruleset);
|
||||||
|
|
||||||
Assert.That(mod1, Is.Not.EqualTo(mod2));
|
Assert.That(mod1, Is.Not.EqualTo(mod2));
|
||||||
Assert.That(apiMod1, Is.Not.EqualTo(apiMod2));
|
Assert.That(doubleConvertedMod1, Is.Not.EqualTo(doulbeConvertedMod2));
|
||||||
|
|
||||||
Assert.That(mod2, Is.EqualTo(mod2));
|
Assert.That(mod2, Is.EqualTo(mod2));
|
||||||
Assert.That(apiMod2, Is.EqualTo(apiMod2));
|
Assert.That(doulbeConvertedMod2, Is.EqualTo(doulbeConvertedMod2));
|
||||||
|
|
||||||
Assert.That(mod2, Is.EqualTo(mod3));
|
Assert.That(mod2, Is.EqualTo(mod3));
|
||||||
Assert.That(apiMod2, Is.EqualTo(apiMod3));
|
Assert.That(doulbeConvertedMod2, Is.EqualTo(doulbeConvertedMod3));
|
||||||
|
|
||||||
Assert.That(mod3, Is.EqualTo(mod2));
|
Assert.That(mod3, Is.EqualTo(mod2));
|
||||||
Assert.That(apiMod3, Is.EqualTo(apiMod2));
|
Assert.That(doulbeConvertedMod3, Is.EqualTo(doulbeConvertedMod2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
// 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.Linq;
|
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
@ -71,7 +70,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
var working = CreateWorkingBeatmap(rulesetInfo);
|
var working = CreateWorkingBeatmap(rulesetInfo);
|
||||||
|
|
||||||
Beatmap.Value = working;
|
Beatmap.Value = working;
|
||||||
SelectedMods.Value = new[] { ruleset.GetAllMods().First(m => m is ModNoFail) };
|
SelectedMods.Value = new[] { ruleset.CreateMod<ModNoFail>() };
|
||||||
|
|
||||||
Player = CreatePlayer(ruleset);
|
Player = CreatePlayer(ruleset);
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@ using osu.Game.Overlays.Mods;
|
|||||||
using osu.Game.Overlays.Toolbar;
|
using osu.Game.Overlays.Toolbar;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.Osu.Mods;
|
using osu.Game.Rulesets.Osu.Mods;
|
||||||
|
using osu.Game.Screens.Menu;
|
||||||
using osu.Game.Screens.OnlinePlay.Components;
|
using osu.Game.Screens.OnlinePlay.Components;
|
||||||
using osu.Game.Screens.OnlinePlay.Lounge;
|
using osu.Game.Screens.OnlinePlay.Lounge;
|
||||||
using osu.Game.Screens.Play;
|
using osu.Game.Screens.Play;
|
||||||
@ -388,6 +389,19 @@ namespace osu.Game.Tests.Visual.Navigation
|
|||||||
AddAssert("now playing is hidden", () => nowPlayingOverlay.State.Value == Visibility.Hidden);
|
AddAssert("now playing is hidden", () => nowPlayingOverlay.State.Value == Visibility.Hidden);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestExitGameFromSongSelect()
|
||||||
|
{
|
||||||
|
PushAndConfirm(() => new TestPlaySongSelect());
|
||||||
|
exitViaEscapeAndConfirm();
|
||||||
|
|
||||||
|
pushEscape(); // returns to osu! logo
|
||||||
|
|
||||||
|
AddStep("Hold escape", () => InputManager.PressKey(Key.Escape));
|
||||||
|
AddUntilStep("Wait for intro", () => Game.ScreenStack.CurrentScreen is IntroTriangles);
|
||||||
|
AddUntilStep("Wait for game exit", () => Game.ScreenStack.CurrentScreen == null);
|
||||||
|
}
|
||||||
|
|
||||||
private void pushEscape() =>
|
private void pushEscape() =>
|
||||||
AddStep("Press escape", () => InputManager.Key(Key.Escape));
|
AddStep("Press escape", () => InputManager.Key(Key.Escape));
|
||||||
|
|
||||||
|
@ -5,10 +5,10 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Allocation;
|
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Graphics.UserInterface;
|
||||||
using osu.Game.Online.API;
|
using osu.Game.Online.API;
|
||||||
using osu.Game.Online.API.Requests;
|
using osu.Game.Online.API.Requests;
|
||||||
using osu.Game.Online.API.Requests.Responses;
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
@ -17,10 +17,11 @@ using osu.Game.Overlays.BeatmapListing;
|
|||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Scoring;
|
using osu.Game.Scoring;
|
||||||
using osu.Game.Users;
|
using osu.Game.Users;
|
||||||
|
using osuTK.Input;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual.Online
|
namespace osu.Game.Tests.Visual.Online
|
||||||
{
|
{
|
||||||
public class TestSceneBeatmapListingOverlay : OsuTestScene
|
public class TestSceneBeatmapListingOverlay : OsuManualInputManagerTestScene
|
||||||
{
|
{
|
||||||
private readonly List<APIBeatmapSet> setsForResponse = new List<APIBeatmapSet>();
|
private readonly List<APIBeatmapSet> setsForResponse = new List<APIBeatmapSet>();
|
||||||
|
|
||||||
@ -28,27 +29,33 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
|
|
||||||
private BeatmapListingSearchControl searchControl => overlay.ChildrenOfType<BeatmapListingSearchControl>().Single();
|
private BeatmapListingSearchControl searchControl => overlay.ChildrenOfType<BeatmapListingSearchControl>().Single();
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[SetUpSteps]
|
||||||
private void load()
|
public void SetUpSteps()
|
||||||
{
|
{
|
||||||
Child = overlay = new BeatmapListingOverlay { State = { Value = Visibility.Visible } };
|
AddStep("setup overlay", () =>
|
||||||
|
|
||||||
((DummyAPIAccess)API).HandleRequest = req =>
|
|
||||||
{
|
{
|
||||||
if (!(req is SearchBeatmapSetsRequest searchBeatmapSetsRequest)) return false;
|
Child = overlay = new BeatmapListingOverlay { State = { Value = Visibility.Visible } };
|
||||||
|
setsForResponse.Clear();
|
||||||
searchBeatmapSetsRequest.TriggerSuccess(new SearchBeatmapSetsResponse
|
});
|
||||||
{
|
|
||||||
BeatmapSets = setsForResponse,
|
|
||||||
});
|
|
||||||
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
AddStep("initialize dummy", () =>
|
AddStep("initialize dummy", () =>
|
||||||
{
|
{
|
||||||
|
var api = (DummyAPIAccess)API;
|
||||||
|
|
||||||
|
api.HandleRequest = req =>
|
||||||
|
{
|
||||||
|
if (!(req is SearchBeatmapSetsRequest searchBeatmapSetsRequest)) return false;
|
||||||
|
|
||||||
|
searchBeatmapSetsRequest.TriggerSuccess(new SearchBeatmapSetsResponse
|
||||||
|
{
|
||||||
|
BeatmapSets = setsForResponse,
|
||||||
|
});
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
// non-supporter user
|
// non-supporter user
|
||||||
((DummyAPIAccess)API).LocalUser.Value = new User
|
api.LocalUser.Value = new User
|
||||||
{
|
{
|
||||||
Username = "TestBot",
|
Username = "TestBot",
|
||||||
Id = API.LocalUser.Value.Id + 1,
|
Id = API.LocalUser.Value.Id + 1,
|
||||||
@ -56,6 +63,51 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestHideViaBack()
|
||||||
|
{
|
||||||
|
AddAssert("is visible", () => overlay.State.Value == Visibility.Visible);
|
||||||
|
AddStep("hide", () => InputManager.Key(Key.Escape));
|
||||||
|
AddUntilStep("is hidden", () => overlay.State.Value == Visibility.Hidden);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestHideViaBackWithSearch()
|
||||||
|
{
|
||||||
|
AddAssert("is visible", () => overlay.State.Value == Visibility.Visible);
|
||||||
|
|
||||||
|
AddStep("search something", () => overlay.ChildrenOfType<SearchTextBox>().First().Text = "search");
|
||||||
|
|
||||||
|
AddStep("kill search", () => InputManager.Key(Key.Escape));
|
||||||
|
|
||||||
|
AddAssert("search textbox empty", () => string.IsNullOrEmpty(overlay.ChildrenOfType<SearchTextBox>().First().Text));
|
||||||
|
AddAssert("is visible", () => overlay.State.Value == Visibility.Visible);
|
||||||
|
|
||||||
|
AddStep("hide", () => InputManager.Key(Key.Escape));
|
||||||
|
AddUntilStep("is hidden", () => overlay.State.Value == Visibility.Hidden);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestHideViaBackWithScrolledSearch()
|
||||||
|
{
|
||||||
|
AddAssert("is visible", () => overlay.State.Value == Visibility.Visible);
|
||||||
|
|
||||||
|
AddStep("show many results", () => fetchFor(Enumerable.Repeat(CreateBeatmap(Ruleset.Value).BeatmapInfo.BeatmapSet, 100).ToArray()));
|
||||||
|
|
||||||
|
AddUntilStep("placeholder hidden", () => !overlay.ChildrenOfType<BeatmapListingOverlay.NotFoundDrawable>().Any(d => d.IsPresent));
|
||||||
|
|
||||||
|
AddStep("scroll to bottom", () => overlay.ChildrenOfType<OverlayScrollContainer>().First().ScrollToEnd());
|
||||||
|
|
||||||
|
AddStep("kill search", () => InputManager.Key(Key.Escape));
|
||||||
|
|
||||||
|
AddUntilStep("search textbox empty", () => string.IsNullOrEmpty(overlay.ChildrenOfType<SearchTextBox>().First().Text));
|
||||||
|
AddUntilStep("is scrolled to top", () => overlay.ChildrenOfType<OverlayScrollContainer>().First().Current == 0);
|
||||||
|
AddAssert("is visible", () => overlay.State.Value == Visibility.Visible);
|
||||||
|
|
||||||
|
AddStep("hide", () => InputManager.Key(Key.Escape));
|
||||||
|
AddUntilStep("is hidden", () => overlay.State.Value == Visibility.Hidden);
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestNoBeatmapsPlaceholder()
|
public void TestNoBeatmapsPlaceholder()
|
||||||
{
|
{
|
||||||
@ -63,7 +115,7 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
AddUntilStep("placeholder shown", () => overlay.ChildrenOfType<BeatmapListingOverlay.NotFoundDrawable>().SingleOrDefault()?.IsPresent == true);
|
AddUntilStep("placeholder shown", () => overlay.ChildrenOfType<BeatmapListingOverlay.NotFoundDrawable>().SingleOrDefault()?.IsPresent == true);
|
||||||
|
|
||||||
AddStep("fetch for 1 beatmap", () => fetchFor(CreateBeatmap(Ruleset.Value).BeatmapInfo.BeatmapSet));
|
AddStep("fetch for 1 beatmap", () => fetchFor(CreateBeatmap(Ruleset.Value).BeatmapInfo.BeatmapSet));
|
||||||
AddUntilStep("placeholder hidden", () => !overlay.ChildrenOfType<BeatmapListingOverlay.NotFoundDrawable>().Any());
|
AddUntilStep("placeholder hidden", () => !overlay.ChildrenOfType<BeatmapListingOverlay.NotFoundDrawable>().Any(d => d.IsPresent));
|
||||||
|
|
||||||
AddStep("fetch for 0 beatmaps", () => fetchFor());
|
AddStep("fetch for 0 beatmaps", () => fetchFor());
|
||||||
AddUntilStep("placeholder shown", () => overlay.ChildrenOfType<BeatmapListingOverlay.NotFoundDrawable>().SingleOrDefault()?.IsPresent == true);
|
AddUntilStep("placeholder shown", () => overlay.ChildrenOfType<BeatmapListingOverlay.NotFoundDrawable>().SingleOrDefault()?.IsPresent == true);
|
||||||
@ -193,13 +245,15 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
noPlaceholderShown();
|
noPlaceholderShown();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static int searchCount;
|
||||||
|
|
||||||
private void fetchFor(params BeatmapSetInfo[] beatmaps)
|
private void fetchFor(params BeatmapSetInfo[] beatmaps)
|
||||||
{
|
{
|
||||||
setsForResponse.Clear();
|
setsForResponse.Clear();
|
||||||
setsForResponse.AddRange(beatmaps.Select(b => new TestAPIBeatmapSet(b)));
|
setsForResponse.AddRange(beatmaps.Select(b => new TestAPIBeatmapSet(b)));
|
||||||
|
|
||||||
// trigger arbitrary change for fetching.
|
// trigger arbitrary change for fetching.
|
||||||
searchControl.Query.TriggerChange();
|
searchControl.Query.Value = $"search {searchCount++}";
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setRankAchievedFilter(ScoreRank[] ranks)
|
private void setRankAchievedFilter(ScoreRank[] ranks)
|
||||||
@ -229,8 +283,8 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
private void noPlaceholderShown()
|
private void noPlaceholderShown()
|
||||||
{
|
{
|
||||||
AddUntilStep("no placeholder shown", () =>
|
AddUntilStep("no placeholder shown", () =>
|
||||||
!overlay.ChildrenOfType<BeatmapListingOverlay.SupporterRequiredDrawable>().Any()
|
!overlay.ChildrenOfType<BeatmapListingOverlay.SupporterRequiredDrawable>().Any(d => d.IsPresent)
|
||||||
&& !overlay.ChildrenOfType<BeatmapListingOverlay.NotFoundDrawable>().Any());
|
&& !overlay.ChildrenOfType<BeatmapListingOverlay.NotFoundDrawable>().Any(d => d.IsPresent));
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TestAPIBeatmapSet : APIBeatmapSet
|
private class TestAPIBeatmapSet : APIBeatmapSet
|
||||||
|
@ -21,6 +21,8 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
|
|
||||||
protected override bool UseOnlineAPI => true;
|
protected override bool UseOnlineAPI => true;
|
||||||
|
|
||||||
|
private int nextBeatmapSetId = 1;
|
||||||
|
|
||||||
public TestSceneBeatmapSetOverlay()
|
public TestSceneBeatmapSetOverlay()
|
||||||
{
|
{
|
||||||
Add(overlay = new TestBeatmapSetOverlay());
|
Add(overlay = new TestBeatmapSetOverlay());
|
||||||
@ -240,12 +242,23 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
{
|
{
|
||||||
AddStep("show explicit map", () =>
|
AddStep("show explicit map", () =>
|
||||||
{
|
{
|
||||||
var beatmapSet = CreateBeatmap(Ruleset.Value).BeatmapInfo.BeatmapSet;
|
var beatmapSet = getBeatmapSet();
|
||||||
beatmapSet.OnlineInfo.HasExplicitContent = true;
|
beatmapSet.OnlineInfo.HasExplicitContent = true;
|
||||||
overlay.ShowBeatmapSet(beatmapSet);
|
overlay.ShowBeatmapSet(beatmapSet);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestFeaturedBeatmap()
|
||||||
|
{
|
||||||
|
AddStep("show featured map", () =>
|
||||||
|
{
|
||||||
|
var beatmapSet = getBeatmapSet();
|
||||||
|
beatmapSet.OnlineInfo.TrackId = 1;
|
||||||
|
overlay.ShowBeatmapSet(beatmapSet);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestHide()
|
public void TestHide()
|
||||||
{
|
{
|
||||||
@ -308,6 +321,14 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private BeatmapSetInfo getBeatmapSet()
|
||||||
|
{
|
||||||
|
var beatmapSet = CreateBeatmap(Ruleset.Value).BeatmapInfo.BeatmapSet;
|
||||||
|
// Make sure the overlay is reloaded (see `BeatmapSetInfo.Equals`).
|
||||||
|
beatmapSet.OnlineBeatmapSetID = nextBeatmapSetId++;
|
||||||
|
return beatmapSet;
|
||||||
|
}
|
||||||
|
|
||||||
private void downloadAssert(bool shown)
|
private void downloadAssert(bool shown)
|
||||||
{
|
{
|
||||||
AddAssert($"is download button {(shown ? "shown" : "hidden")}", () => overlay.Header.HeaderContent.DownloadButtonsVisible == shown);
|
AddAssert($"is download button {(shown ? "shown" : "hidden")}", () => overlay.Header.HeaderContent.DownloadButtonsVisible == shown);
|
||||||
|
@ -99,16 +99,23 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(RulesetStore rulesets)
|
private void load(RulesetStore rulesets)
|
||||||
{
|
{
|
||||||
var normal = CreateBeatmap(Ruleset.Value).BeatmapInfo.BeatmapSet;
|
var normal = getBeatmapSet();
|
||||||
normal.OnlineInfo.HasVideo = true;
|
normal.OnlineInfo.HasVideo = true;
|
||||||
normal.OnlineInfo.HasStoryboard = true;
|
normal.OnlineInfo.HasStoryboard = true;
|
||||||
|
|
||||||
var undownloadable = getUndownloadableBeatmapSet();
|
var undownloadable = getUndownloadableBeatmapSet();
|
||||||
var manyDifficulties = getManyDifficultiesBeatmapSet(rulesets);
|
var manyDifficulties = getManyDifficultiesBeatmapSet(rulesets);
|
||||||
|
|
||||||
var explicitMap = CreateBeatmap(Ruleset.Value).BeatmapInfo.BeatmapSet;
|
var explicitMap = getBeatmapSet();
|
||||||
explicitMap.OnlineInfo.HasExplicitContent = true;
|
explicitMap.OnlineInfo.HasExplicitContent = true;
|
||||||
|
|
||||||
|
var featuredMap = getBeatmapSet();
|
||||||
|
featuredMap.OnlineInfo.TrackId = 1;
|
||||||
|
|
||||||
|
var explicitFeaturedMap = getBeatmapSet();
|
||||||
|
explicitFeaturedMap.OnlineInfo.HasExplicitContent = true;
|
||||||
|
explicitFeaturedMap.OnlineInfo.TrackId = 2;
|
||||||
|
|
||||||
Child = new BasicScrollContainer
|
Child = new BasicScrollContainer
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
@ -125,13 +132,19 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
new GridBeatmapPanel(undownloadable),
|
new GridBeatmapPanel(undownloadable),
|
||||||
new GridBeatmapPanel(manyDifficulties),
|
new GridBeatmapPanel(manyDifficulties),
|
||||||
new GridBeatmapPanel(explicitMap),
|
new GridBeatmapPanel(explicitMap),
|
||||||
|
new GridBeatmapPanel(featuredMap),
|
||||||
|
new GridBeatmapPanel(explicitFeaturedMap),
|
||||||
new ListBeatmapPanel(normal),
|
new ListBeatmapPanel(normal),
|
||||||
new ListBeatmapPanel(undownloadable),
|
new ListBeatmapPanel(undownloadable),
|
||||||
new ListBeatmapPanel(manyDifficulties),
|
new ListBeatmapPanel(manyDifficulties),
|
||||||
new ListBeatmapPanel(explicitMap)
|
new ListBeatmapPanel(explicitMap),
|
||||||
|
new ListBeatmapPanel(featuredMap),
|
||||||
|
new ListBeatmapPanel(explicitFeaturedMap)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
BeatmapSetInfo getBeatmapSet() => CreateBeatmap(Ruleset.Value).BeatmapInfo.BeatmapSet;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -89,7 +89,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
AddStep("select EZ mod", () =>
|
AddStep("select EZ mod", () =>
|
||||||
{
|
{
|
||||||
var ruleset = advancedStats.Beatmap.Ruleset.CreateInstance();
|
var ruleset = advancedStats.Beatmap.Ruleset.CreateInstance();
|
||||||
SelectedMods.Value = new[] { ruleset.GetAllMods().OfType<ModEasy>().Single() };
|
SelectedMods.Value = new[] { ruleset.CreateMod<ModEasy>() };
|
||||||
});
|
});
|
||||||
|
|
||||||
AddAssert("circle size bar is blue", () => barIsBlue(advancedStats.FirstValue));
|
AddAssert("circle size bar is blue", () => barIsBlue(advancedStats.FirstValue));
|
||||||
@ -106,7 +106,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
AddStep("select HR mod", () =>
|
AddStep("select HR mod", () =>
|
||||||
{
|
{
|
||||||
var ruleset = advancedStats.Beatmap.Ruleset.CreateInstance();
|
var ruleset = advancedStats.Beatmap.Ruleset.CreateInstance();
|
||||||
SelectedMods.Value = new[] { ruleset.GetAllMods().OfType<ModHardRock>().Single() };
|
SelectedMods.Value = new[] { ruleset.CreateMod<ModHardRock>() };
|
||||||
});
|
});
|
||||||
|
|
||||||
AddAssert("circle size bar is red", () => barIsRed(advancedStats.FirstValue));
|
AddAssert("circle size bar is red", () => barIsRed(advancedStats.FirstValue));
|
||||||
@ -123,7 +123,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
AddStep("select unchanged Difficulty Adjust mod", () =>
|
AddStep("select unchanged Difficulty Adjust mod", () =>
|
||||||
{
|
{
|
||||||
var ruleset = advancedStats.Beatmap.Ruleset.CreateInstance();
|
var ruleset = advancedStats.Beatmap.Ruleset.CreateInstance();
|
||||||
var difficultyAdjustMod = ruleset.GetAllMods().OfType<ModDifficultyAdjust>().Single();
|
var difficultyAdjustMod = ruleset.CreateMod<ModDifficultyAdjust>();
|
||||||
difficultyAdjustMod.ReadFromDifficulty(advancedStats.Beatmap.BaseDifficulty);
|
difficultyAdjustMod.ReadFromDifficulty(advancedStats.Beatmap.BaseDifficulty);
|
||||||
SelectedMods.Value = new[] { difficultyAdjustMod };
|
SelectedMods.Value = new[] { difficultyAdjustMod };
|
||||||
});
|
});
|
||||||
@ -142,7 +142,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
AddStep("select changed Difficulty Adjust mod", () =>
|
AddStep("select changed Difficulty Adjust mod", () =>
|
||||||
{
|
{
|
||||||
var ruleset = advancedStats.Beatmap.Ruleset.CreateInstance();
|
var ruleset = advancedStats.Beatmap.Ruleset.CreateInstance();
|
||||||
var difficultyAdjustMod = ruleset.GetAllMods().OfType<OsuModDifficultyAdjust>().Single();
|
var difficultyAdjustMod = ruleset.CreateMod<OsuModDifficultyAdjust>();
|
||||||
var originalDifficulty = advancedStats.Beatmap.BaseDifficulty;
|
var originalDifficulty = advancedStats.Beatmap.BaseDifficulty;
|
||||||
|
|
||||||
difficultyAdjustMod.ReadFromDifficulty(originalDifficulty);
|
difficultyAdjustMod.ReadFromDifficulty(originalDifficulty);
|
||||||
|
@ -92,7 +92,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
{
|
{
|
||||||
AddStep("setup display", () =>
|
AddStep("setup display", () =>
|
||||||
{
|
{
|
||||||
var randomMods = Ruleset.Value.CreateInstance().GetAllMods().OrderBy(_ => RNG.Next()).Take(5).ToList();
|
var randomMods = Ruleset.Value.CreateInstance().CreateAllMods().OrderBy(_ => RNG.Next()).Take(5).ToList();
|
||||||
|
|
||||||
OsuLogo logo = new OsuLogo { Scale = new Vector2(0.15f) };
|
OsuLogo logo = new OsuLogo { Scale = new Vector2(0.15f) };
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
Width = 200,
|
Width = 200,
|
||||||
Current =
|
Current =
|
||||||
{
|
{
|
||||||
Value = new OsuRuleset().GetAllMods().ToArray(),
|
Value = new OsuRuleset().CreateAllMods().ToArray(),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
// 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.Linq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
using osu.Game.Rulesets.Osu;
|
||||||
using osu.Game.Rulesets.Osu.Mods;
|
using osu.Game.Rulesets.Osu.Mods;
|
||||||
using osu.Game.Rulesets.UI;
|
using osu.Game.Rulesets.UI;
|
||||||
|
|
||||||
@ -17,5 +19,16 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
AddStep("create mod icon", () => Child = icon = new ModIcon(new OsuModDoubleTime()));
|
AddStep("create mod icon", () => Child = icon = new ModIcon(new OsuModDoubleTime()));
|
||||||
AddStep("change mod", () => icon.Mod = new OsuModEasy());
|
AddStep("change mod", () => icon.Mod = new OsuModEasy());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestInterfaceModType()
|
||||||
|
{
|
||||||
|
ModIcon icon = null;
|
||||||
|
|
||||||
|
var ruleset = new OsuRuleset();
|
||||||
|
|
||||||
|
AddStep("create mod icon", () => Child = icon = new ModIcon(ruleset.AllMods.First(m => m.Acronym == "DT")));
|
||||||
|
AddStep("change mod", () => icon.Mod = ruleset.AllMods.First(m => m.Acronym == "EZ"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -158,8 +158,8 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
var mania = new ManiaRuleset();
|
var mania = new ManiaRuleset();
|
||||||
|
|
||||||
testModsWithSameBaseType(
|
testModsWithSameBaseType(
|
||||||
mania.GetAllMods().Single(m => m.GetType() == typeof(ManiaModFadeIn)),
|
mania.CreateMod<ManiaModFadeIn>(),
|
||||||
mania.GetAllMods().Single(m => m.GetType() == typeof(ManiaModHidden)));
|
mania.CreateMod<ManiaModHidden>());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
@ -45,7 +45,7 @@ namespace osu.Game.Tournament.Tests.Components
|
|||||||
private void success(APIBeatmap apiBeatmap)
|
private void success(APIBeatmap apiBeatmap)
|
||||||
{
|
{
|
||||||
beatmap = apiBeatmap.ToBeatmap(rulesets);
|
beatmap = apiBeatmap.ToBeatmap(rulesets);
|
||||||
var mods = rulesets.GetRuleset(Ladder.Ruleset.Value.ID ?? 0).CreateInstance().GetAllMods();
|
var mods = rulesets.GetRuleset(Ladder.Ruleset.Value.ID ?? 0).CreateInstance().AllMods;
|
||||||
|
|
||||||
foreach (var mod in mods)
|
foreach (var mod in mods)
|
||||||
{
|
{
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
// 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.Linq;
|
|
||||||
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;
|
||||||
@ -49,7 +48,7 @@ namespace osu.Game.Tournament.Components
|
|||||||
}
|
}
|
||||||
|
|
||||||
var ruleset = rulesets.GetRuleset(ladderInfo.Ruleset.Value?.ID ?? 0);
|
var ruleset = rulesets.GetRuleset(ladderInfo.Ruleset.Value?.ID ?? 0);
|
||||||
var modIcon = ruleset?.CreateInstance().GetAllMods().FirstOrDefault(mod => mod.Acronym == modAcronym);
|
var modIcon = ruleset?.CreateInstance().CreateModFromAcronym(modAcronym);
|
||||||
|
|
||||||
if (modIcon == null)
|
if (modIcon == null)
|
||||||
return;
|
return;
|
||||||
|
@ -90,6 +90,12 @@ namespace osu.Game.Beatmaps
|
|||||||
/// The song language of this beatmap set.
|
/// The song language of this beatmap set.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public BeatmapSetOnlineLanguage Language { get; set; }
|
public BeatmapSetOnlineLanguage Language { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The track ID of this beatmap set.
|
||||||
|
/// Non-null only if the track is linked to a featured artist track entry.
|
||||||
|
/// </summary>
|
||||||
|
public int? TrackId { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class BeatmapSetOnlineGenre
|
public class BeatmapSetOnlineGenre
|
||||||
|
@ -70,7 +70,7 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
return base.OnKeyDown(e);
|
return base.OnKeyDown(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool OnPressed(GlobalAction action)
|
public virtual bool OnPressed(GlobalAction action)
|
||||||
{
|
{
|
||||||
if (!HasFocus) return false;
|
if (!HasFocus) return false;
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ using osu.Game.Utils;
|
|||||||
namespace osu.Game.Online.API
|
namespace osu.Game.Online.API
|
||||||
{
|
{
|
||||||
[MessagePackObject]
|
[MessagePackObject]
|
||||||
public class APIMod : IMod, IEquatable<APIMod>
|
public class APIMod : IEquatable<APIMod>
|
||||||
{
|
{
|
||||||
[JsonProperty("acronym")]
|
[JsonProperty("acronym")]
|
||||||
[Key(0)]
|
[Key(0)]
|
||||||
@ -48,7 +48,7 @@ namespace osu.Game.Online.API
|
|||||||
|
|
||||||
public Mod ToMod(Ruleset ruleset)
|
public Mod ToMod(Ruleset ruleset)
|
||||||
{
|
{
|
||||||
Mod resultMod = ruleset.GetAllMods().FirstOrDefault(m => m.Acronym == Acronym);
|
Mod resultMod = ruleset.CreateModFromAcronym(Acronym);
|
||||||
|
|
||||||
if (resultMod == null)
|
if (resultMod == null)
|
||||||
throw new InvalidOperationException($"There is no mod in the ruleset ({ruleset.ShortName}) matching the acronym {Acronym}.");
|
throw new InvalidOperationException($"There is no mod in the ruleset ({ruleset.ShortName}) matching the acronym {Acronym}.");
|
||||||
@ -67,15 +67,12 @@ namespace osu.Game.Online.API
|
|||||||
return resultMod;
|
return resultMod;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Equals(IMod other) => other is APIMod them && Equals(them);
|
|
||||||
|
|
||||||
public bool Equals(APIMod other)
|
public bool Equals(APIMod other)
|
||||||
{
|
{
|
||||||
if (ReferenceEquals(null, other)) return false;
|
if (ReferenceEquals(null, other)) return false;
|
||||||
if (ReferenceEquals(this, other)) return true;
|
if (ReferenceEquals(this, other)) return true;
|
||||||
|
|
||||||
return Acronym == other.Acronym &&
|
return Acronym == other.Acronym && Settings.SequenceEqual(other.Settings, ModSettingsEqualityComparer.Default);
|
||||||
Settings.SequenceEqual(other.Settings, ModSettingsEqualityComparer.Default);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
|
@ -18,9 +18,9 @@ namespace osu.Game.Online.API.Requests
|
|||||||
private readonly BeatmapInfo beatmap;
|
private readonly BeatmapInfo beatmap;
|
||||||
private readonly BeatmapLeaderboardScope scope;
|
private readonly BeatmapLeaderboardScope scope;
|
||||||
private readonly RulesetInfo ruleset;
|
private readonly RulesetInfo ruleset;
|
||||||
private readonly IEnumerable<Mod> mods;
|
private readonly IEnumerable<IMod> mods;
|
||||||
|
|
||||||
public GetScoresRequest(BeatmapInfo beatmap, RulesetInfo ruleset, BeatmapLeaderboardScope scope = BeatmapLeaderboardScope.Global, IEnumerable<Mod> mods = null)
|
public GetScoresRequest(BeatmapInfo beatmap, RulesetInfo ruleset, BeatmapLeaderboardScope scope = BeatmapLeaderboardScope.Global, IEnumerable<IMod> mods = null)
|
||||||
{
|
{
|
||||||
if (!beatmap.OnlineBeatmapID.HasValue)
|
if (!beatmap.OnlineBeatmapID.HasValue)
|
||||||
throw new InvalidOperationException($"Cannot lookup a beatmap's scores without having a populated {nameof(BeatmapInfo.OnlineBeatmapID)}.");
|
throw new InvalidOperationException($"Cannot lookup a beatmap's scores without having a populated {nameof(BeatmapInfo.OnlineBeatmapID)}.");
|
||||||
@ -31,7 +31,7 @@ namespace osu.Game.Online.API.Requests
|
|||||||
this.beatmap = beatmap;
|
this.beatmap = beatmap;
|
||||||
this.scope = scope;
|
this.scope = scope;
|
||||||
this.ruleset = ruleset ?? throw new ArgumentNullException(nameof(ruleset));
|
this.ruleset = ruleset ?? throw new ArgumentNullException(nameof(ruleset));
|
||||||
this.mods = mods ?? Array.Empty<Mod>();
|
this.mods = mods ?? Array.Empty<IMod>();
|
||||||
|
|
||||||
Success += onSuccess;
|
Success += onSuccess;
|
||||||
}
|
}
|
||||||
|
@ -63,6 +63,9 @@ namespace osu.Game.Online.API.Requests.Responses
|
|||||||
[JsonProperty(@"ratings")]
|
[JsonProperty(@"ratings")]
|
||||||
private int[] ratings { get; set; }
|
private int[] ratings { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty(@"track_id")]
|
||||||
|
private int? trackId { get; set; }
|
||||||
|
|
||||||
[JsonProperty(@"user_id")]
|
[JsonProperty(@"user_id")]
|
||||||
private int creatorId
|
private int creatorId
|
||||||
{
|
{
|
||||||
@ -106,7 +109,8 @@ namespace osu.Game.Online.API.Requests.Responses
|
|||||||
Availability = availability,
|
Availability = availability,
|
||||||
HasFavourited = hasFavourited,
|
HasFavourited = hasFavourited,
|
||||||
Genre = genre,
|
Genre = genre,
|
||||||
Language = language
|
Language = language,
|
||||||
|
TrackId = trackId
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -23,10 +23,10 @@ namespace osu.Game.Online.API.Requests.Responses
|
|||||||
|
|
||||||
var rulesetInstance = ruleset.CreateInstance();
|
var rulesetInstance = ruleset.CreateInstance();
|
||||||
|
|
||||||
var mods = Mods != null ? rulesetInstance.GetAllMods().Where(mod => Mods.Contains(mod.Acronym)).ToArray() : Array.Empty<Mod>();
|
var mods = Mods != null ? Mods.Select(acronym => rulesetInstance.CreateModFromAcronym(acronym)).Where(m => m != null).ToArray() : Array.Empty<Mod>();
|
||||||
|
|
||||||
// all API scores provided by this class are considered to be legacy.
|
// all API scores provided by this class are considered to be legacy.
|
||||||
mods = mods.Append(rulesetInstance.GetAllMods().OfType<ModClassic>().Single()).ToArray();
|
mods = mods.Append(rulesetInstance.CreateMod<ModClassic>()).ToArray();
|
||||||
|
|
||||||
var scoreInfo = new ScoreInfo
|
var scoreInfo = new ScoreInfo
|
||||||
{
|
{
|
||||||
|
@ -3,21 +3,22 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
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.Framework.Graphics.Shapes;
|
||||||
using osuTK;
|
|
||||||
using osu.Framework.Bindables;
|
|
||||||
using osu.Framework.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
using osu.Game.Beatmaps.Drawables;
|
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Beatmaps.Drawables;
|
||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
using osu.Game.Graphics.Containers;
|
using osu.Game.Graphics.Containers;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
|
using osu.Game.Input.Bindings;
|
||||||
using osu.Game.Resources.Localisation.Web;
|
using osu.Game.Resources.Localisation.Web;
|
||||||
using osuTK.Graphics;
|
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Scoring;
|
using osu.Game.Scoring;
|
||||||
|
using osuTK;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Game.Overlays.BeatmapListing
|
namespace osu.Game.Overlays.BeatmapListing
|
||||||
{
|
{
|
||||||
@ -117,7 +118,7 @@ namespace osu.Game.Overlays.BeatmapListing
|
|||||||
textBox = new BeatmapSearchTextBox
|
textBox = new BeatmapSearchTextBox
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
TypingStarted = () => TypingStarted?.Invoke(),
|
TextChanged = () => TypingStarted?.Invoke(),
|
||||||
},
|
},
|
||||||
new ReverseChildIDFillFlowContainer<Drawable>
|
new ReverseChildIDFillFlowContainer<Drawable>
|
||||||
{
|
{
|
||||||
@ -167,7 +168,7 @@ namespace osu.Game.Overlays.BeatmapListing
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Any time the text box receives key events (even while masked).
|
/// Any time the text box receives key events (even while masked).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Action TypingStarted;
|
public Action TextChanged;
|
||||||
|
|
||||||
protected override Color4 SelectionColour => Color4.Gray;
|
protected override Color4 SelectionColour => Color4.Gray;
|
||||||
|
|
||||||
@ -181,7 +182,16 @@ namespace osu.Game.Overlays.BeatmapListing
|
|||||||
if (!base.OnKeyDown(e))
|
if (!base.OnKeyDown(e))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
TypingStarted?.Invoke();
|
TextChanged?.Invoke();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool OnPressed(GlobalAction action)
|
||||||
|
{
|
||||||
|
if (!base.OnPressed(action))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
TextChanged?.Invoke();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
|
|||||||
private const float horizontal_padding = 10;
|
private const float horizontal_padding = 10;
|
||||||
private const float vertical_padding = 5;
|
private const float vertical_padding = 5;
|
||||||
|
|
||||||
private FillFlowContainer bottomPanel, statusContainer, titleContainer;
|
private FillFlowContainer bottomPanel, statusContainer, titleContainer, artistContainer;
|
||||||
private PlayButton playButton;
|
private PlayButton playButton;
|
||||||
private Box progressBar;
|
private Box progressBar;
|
||||||
|
|
||||||
@ -89,11 +89,19 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
new OsuSpriteText
|
artistContainer = new FillFlowContainer
|
||||||
{
|
{
|
||||||
Text = new RomanisableString(SetInfo.Metadata.ArtistUnicode, SetInfo.Metadata.Artist),
|
AutoSizeAxes = Axes.Both,
|
||||||
Font = OsuFont.GetFont(weight: FontWeight.Bold, italics: true)
|
Direction = FillDirection.Horizontal,
|
||||||
},
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new OsuSpriteText
|
||||||
|
{
|
||||||
|
Text = new RomanisableString(SetInfo.Metadata.ArtistUnicode, SetInfo.Metadata.Artist),
|
||||||
|
Font = OsuFont.GetFont(weight: FontWeight.Bold, italics: true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
new Container
|
new Container
|
||||||
@ -213,6 +221,16 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (SetInfo.OnlineInfo?.TrackId != null)
|
||||||
|
{
|
||||||
|
artistContainer.Add(new FeaturedArtistBeatmapPill
|
||||||
|
{
|
||||||
|
Anchor = Anchor.CentreLeft,
|
||||||
|
Origin = Anchor.CentreLeft,
|
||||||
|
Margin = new MarginPadding { Left = 10f, Top = 2f },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (SetInfo.OnlineInfo?.HasVideo ?? false)
|
if (SetInfo.OnlineInfo?.HasVideo ?? false)
|
||||||
{
|
{
|
||||||
statusContainer.Add(new IconPill(FontAwesome.Solid.Film));
|
statusContainer.Add(new IconPill(FontAwesome.Solid.Film));
|
||||||
|
@ -27,7 +27,7 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
|
|||||||
private const float vertical_padding = 5;
|
private const float vertical_padding = 5;
|
||||||
private const float height = 70;
|
private const float height = 70;
|
||||||
|
|
||||||
private FillFlowContainer statusContainer, titleContainer;
|
private FillFlowContainer statusContainer, titleContainer, artistContainer;
|
||||||
protected BeatmapPanelDownloadButton DownloadButton;
|
protected BeatmapPanelDownloadButton DownloadButton;
|
||||||
private PlayButton playButton;
|
private PlayButton playButton;
|
||||||
private Box progressBar;
|
private Box progressBar;
|
||||||
@ -112,10 +112,18 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
new OsuSpriteText
|
artistContainer = new FillFlowContainer
|
||||||
{
|
{
|
||||||
Text = new RomanisableString(SetInfo.Metadata.ArtistUnicode, SetInfo.Metadata.Artist),
|
AutoSizeAxes = Axes.Both,
|
||||||
Font = OsuFont.GetFont(weight: FontWeight.Bold, italics: true)
|
Direction = FillDirection.Horizontal,
|
||||||
|
Children = new[]
|
||||||
|
{
|
||||||
|
new OsuSpriteText
|
||||||
|
{
|
||||||
|
Text = new RomanisableString(SetInfo.Metadata.ArtistUnicode, SetInfo.Metadata.Artist),
|
||||||
|
Font = OsuFont.GetFont(weight: FontWeight.Bold, italics: true)
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -227,6 +235,16 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (SetInfo.OnlineInfo?.TrackId != null)
|
||||||
|
{
|
||||||
|
artistContainer.Add(new FeaturedArtistBeatmapPill
|
||||||
|
{
|
||||||
|
Anchor = Anchor.CentreLeft,
|
||||||
|
Origin = Anchor.CentreLeft,
|
||||||
|
Margin = new MarginPadding { Left = 10f, Top = 2f },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (SetInfo.OnlineInfo?.HasVideo ?? false)
|
if (SetInfo.OnlineInfo?.HasVideo ?? false)
|
||||||
{
|
{
|
||||||
statusContainer.Add(new IconPill(FontAwesome.Solid.Film) { IconSize = new Vector2(20) });
|
statusContainer.Add(new IconPill(FontAwesome.Solid.Film) { IconSize = new Vector2(20) });
|
||||||
|
@ -37,6 +37,7 @@ namespace osu.Game.Overlays.BeatmapSet
|
|||||||
private readonly OsuSpriteText title, artist;
|
private readonly OsuSpriteText title, artist;
|
||||||
private readonly AuthorInfo author;
|
private readonly AuthorInfo author;
|
||||||
private readonly ExplicitContentBeatmapPill explicitContentPill;
|
private readonly ExplicitContentBeatmapPill explicitContentPill;
|
||||||
|
private readonly FeaturedArtistBeatmapPill featuredArtistPill;
|
||||||
private readonly FillFlowContainer downloadButtonsContainer;
|
private readonly FillFlowContainer downloadButtonsContainer;
|
||||||
private readonly BeatmapAvailability beatmapAvailability;
|
private readonly BeatmapAvailability beatmapAvailability;
|
||||||
private readonly BeatmapSetOnlineStatusPill onlineStatusPill;
|
private readonly BeatmapSetOnlineStatusPill onlineStatusPill;
|
||||||
@ -129,10 +130,25 @@ namespace osu.Game.Overlays.BeatmapSet
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
artist = new OsuSpriteText
|
new FillFlowContainer
|
||||||
{
|
{
|
||||||
Font = OsuFont.GetFont(size: 20, weight: FontWeight.Medium, italics: true),
|
Direction = FillDirection.Horizontal,
|
||||||
Margin = new MarginPadding { Bottom = 20 }
|
AutoSizeAxes = Axes.Both,
|
||||||
|
Margin = new MarginPadding { Bottom = 20 },
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
artist = new OsuSpriteText
|
||||||
|
{
|
||||||
|
Font = OsuFont.GetFont(size: 20, weight: FontWeight.Medium, italics: true),
|
||||||
|
},
|
||||||
|
featuredArtistPill = new FeaturedArtistBeatmapPill
|
||||||
|
{
|
||||||
|
Alpha = 0f,
|
||||||
|
Anchor = Anchor.BottomLeft,
|
||||||
|
Origin = Anchor.BottomLeft,
|
||||||
|
Margin = new MarginPadding { Left = 10 }
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
new Container
|
new Container
|
||||||
{
|
{
|
||||||
@ -233,6 +249,7 @@ namespace osu.Game.Overlays.BeatmapSet
|
|||||||
artist.Text = new RomanisableString(setInfo.NewValue.Metadata.ArtistUnicode, setInfo.NewValue.Metadata.Artist);
|
artist.Text = new RomanisableString(setInfo.NewValue.Metadata.ArtistUnicode, setInfo.NewValue.Metadata.Artist);
|
||||||
|
|
||||||
explicitContentPill.Alpha = setInfo.NewValue.OnlineInfo.HasExplicitContent ? 1 : 0;
|
explicitContentPill.Alpha = setInfo.NewValue.OnlineInfo.HasExplicitContent ? 1 : 0;
|
||||||
|
featuredArtistPill.Alpha = setInfo.NewValue.OnlineInfo.TrackId != null ? 1 : 0;
|
||||||
|
|
||||||
onlineStatusPill.FadeIn(500, Easing.OutQuint);
|
onlineStatusPill.FadeIn(500, Easing.OutQuint);
|
||||||
onlineStatusPill.Status = setInfo.NewValue.OnlineInfo.Status;
|
onlineStatusPill.Status = setInfo.NewValue.OnlineInfo.Status;
|
||||||
|
47
osu.Game/Overlays/BeatmapSet/FeaturedArtistBeatmapPill.cs
Normal file
47
osu.Game/Overlays/BeatmapSet/FeaturedArtistBeatmapPill.cs
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Extensions.LocalisationExtensions;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
using osu.Game.Graphics.Sprites;
|
||||||
|
using osu.Game.Resources.Localisation.Web;
|
||||||
|
|
||||||
|
namespace osu.Game.Overlays.BeatmapSet
|
||||||
|
{
|
||||||
|
public class FeaturedArtistBeatmapPill : CompositeDrawable
|
||||||
|
{
|
||||||
|
public FeaturedArtistBeatmapPill()
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Both;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader(true)]
|
||||||
|
private void load(OsuColour colours, OverlayColourProvider colourProvider)
|
||||||
|
{
|
||||||
|
InternalChild = new CircularContainer
|
||||||
|
{
|
||||||
|
Masking = true,
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Colour = colourProvider?.Background5 ?? colours.Gray2,
|
||||||
|
},
|
||||||
|
new OsuSpriteText
|
||||||
|
{
|
||||||
|
Margin = new MarginPadding { Horizontal = 10f, Vertical = 2f },
|
||||||
|
Text = BeatmapsetsStrings.FeaturedArtistBadgeLabel.ToUpper(),
|
||||||
|
Font = OsuFont.GetFont(size: 10, weight: FontWeight.SemiBold),
|
||||||
|
Colour = OverlayColourProvider.Blue.Colour1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -19,7 +19,7 @@ namespace osu.Game.Overlays.BeatmapSet
|
|||||||
{
|
{
|
||||||
public class LeaderboardModSelector : CompositeDrawable
|
public class LeaderboardModSelector : CompositeDrawable
|
||||||
{
|
{
|
||||||
public readonly BindableList<Mod> SelectedMods = new BindableList<Mod>();
|
public readonly BindableList<IMod> SelectedMods = new BindableList<IMod>();
|
||||||
public readonly Bindable<RulesetInfo> Ruleset = new Bindable<RulesetInfo>();
|
public readonly Bindable<RulesetInfo> Ruleset = new Bindable<RulesetInfo>();
|
||||||
|
|
||||||
private readonly FillFlowContainer<ModButton> modsContainer;
|
private readonly FillFlowContainer<ModButton> modsContainer;
|
||||||
@ -54,7 +54,7 @@ namespace osu.Game.Overlays.BeatmapSet
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
modsContainer.Add(new ModButton(new ModNoMod()));
|
modsContainer.Add(new ModButton(new ModNoMod()));
|
||||||
modsContainer.AddRange(ruleset.NewValue.CreateInstance().GetAllMods().Where(m => m.UserPlayable).Select(m => new ModButton(m)));
|
modsContainer.AddRange(ruleset.NewValue.CreateInstance().AllMods.Where(m => m.UserPlayable).Select(m => new ModButton(m)));
|
||||||
|
|
||||||
modsContainer.ForEach(button =>
|
modsContainer.ForEach(button =>
|
||||||
{
|
{
|
||||||
@ -76,7 +76,7 @@ namespace osu.Game.Overlays.BeatmapSet
|
|||||||
updateHighlighted();
|
updateHighlighted();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void selectionChanged(Mod mod, bool selected)
|
private void selectionChanged(IMod mod, bool selected)
|
||||||
{
|
{
|
||||||
if (selected)
|
if (selected)
|
||||||
SelectedMods.Add(mod);
|
SelectedMods.Add(mod);
|
||||||
@ -101,9 +101,9 @@ namespace osu.Game.Overlays.BeatmapSet
|
|||||||
private const int duration = 200;
|
private const int duration = 200;
|
||||||
|
|
||||||
public readonly BindableBool Highlighted = new BindableBool();
|
public readonly BindableBool Highlighted = new BindableBool();
|
||||||
public Action<Mod, bool> OnSelectionChanged;
|
public Action<IMod, bool> OnSelectionChanged;
|
||||||
|
|
||||||
public ModButton(Mod mod)
|
public ModButton(IMod mod)
|
||||||
: base(mod)
|
: base(mod)
|
||||||
{
|
{
|
||||||
Scale = new Vector2(0.4f);
|
Scale = new Vector2(0.4f);
|
||||||
|
@ -26,9 +26,6 @@ namespace osu.Game.Overlays.Changelog
|
|||||||
private const float image_container_width = 164;
|
private const float image_container_width = 164;
|
||||||
private const float heart_size = 75;
|
private const float heart_size = 75;
|
||||||
|
|
||||||
private readonly FillFlowContainer textContainer;
|
|
||||||
private readonly Container imageContainer;
|
|
||||||
|
|
||||||
public ChangelogSupporterPromo()
|
public ChangelogSupporterPromo()
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X;
|
RelativeSizeAxes = Axes.X;
|
||||||
@ -38,6 +35,12 @@ namespace osu.Game.Overlays.Changelog
|
|||||||
Vertical = 20,
|
Vertical = 20,
|
||||||
Horizontal = 50,
|
Horizontal = 50,
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuColour colour, TextureStore textures, OverlayColourProvider colourProvider)
|
||||||
|
{
|
||||||
|
SupporterPromoLinkFlowContainer supportLinkText;
|
||||||
|
|
||||||
InternalChildren = new Drawable[]
|
InternalChildren = new Drawable[]
|
||||||
{
|
{
|
||||||
@ -59,7 +62,7 @@ namespace osu.Game.Overlays.Changelog
|
|||||||
new Box
|
new Box
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Colour = Color4.Black.Opacity(0.3f),
|
Colour = colourProvider.Background5,
|
||||||
},
|
},
|
||||||
new Container
|
new Container
|
||||||
{
|
{
|
||||||
@ -68,7 +71,7 @@ namespace osu.Game.Overlays.Changelog
|
|||||||
Padding = new MarginPadding { Horizontal = 75 },
|
Padding = new MarginPadding { Horizontal = 75 },
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
textContainer = new FillFlowContainer
|
new FillFlowContainer
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
AutoSizeAxes = Axes.Y,
|
AutoSizeAxes = Axes.Y,
|
||||||
@ -76,91 +79,84 @@ namespace osu.Game.Overlays.Changelog
|
|||||||
Anchor = Anchor.CentreLeft,
|
Anchor = Anchor.CentreLeft,
|
||||||
Origin = Anchor.CentreLeft,
|
Origin = Anchor.CentreLeft,
|
||||||
Padding = new MarginPadding { Right = 50 + image_container_width },
|
Padding = new MarginPadding { Right = 50 + image_container_width },
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new OsuSpriteText
|
||||||
|
{
|
||||||
|
Text = ChangelogStrings.SupportHeading,
|
||||||
|
Font = OsuFont.GetFont(size: 20, weight: FontWeight.Light),
|
||||||
|
Margin = new MarginPadding { Bottom = 20 },
|
||||||
|
},
|
||||||
|
supportLinkText = new SupporterPromoLinkFlowContainer(t =>
|
||||||
|
{
|
||||||
|
t.Font = t.Font.With(size: 14);
|
||||||
|
t.Colour = colour.PinkLighter;
|
||||||
|
})
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
|
},
|
||||||
|
new OsuTextFlowContainer(t =>
|
||||||
|
{
|
||||||
|
t.Font = t.Font.With(size: 12);
|
||||||
|
t.Colour = colour.PinkLighter;
|
||||||
|
})
|
||||||
|
{
|
||||||
|
Text = ChangelogStrings.SupportText2.ToString(),
|
||||||
|
Margin = new MarginPadding { Top = 10 },
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
|
}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
imageContainer = new Container
|
new Container
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Y,
|
RelativeSizeAxes = Axes.Y,
|
||||||
Width = image_container_width,
|
Width = image_container_width,
|
||||||
Anchor = Anchor.CentreRight,
|
Anchor = Anchor.CentreRight,
|
||||||
Origin = Anchor.CentreRight,
|
Origin = Anchor.CentreRight,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new Sprite
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
Margin = new MarginPadding { Bottom = 28 },
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
FillMode = FillMode.Fill,
|
||||||
|
Texture = textures.Get(@"Online/supporter-pippi"),
|
||||||
|
},
|
||||||
|
new Container
|
||||||
|
{
|
||||||
|
Anchor = Anchor.TopCentre,
|
||||||
|
Origin = Anchor.TopCentre,
|
||||||
|
Size = new Vector2(heart_size),
|
||||||
|
Margin = new MarginPadding { Top = 70 },
|
||||||
|
Masking = true,
|
||||||
|
EdgeEffect = new EdgeEffectParameters
|
||||||
|
{
|
||||||
|
Type = EdgeEffectType.Shadow,
|
||||||
|
Colour = colour.Pink,
|
||||||
|
Radius = 10,
|
||||||
|
Roundness = heart_size / 2,
|
||||||
|
},
|
||||||
|
Child = new Sprite
|
||||||
|
{
|
||||||
|
Size = new Vector2(heart_size),
|
||||||
|
Texture = textures.Get(@"Online/supporter-heart"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
|
||||||
private void load(OsuColour colour, TextureStore textures)
|
|
||||||
{
|
|
||||||
SupporterPromoLinkFlowContainer supportLinkText;
|
|
||||||
textContainer.Children = new Drawable[]
|
|
||||||
{
|
|
||||||
new OsuSpriteText
|
|
||||||
{
|
|
||||||
Text = ChangelogStrings.SupportHeading,
|
|
||||||
Font = OsuFont.GetFont(size: 20, weight: FontWeight.Light),
|
|
||||||
Margin = new MarginPadding { Bottom = 20 },
|
|
||||||
},
|
|
||||||
supportLinkText = new SupporterPromoLinkFlowContainer(t =>
|
|
||||||
{
|
|
||||||
t.Font = t.Font.With(size: 14);
|
|
||||||
t.Colour = colour.PinkLighter;
|
|
||||||
})
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.X,
|
|
||||||
AutoSizeAxes = Axes.Y,
|
|
||||||
},
|
|
||||||
new OsuTextFlowContainer(t =>
|
|
||||||
{
|
|
||||||
t.Font = t.Font.With(size: 12);
|
|
||||||
t.Colour = colour.PinkLighter;
|
|
||||||
})
|
|
||||||
{
|
|
||||||
Text = ChangelogStrings.SupportText2.ToString(),
|
|
||||||
Margin = new MarginPadding { Top = 10 },
|
|
||||||
RelativeSizeAxes = Axes.X,
|
|
||||||
AutoSizeAxes = Axes.Y,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
supportLinkText.AddText("Support further development of osu! and ");
|
supportLinkText.AddText("Support further development of osu! and ");
|
||||||
supportLinkText.AddLink("become an osu!supporter", @"https://osu.ppy.sh/home/support", t => t.Font = t.Font.With(weight: FontWeight.Bold));
|
supportLinkText.AddLink("become an osu!supporter", @"https://osu.ppy.sh/home/support", t => t.Font = t.Font.With(weight: FontWeight.Bold));
|
||||||
supportLinkText.AddText(" today!");
|
supportLinkText.AddText(" today!");
|
||||||
|
|
||||||
imageContainer.Children = new Drawable[]
|
|
||||||
{
|
|
||||||
new Sprite
|
|
||||||
{
|
|
||||||
Anchor = Anchor.Centre,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
Margin = new MarginPadding { Bottom = 28 },
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
FillMode = FillMode.Fill,
|
|
||||||
Texture = textures.Get(@"Online/supporter-pippi"),
|
|
||||||
},
|
|
||||||
new Container
|
|
||||||
{
|
|
||||||
Anchor = Anchor.TopCentre,
|
|
||||||
Origin = Anchor.TopCentre,
|
|
||||||
Size = new Vector2(heart_size),
|
|
||||||
Margin = new MarginPadding { Top = 70 },
|
|
||||||
Masking = true,
|
|
||||||
EdgeEffect = new EdgeEffectParameters
|
|
||||||
{
|
|
||||||
Type = EdgeEffectType.Shadow,
|
|
||||||
Colour = colour.Pink,
|
|
||||||
Radius = 10,
|
|
||||||
Roundness = heart_size / 2,
|
|
||||||
},
|
|
||||||
Child = new Sprite
|
|
||||||
{
|
|
||||||
Size = new Vector2(heart_size),
|
|
||||||
Texture = textures.Get(@"Online/supporter-heart"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class SupporterPromoLinkFlowContainer : LinkFlowContainer
|
private class SupporterPromoLinkFlowContainer : LinkFlowContainer
|
||||||
|
@ -107,9 +107,9 @@ namespace osu.Game.Overlays.Mods
|
|||||||
|
|
||||||
var incompatibleTypes = mod.IncompatibleMods;
|
var incompatibleTypes = mod.IncompatibleMods;
|
||||||
|
|
||||||
var allMods = ruleset.Value.CreateInstance().GetAllMods();
|
var allMods = ruleset.Value.CreateInstance().AllMods;
|
||||||
|
|
||||||
incompatibleMods.Value = allMods.Where(m => m.GetType() != mod.GetType() && incompatibleTypes.Any(t => t.IsInstanceOfType(m))).ToList();
|
incompatibleMods.Value = allMods.Where(m => m.GetType() != mod.GetType() && incompatibleTypes.Any(t => t.IsInstanceOfType(m))).Select(m => m.CreateInstance()).ToList();
|
||||||
incompatibleText.Text = incompatibleMods.Value.Any() ? "Incompatible with:" : "Compatible with all mods";
|
incompatibleText.Text = incompatibleMods.Value.Any() ? "Incompatible with:" : "Compatible with all mods";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
// 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 Newtonsoft.Json;
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mods
|
namespace osu.Game.Rulesets.Mods
|
||||||
{
|
{
|
||||||
@ -11,7 +11,37 @@ namespace osu.Game.Rulesets.Mods
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The shortened name of this mod.
|
/// The shortened name of this mod.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[JsonProperty("acronym")]
|
|
||||||
string Acronym { get; }
|
string Acronym { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The name of this mod.
|
||||||
|
/// </summary>
|
||||||
|
string Name { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The user readable description of this mod.
|
||||||
|
/// </summary>
|
||||||
|
string Description { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The type of this mod.
|
||||||
|
/// </summary>
|
||||||
|
ModType Type { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The icon of this mod.
|
||||||
|
/// </summary>
|
||||||
|
IconUsage? Icon { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether this mod is playable by an end user.
|
||||||
|
/// Should be <c>false</c> for cases where the user is not interacting with the game (so it can be excluded from multiplayer selection, for example).
|
||||||
|
/// </summary>
|
||||||
|
bool UserPlayable { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create a fresh <see cref="Mod"/> instance based on this mod.
|
||||||
|
/// </summary>
|
||||||
|
Mod CreateInstance() => (Mod)Activator.CreateInstance(GetType());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,32 +22,17 @@ namespace osu.Game.Rulesets.Mods
|
|||||||
[ExcludeFromDynamicCompile]
|
[ExcludeFromDynamicCompile]
|
||||||
public abstract class Mod : IMod, IEquatable<Mod>, IDeepCloneable<Mod>
|
public abstract class Mod : IMod, IEquatable<Mod>, IDeepCloneable<Mod>
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// The name of this mod.
|
|
||||||
/// </summary>
|
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public abstract string Name { get; }
|
public abstract string Name { get; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The shortened name of this mod.
|
|
||||||
/// </summary>
|
|
||||||
public abstract string Acronym { get; }
|
public abstract string Acronym { get; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The icon of this mod.
|
|
||||||
/// </summary>
|
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public virtual IconUsage? Icon => null;
|
public virtual IconUsage? Icon => null;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The type of this mod.
|
|
||||||
/// </summary>
|
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public virtual ModType Type => ModType.Fun;
|
public virtual ModType Type => ModType.Fun;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The user readable description of this mod.
|
|
||||||
/// </summary>
|
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public abstract string Description { get; }
|
public abstract string Description { get; }
|
||||||
|
|
||||||
@ -106,10 +91,6 @@ namespace osu.Game.Rulesets.Mods
|
|||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public virtual bool HasImplementation => this is IApplicableMod;
|
public virtual bool HasImplementation => this is IApplicableMod;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Whether this mod is playable by an end user.
|
|
||||||
/// Should be <c>false</c> for cases where the user is not interacting with the game (so it can be excluded from mutliplayer selection, for example).
|
|
||||||
/// </summary>
|
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public virtual bool UserPlayable => true;
|
public virtual bool UserPlayable => true;
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
// 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 System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
@ -38,13 +39,58 @@ namespace osu.Game.Rulesets
|
|||||||
{
|
{
|
||||||
public RulesetInfo RulesetInfo { get; internal set; }
|
public RulesetInfo RulesetInfo { get; internal set; }
|
||||||
|
|
||||||
public IEnumerable<Mod> GetAllMods() => Enum.GetValues(typeof(ModType)).Cast<ModType>()
|
private static readonly ConcurrentDictionary<int, IMod[]> mod_reference_cache = new ConcurrentDictionary<int, IMod[]>();
|
||||||
// Confine all mods of each mod type into a single IEnumerable<Mod>
|
|
||||||
.SelectMany(GetModsFor)
|
/// <summary>
|
||||||
// Filter out all null mods
|
/// A queryable source containing all available mods.
|
||||||
.Where(mod => mod != null)
|
/// Call <see cref="IMod.CreateInstance"/> for consumption purposes.
|
||||||
// Resolve MultiMods as their .Mods property
|
/// </summary>
|
||||||
.SelectMany(mod => (mod as MultiMod)?.Mods ?? new[] { mod });
|
public IEnumerable<IMod> AllMods
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (!(RulesetInfo.ID is int id))
|
||||||
|
return CreateAllMods();
|
||||||
|
|
||||||
|
if (!mod_reference_cache.TryGetValue(id, out var mods))
|
||||||
|
mod_reference_cache[id] = mods = CreateAllMods().Cast<IMod>().ToArray();
|
||||||
|
|
||||||
|
return mods;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns fresh instances of all mods.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This comes with considerable allocation overhead. If only accessing for reference purposes (ie. not changing bindables / settings)
|
||||||
|
/// use <see cref="AllMods"/> instead.
|
||||||
|
/// </remarks>
|
||||||
|
public IEnumerable<Mod> CreateAllMods() => Enum.GetValues(typeof(ModType)).Cast<ModType>()
|
||||||
|
// Confine all mods of each mod type into a single IEnumerable<Mod>
|
||||||
|
.SelectMany(GetModsFor)
|
||||||
|
// Filter out all null mods
|
||||||
|
.Where(mod => mod != null)
|
||||||
|
// Resolve MultiMods as their .Mods property
|
||||||
|
.SelectMany(mod => (mod as MultiMod)?.Mods ?? new[] { mod });
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a fresh instance of the mod matching the specified acronym.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="acronym">The acronym to query for .</param>
|
||||||
|
public Mod CreateModFromAcronym(string acronym)
|
||||||
|
{
|
||||||
|
return AllMods.FirstOrDefault(m => m.Acronym == acronym)?.CreateInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a fresh instance of the mod matching the specified type.
|
||||||
|
/// </summary>
|
||||||
|
public T CreateMod<T>()
|
||||||
|
where T : Mod
|
||||||
|
{
|
||||||
|
return AllMods.FirstOrDefault(m => m is T)?.CreateInstance() as T;
|
||||||
|
}
|
||||||
|
|
||||||
public abstract IEnumerable<Mod> GetModsFor(ModType type);
|
public abstract IEnumerable<Mod> GetModsFor(ModType type);
|
||||||
|
|
||||||
@ -126,7 +172,7 @@ namespace osu.Game.Rulesets
|
|||||||
}
|
}
|
||||||
|
|
||||||
[CanBeNull]
|
[CanBeNull]
|
||||||
public ModAutoplay GetAutoplayMod() => GetAllMods().OfType<ModAutoplay>().FirstOrDefault();
|
public ModAutoplay GetAutoplayMod() => CreateMod<ModAutoplay>();
|
||||||
|
|
||||||
public virtual ISkin CreateLegacySkinProvider([NotNull] ISkin skin, IBeatmap beatmap) => null;
|
public virtual ISkin CreateLegacySkinProvider([NotNull] ISkin skin, IBeatmap beatmap) => null;
|
||||||
|
|
||||||
|
@ -30,12 +30,12 @@ namespace osu.Game.Rulesets.UI
|
|||||||
|
|
||||||
private const float size = 80;
|
private const float size = 80;
|
||||||
|
|
||||||
public virtual LocalisableString TooltipText => showTooltip ? mod.IconTooltip : null;
|
public virtual LocalisableString TooltipText => showTooltip ? ((mod as Mod)?.IconTooltip ?? mod.Name) : null;
|
||||||
|
|
||||||
private Mod mod;
|
private IMod mod;
|
||||||
private readonly bool showTooltip;
|
private readonly bool showTooltip;
|
||||||
|
|
||||||
public Mod Mod
|
public IMod Mod
|
||||||
{
|
{
|
||||||
get => mod;
|
get => mod;
|
||||||
set
|
set
|
||||||
@ -58,7 +58,7 @@ namespace osu.Game.Rulesets.UI
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="mod">The mod to be displayed</param>
|
/// <param name="mod">The mod to be displayed</param>
|
||||||
/// <param name="showTooltip">Whether a tooltip describing the mod should display on hover.</param>
|
/// <param name="showTooltip">Whether a tooltip describing the mod should display on hover.</param>
|
||||||
public ModIcon(Mod mod, bool showTooltip = true)
|
public ModIcon(IMod mod, bool showTooltip = true)
|
||||||
{
|
{
|
||||||
this.mod = mod ?? throw new ArgumentNullException(nameof(mod));
|
this.mod = mod ?? throw new ArgumentNullException(nameof(mod));
|
||||||
this.showTooltip = showTooltip;
|
this.showTooltip = showTooltip;
|
||||||
@ -105,7 +105,7 @@ namespace osu.Game.Rulesets.UI
|
|||||||
updateMod(mod);
|
updateMod(mod);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateMod(Mod value)
|
private void updateMod(IMod value)
|
||||||
{
|
{
|
||||||
modAcronym.Text = value.Acronym;
|
modAcronym.Text = value.Acronym;
|
||||||
modIcon.Icon = value.Icon ?? FontAwesome.Solid.Question;
|
modIcon.Icon = value.Icon ?? FontAwesome.Solid.Question;
|
||||||
|
@ -67,7 +67,7 @@ namespace osu.Game.Scoring.Legacy
|
|||||||
|
|
||||||
// lazer replays get a really high version number.
|
// lazer replays get a really high version number.
|
||||||
if (version < LegacyScoreEncoder.FIRST_LAZER_VERSION)
|
if (version < LegacyScoreEncoder.FIRST_LAZER_VERSION)
|
||||||
scoreInfo.Mods = scoreInfo.Mods.Append(currentRuleset.GetAllMods().OfType<ModClassic>().Single()).ToArray();
|
scoreInfo.Mods = scoreInfo.Mods.Append(currentRuleset.CreateMod<ModClassic>()).ToArray();
|
||||||
|
|
||||||
currentBeatmap = workingBeatmap.GetPlayableBeatmap(currentRuleset.RulesetInfo, scoreInfo.Mods);
|
currentBeatmap = workingBeatmap.GetPlayableBeatmap(currentRuleset.RulesetInfo, scoreInfo.Mods);
|
||||||
scoreInfo.Beatmap = currentBeatmap.BeatmapInfo;
|
scoreInfo.Beatmap = currentBeatmap.BeatmapInfo;
|
||||||
|
@ -115,7 +115,9 @@ namespace osu.Game.Screens.Menu
|
|||||||
if (setInfo == null)
|
if (setInfo == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return (initialBeatmap = beatmaps.GetWorkingBeatmap(setInfo.Beatmaps[0])) != null;
|
initialBeatmap = beatmaps.GetWorkingBeatmap(setInfo.Beatmaps[0]);
|
||||||
|
|
||||||
|
return UsingThemedIntro = initialBeatmap != null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -165,7 +167,7 @@ namespace osu.Game.Screens.Menu
|
|||||||
|
|
||||||
protected override BackgroundScreen CreateBackground() => new BackgroundScreenBlack();
|
protected override BackgroundScreen CreateBackground() => new BackgroundScreenBlack();
|
||||||
|
|
||||||
protected void StartTrack()
|
protected virtual void StartTrack()
|
||||||
{
|
{
|
||||||
// Only start the current track if it is the menu music. A beatmap's track is started when entering the Main Menu.
|
// Only start the current track if it is the menu music. A beatmap's track is started when entering the Main Menu.
|
||||||
if (UsingThemedIntro)
|
if (UsingThemedIntro)
|
||||||
@ -184,7 +186,6 @@ namespace osu.Game.Screens.Menu
|
|||||||
{
|
{
|
||||||
beatmap.Value = initialBeatmap;
|
beatmap.Value = initialBeatmap;
|
||||||
Track = initialBeatmap.Track;
|
Track = initialBeatmap.Track;
|
||||||
UsingThemedIntro = !initialBeatmap.Track.IsDummyDevice;
|
|
||||||
|
|
||||||
// ensure the track starts at maximum volume
|
// ensure the track starts at maximum volume
|
||||||
musicController.CurrentTrack.FinishTransforms();
|
musicController.CurrentTrack.FinishTransforms();
|
||||||
|
@ -41,6 +41,9 @@ namespace osu.Game.Screens.Menu
|
|||||||
|
|
||||||
private Sample welcome;
|
private Sample welcome;
|
||||||
|
|
||||||
|
private DecoupleableInterpolatingFramedClock decoupledClock;
|
||||||
|
private TrianglesIntroSequence intro;
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
{
|
{
|
||||||
@ -56,10 +59,18 @@ namespace osu.Game.Screens.Menu
|
|||||||
{
|
{
|
||||||
PrepareMenuLoad();
|
PrepareMenuLoad();
|
||||||
|
|
||||||
LoadComponentAsync(new TrianglesIntroSequence(logo, background)
|
decoupledClock = new DecoupleableInterpolatingFramedClock
|
||||||
|
{
|
||||||
|
IsCoupled = false
|
||||||
|
};
|
||||||
|
|
||||||
|
if (UsingThemedIntro)
|
||||||
|
decoupledClock.ChangeSource(Track);
|
||||||
|
|
||||||
|
LoadComponentAsync(intro = new TrianglesIntroSequence(logo, background)
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Clock = new FramedClock(UsingThemedIntro ? Track : null),
|
Clock = decoupledClock,
|
||||||
LoadMenu = LoadMenu
|
LoadMenu = LoadMenu
|
||||||
}, t =>
|
}, t =>
|
||||||
{
|
{
|
||||||
@ -72,12 +83,25 @@ namespace osu.Game.Screens.Menu
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void OnSuspending(IScreen next)
|
||||||
|
{
|
||||||
|
base.OnSuspending(next);
|
||||||
|
|
||||||
|
// important as there is a clock attached to a track which will likely be disposed before returning to this screen.
|
||||||
|
intro.Expire();
|
||||||
|
}
|
||||||
|
|
||||||
public override void OnResuming(IScreen last)
|
public override void OnResuming(IScreen last)
|
||||||
{
|
{
|
||||||
base.OnResuming(last);
|
base.OnResuming(last);
|
||||||
background.FadeOut(100);
|
background.FadeOut(100);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void StartTrack()
|
||||||
|
{
|
||||||
|
decoupledClock.Start();
|
||||||
|
}
|
||||||
|
|
||||||
private class TrianglesIntroSequence : CompositeDrawable
|
private class TrianglesIntroSequence : CompositeDrawable
|
||||||
{
|
{
|
||||||
private readonly OsuLogo logo;
|
private readonly OsuLogo logo;
|
||||||
|
@ -34,7 +34,7 @@ namespace osu.Game.Tests.Beatmaps
|
|||||||
protected void TestToLegacy(LegacyMods expectedLegacyMods, Type[] providedModTypes)
|
protected void TestToLegacy(LegacyMods expectedLegacyMods, Type[] providedModTypes)
|
||||||
{
|
{
|
||||||
var ruleset = CreateRuleset();
|
var ruleset = CreateRuleset();
|
||||||
var modInstances = ruleset.GetAllMods()
|
var modInstances = ruleset.CreateAllMods()
|
||||||
.Where(mod => providedModTypes.Contains(mod.GetType()))
|
.Where(mod => providedModTypes.Contains(mod.GetType()))
|
||||||
.ToArray();
|
.ToArray();
|
||||||
var actualLegacyMods = ruleset.ConvertToLegacyMods(modInstances);
|
var actualLegacyMods = ruleset.ConvertToLegacyMods(modInstances);
|
||||||
|
@ -28,7 +28,7 @@ namespace osu.Game.Tests
|
|||||||
RulesetID = ruleset.ID ?? 0;
|
RulesetID = ruleset.ID ?? 0;
|
||||||
|
|
||||||
Mods = excessMods
|
Mods = excessMods
|
||||||
? ruleset.CreateInstance().GetAllMods().ToArray()
|
? ruleset.CreateInstance().CreateAllMods().ToArray()
|
||||||
: new Mod[] { new TestModHardRock(), new TestModDoubleTime() };
|
: new Mod[] { new TestModHardRock(), new TestModDoubleTime() };
|
||||||
|
|
||||||
TotalScore = 2845370;
|
TotalScore = 2845370;
|
||||||
|
@ -67,7 +67,7 @@ namespace osu.Game.Tests.Visual
|
|||||||
|
|
||||||
if (!AllowFail)
|
if (!AllowFail)
|
||||||
{
|
{
|
||||||
var noFailMod = ruleset.GetAllMods().FirstOrDefault(m => m is ModNoFail);
|
var noFailMod = ruleset.CreateMod<ModNoFail>();
|
||||||
if (noFailMod != null)
|
if (noFailMod != null)
|
||||||
SelectedMods.Value = new[] { noFailMod };
|
SelectedMods.Value = new[] { noFailMod };
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user