mirror of
https://github.com/ppy/osu.git
synced 2024-11-06 06:57:39 +08:00
Merge branch 'master' into fix-editor-time-change-display
This commit is contained in:
commit
5b3f0bbb0a
@ -54,6 +54,6 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2019.1230.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2020.207.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2020.213.0" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
@ -10,7 +10,7 @@ namespace osu.Game.Rulesets.Catch.Mods
|
||||
{
|
||||
public class CatchModDifficultyAdjust : ModDifficultyAdjust
|
||||
{
|
||||
[SettingSource("Fruit Size", "Override a beatmap's set CS.")]
|
||||
[SettingSource("Circle Size", "Override a beatmap's set CS.", FIRST_SETTING_ORDER - 1)]
|
||||
public BindableNumber<float> CircleSize { get; } = new BindableFloat
|
||||
{
|
||||
Precision = 0.1f,
|
||||
@ -20,7 +20,7 @@ namespace osu.Game.Rulesets.Catch.Mods
|
||||
Value = 5,
|
||||
};
|
||||
|
||||
[SettingSource("Approach Rate", "Override a beatmap's set AR.")]
|
||||
[SettingSource("Approach Rate", "Override a beatmap's set AR.", LAST_SETTING_ORDER + 1)]
|
||||
public BindableNumber<float> ApproachRate { get; } = new BindableFloat
|
||||
{
|
||||
Precision = 0.1f,
|
||||
|
@ -52,7 +52,7 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints
|
||||
{
|
||||
base.UpdatePosition(screenSpacePosition);
|
||||
|
||||
if (PlacementBegun)
|
||||
if (PlacementActive)
|
||||
{
|
||||
var endTime = TimeAt(screenSpacePosition);
|
||||
|
||||
|
@ -62,7 +62,7 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints
|
||||
|
||||
public override void UpdatePosition(Vector2 screenSpacePosition)
|
||||
{
|
||||
if (!PlacementBegun)
|
||||
if (!PlacementActive)
|
||||
Column = ColumnAt(screenSpacePosition);
|
||||
|
||||
if (Column == null) return;
|
||||
|
@ -126,7 +126,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
|
||||
|
||||
private void beginCurve()
|
||||
{
|
||||
BeginPlacement();
|
||||
BeginPlacement(commitStart: true);
|
||||
setState(PlacementState.Body);
|
||||
}
|
||||
|
||||
|
@ -52,7 +52,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners
|
||||
if (e.Button != MouseButton.Left)
|
||||
return false;
|
||||
|
||||
BeginPlacement();
|
||||
BeginPlacement(commitStart: true);
|
||||
piece.FadeTo(1f, 150, Easing.OutQuint);
|
||||
|
||||
isPlacingEnd = true;
|
||||
|
@ -10,7 +10,7 @@ namespace osu.Game.Rulesets.Osu.Mods
|
||||
{
|
||||
public class OsuModDifficultyAdjust : ModDifficultyAdjust
|
||||
{
|
||||
[SettingSource("Circle Size", "Override a beatmap's set CS.")]
|
||||
[SettingSource("Circle Size", "Override a beatmap's set CS.", FIRST_SETTING_ORDER - 1)]
|
||||
public BindableNumber<float> CircleSize { get; } = new BindableFloat
|
||||
{
|
||||
Precision = 0.1f,
|
||||
@ -20,7 +20,7 @@ namespace osu.Game.Rulesets.Osu.Mods
|
||||
Value = 5,
|
||||
};
|
||||
|
||||
[SettingSource("Approach Rate", "Override a beatmap's set AR.")]
|
||||
[SettingSource("Approach Rate", "Override a beatmap's set AR.", LAST_SETTING_ORDER + 1)]
|
||||
public BindableNumber<float> ApproachRate { get; } = new BindableFloat
|
||||
{
|
||||
Precision = 0.1f,
|
||||
|
@ -121,10 +121,13 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
room.Playlist.Add(new PlaylistItem
|
||||
{
|
||||
Ruleset = ruleset,
|
||||
Beatmap = new BeatmapInfo
|
||||
Ruleset = { Value = ruleset },
|
||||
Beatmap =
|
||||
{
|
||||
Metadata = new BeatmapMetadata()
|
||||
Value = new BeatmapInfo
|
||||
{
|
||||
Metadata = new BeatmapMetadata()
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -7,7 +7,6 @@ using osu.Game.Beatmaps;
|
||||
using osu.Game.Online.Multiplayer;
|
||||
using osu.Game.Screens.Multi.Match.Components;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Game.Audio;
|
||||
using osu.Framework.Allocation;
|
||||
|
||||
@ -32,22 +31,11 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
Origin = Anchor.Centre,
|
||||
});
|
||||
|
||||
Room.Playlist.Add(new PlaylistItem { Beatmap = new BeatmapInfo { OnlineBeatmapID = 1763072 } });
|
||||
Room.Playlist.Add(new PlaylistItem { Beatmap = new BeatmapInfo { OnlineBeatmapID = 2101557 } });
|
||||
Room.Playlist.Add(new PlaylistItem { Beatmap = new BeatmapInfo { OnlineBeatmapID = 1973466 } });
|
||||
Room.Playlist.Add(new PlaylistItem { Beatmap = new BeatmapInfo { OnlineBeatmapID = 2109801 } });
|
||||
Room.Playlist.Add(new PlaylistItem { Beatmap = new BeatmapInfo { OnlineBeatmapID = 1922035 } });
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
AddStep("Select random beatmap", () =>
|
||||
{
|
||||
Room.CurrentItem.Value = Room.Playlist[RNG.Next(Room.Playlist.Count)];
|
||||
previewTrackManager.StopAnyPlaying(this);
|
||||
});
|
||||
Room.Playlist.Add(new PlaylistItem { Beatmap = { Value = new BeatmapInfo { OnlineBeatmapID = 1763072 } } });
|
||||
Room.Playlist.Add(new PlaylistItem { Beatmap = { Value = new BeatmapInfo { OnlineBeatmapID = 2101557 } } });
|
||||
Room.Playlist.Add(new PlaylistItem { Beatmap = { Value = new BeatmapInfo { OnlineBeatmapID = 1973466 } } });
|
||||
Room.Playlist.Add(new PlaylistItem { Beatmap = { Value = new BeatmapInfo { OnlineBeatmapID = 2109801 } } });
|
||||
Room.Playlist.Add(new PlaylistItem { Beatmap = { Value = new BeatmapInfo { OnlineBeatmapID = 1922035 } } });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -23,16 +23,19 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
Room.Playlist.Add(new PlaylistItem
|
||||
{
|
||||
Beatmap = new BeatmapInfo
|
||||
Beatmap =
|
||||
{
|
||||
Metadata = new BeatmapMetadata
|
||||
Value = new BeatmapInfo
|
||||
{
|
||||
Title = "Title",
|
||||
Artist = "Artist",
|
||||
AuthorString = "Author",
|
||||
},
|
||||
Version = "Version",
|
||||
Ruleset = new OsuRuleset().RulesetInfo
|
||||
Metadata = new BeatmapMetadata
|
||||
{
|
||||
Title = "Title",
|
||||
Artist = "Artist",
|
||||
AuthorString = "Author",
|
||||
},
|
||||
Version = "Version",
|
||||
Ruleset = new OsuRuleset().RulesetInfo
|
||||
}
|
||||
},
|
||||
RequiredMods =
|
||||
{
|
||||
|
@ -37,16 +37,19 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
Room.Playlist.Clear();
|
||||
Room.Playlist.Add(new PlaylistItem
|
||||
{
|
||||
Beatmap = new BeatmapInfo
|
||||
Beatmap =
|
||||
{
|
||||
StarDifficulty = 2.4,
|
||||
Ruleset = rulesets.GetRuleset(0),
|
||||
Metadata = new BeatmapMetadata
|
||||
Value = new BeatmapInfo
|
||||
{
|
||||
Title = @"My Song",
|
||||
Artist = @"VisualTests",
|
||||
AuthorString = @"osu!lazer",
|
||||
},
|
||||
StarDifficulty = 2.4,
|
||||
Ruleset = rulesets.GetRuleset(0),
|
||||
Metadata = new BeatmapMetadata
|
||||
{
|
||||
Title = @"My Song",
|
||||
Artist = @"VisualTests",
|
||||
AuthorString = @"osu!lazer",
|
||||
},
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
@ -60,16 +63,19 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
Room.Playlist.Clear();
|
||||
Room.Playlist.Add(new PlaylistItem
|
||||
{
|
||||
Beatmap = new BeatmapInfo
|
||||
Beatmap =
|
||||
{
|
||||
StarDifficulty = 4.2,
|
||||
Ruleset = rulesets.GetRuleset(3),
|
||||
Metadata = new BeatmapMetadata
|
||||
Value = new BeatmapInfo
|
||||
{
|
||||
Title = @"Your Song",
|
||||
Artist = @"Tester",
|
||||
AuthorString = @"Someone",
|
||||
},
|
||||
StarDifficulty = 4.2,
|
||||
Ruleset = rulesets.GetRuleset(3),
|
||||
Metadata = new BeatmapMetadata
|
||||
{
|
||||
Title = @"Your Song",
|
||||
Artist = @"Tester",
|
||||
AuthorString = @"Someone",
|
||||
},
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -16,7 +16,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
Add(new Participants { RelativeSizeAxes = Axes.Both });
|
||||
|
||||
AddStep(@"set max to null", () => Room.MaxParticipants.Value = null);
|
||||
AddStep(@"set users", () => Room.Participants.Value = new[]
|
||||
AddStep(@"set users", () => Room.Participants.AddRange(new[]
|
||||
{
|
||||
new User
|
||||
{
|
||||
@ -42,10 +42,10 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
CoverUrl = @"https://assets.ppy.sh/user-profile-covers/5287410/5cfeaa9dd41cbce038ecdc9d781396ed4b0108089170bf7f50492ef8eadeb368.jpeg",
|
||||
IsSupporter = true,
|
||||
},
|
||||
});
|
||||
}));
|
||||
|
||||
AddStep(@"set max", () => Room.MaxParticipants.Value = 10);
|
||||
AddStep(@"clear users", () => Room.Participants.Value = System.Array.Empty<User>());
|
||||
AddStep(@"clear users", () => Room.Participants.Clear());
|
||||
AddStep(@"set max to null", () => Room.MaxParticipants.Value = null);
|
||||
}
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
AddStep("set name", () => Room.Name.Value = "Room name");
|
||||
AddAssert("button disabled", () => !settings.ApplyButton.Enabled.Value);
|
||||
|
||||
AddStep("set beatmap", () => Room.Playlist.Add(new PlaylistItem { Beatmap = CreateBeatmap(Ruleset.Value).BeatmapInfo }));
|
||||
AddStep("set beatmap", () => Room.Playlist.Add(new PlaylistItem { Beatmap = { Value = CreateBeatmap(Ruleset.Value).BeatmapInfo } }));
|
||||
AddAssert("button enabled", () => settings.ApplyButton.Enabled.Value);
|
||||
|
||||
AddStep("clear name", () => Room.Name.Value = "");
|
||||
|
@ -5,9 +5,11 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Overlays.BeatmapSet;
|
||||
using osu.Game.Screens.Select.Details;
|
||||
|
||||
@ -22,6 +24,9 @@ namespace osu.Game.Tests.Visual.Online
|
||||
|
||||
private RatingsExposingDetails details;
|
||||
|
||||
[Cached]
|
||||
private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue);
|
||||
|
||||
[SetUp]
|
||||
public void Setup() => Schedule(() =>
|
||||
{
|
||||
@ -55,8 +60,12 @@ namespace osu.Game.Tests.Visual.Online
|
||||
{
|
||||
Fails = Enumerable.Range(1, 100).Select(_ => RNG.Next(10)).ToArray(),
|
||||
Retries = Enumerable.Range(-2, 100).Select(_ => RNG.Next(10)).ToArray(),
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
OnlineInfo = new BeatmapSetOnlineInfo
|
||||
{
|
||||
Status = BeatmapSetOnlineStatus.Ranked
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -5,11 +5,13 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Overlays.BeatmapSet;
|
||||
using osu.Game.Screens.Select.Details;
|
||||
using osuTK;
|
||||
@ -26,6 +28,9 @@ namespace osu.Game.Tests.Visual.Online
|
||||
|
||||
private GraphExposingSuccessRate successRate;
|
||||
|
||||
[Cached]
|
||||
private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue);
|
||||
|
||||
[SetUp]
|
||||
public void Setup() => Schedule(() =>
|
||||
{
|
||||
|
@ -7,11 +7,16 @@ using System.Collections.Generic;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Game.Screens.Select.Leaderboards;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Game.Overlays;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Online
|
||||
{
|
||||
public class TestSceneLeaderboardScopeSelector : OsuTestScene
|
||||
{
|
||||
[Cached]
|
||||
private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue);
|
||||
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(LeaderboardScopeSelector),
|
||||
|
@ -34,25 +34,7 @@ namespace osu.Game.Tests.Visual.Online
|
||||
{
|
||||
Current = { BindTarget = scope },
|
||||
Country = { BindTarget = countryBindable },
|
||||
Ruleset = { BindTarget = ruleset },
|
||||
Spotlights = new[]
|
||||
{
|
||||
new Spotlight
|
||||
{
|
||||
Id = 1,
|
||||
Text = "Spotlight 1"
|
||||
},
|
||||
new Spotlight
|
||||
{
|
||||
Id = 2,
|
||||
Text = "Spotlight 2"
|
||||
},
|
||||
new Spotlight
|
||||
{
|
||||
Id = 3,
|
||||
Text = "Spotlight 3"
|
||||
}
|
||||
}
|
||||
Ruleset = { BindTarget = ruleset }
|
||||
});
|
||||
|
||||
var country = new Country
|
||||
|
@ -35,6 +35,12 @@ namespace osu.Game.Tests.Visual.Online
|
||||
Add(selector = new SpotlightSelector());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestVisibility()
|
||||
{
|
||||
AddStep("Toggle Visibility", selector.ToggleVisibility);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestLocalSpotlights()
|
||||
{
|
||||
|
55
osu.Game.Tests/Visual/Online/TestSceneSpotlightsLayout.cs
Normal file
55
osu.Game.Tests/Visual/Online/TestSceneSpotlightsLayout.cs
Normal file
@ -0,0 +1,55 @@
|
||||
// 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.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Overlays.Rankings;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Catch;
|
||||
using osu.Game.Rulesets.Mania;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Rulesets.Taiko;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Online
|
||||
{
|
||||
public class TestSceneSpotlightsLayout : OsuTestScene
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(SpotlightsLayout),
|
||||
typeof(SpotlightSelector),
|
||||
};
|
||||
|
||||
protected override bool UseOnlineAPI => true;
|
||||
|
||||
[Cached]
|
||||
private readonly OverlayColourProvider overlayColour = new OverlayColourProvider(OverlayColourScheme.Green);
|
||||
|
||||
public TestSceneSpotlightsLayout()
|
||||
{
|
||||
var ruleset = new Bindable<RulesetInfo>(new OsuRuleset().RulesetInfo);
|
||||
|
||||
Add(new BasicScrollContainer
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Width = 0.8f,
|
||||
Child = new SpotlightsLayout
|
||||
{
|
||||
Ruleset = { BindTarget = ruleset }
|
||||
}
|
||||
});
|
||||
|
||||
AddStep("Osu ruleset", () => ruleset.Value = new OsuRuleset().RulesetInfo);
|
||||
AddStep("Mania ruleset", () => ruleset.Value = new ManiaRuleset().RulesetInfo);
|
||||
AddStep("Taiko ruleset", () => ruleset.Value = new TaikoRuleset().RulesetInfo);
|
||||
AddStep("Catch ruleset", () => ruleset.Value = new CatchRuleset().RulesetInfo);
|
||||
}
|
||||
}
|
||||
}
|
@ -17,6 +17,7 @@ using osu.Framework.Screens;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
@ -426,6 +427,44 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
AddAssert("start not requested", () => !startRequested);
|
||||
}
|
||||
|
||||
[TestCase(false)]
|
||||
[TestCase(true)]
|
||||
public void TestExternalBeatmapChangeWhileFiltered(bool differentRuleset)
|
||||
{
|
||||
createSongSelect();
|
||||
addManyTestMaps();
|
||||
|
||||
changeRuleset(0);
|
||||
|
||||
AddUntilStep("has selection", () => songSelect.Carousel.SelectedBeatmap != null);
|
||||
|
||||
AddStep("set filter text", () => songSelect.FilterControl.ChildrenOfType<SearchTextBox>().First().Text = "nonono");
|
||||
|
||||
AddUntilStep("dummy selected", () => Beatmap.Value is DummyWorkingBeatmap);
|
||||
|
||||
AddUntilStep("has no selection", () => songSelect.Carousel.SelectedBeatmap == null);
|
||||
|
||||
BeatmapInfo target = null;
|
||||
|
||||
AddStep("select beatmap externally", () =>
|
||||
{
|
||||
target = manager.GetAllUsableBeatmapSets().Where(b => b.Beatmaps.Any(bi => bi.RulesetID == (differentRuleset ? 1 : 0)))
|
||||
.ElementAt(5).Beatmaps.First();
|
||||
|
||||
Beatmap.Value = manager.GetWorkingBeatmap(target);
|
||||
});
|
||||
|
||||
AddUntilStep("has selection", () => songSelect.Carousel.SelectedBeatmap != null);
|
||||
|
||||
AddUntilStep("carousel has correct", () => songSelect.Carousel.SelectedBeatmap?.OnlineBeatmapID == target.OnlineBeatmapID);
|
||||
AddUntilStep("game has correct", () => Beatmap.Value.BeatmapInfo.OnlineBeatmapID == target.OnlineBeatmapID);
|
||||
|
||||
AddStep("reset filter text", () => songSelect.FilterControl.ChildrenOfType<SearchTextBox>().First().Text = string.Empty);
|
||||
|
||||
AddAssert("game still correct", () => Beatmap.Value?.BeatmapInfo.OnlineBeatmapID == target.OnlineBeatmapID);
|
||||
AddAssert("carousel still correct", () => songSelect.Carousel.SelectedBeatmap.OnlineBeatmapID == target.OnlineBeatmapID);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestAutoplayViaCtrlEnter()
|
||||
{
|
||||
@ -468,6 +507,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
private void importForRuleset(int id) => manager.Import(createTestBeatmapSet(getImportId(), rulesets.AvailableRulesets.Where(r => r.ID == id).ToArray())).Wait();
|
||||
|
||||
private static int importId;
|
||||
|
||||
private int getImportId() => ++importId;
|
||||
|
||||
private void checkMusicPlaying(bool playing) =>
|
||||
@ -551,6 +591,8 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
|
||||
public new Bindable<RulesetInfo> Ruleset => base.Ruleset;
|
||||
|
||||
public new FilterControl FilterControl => base.FilterControl;
|
||||
|
||||
public WorkingBeatmap CurrentBeatmap => Beatmap.Value;
|
||||
public WorkingBeatmap CurrentBeatmapDetailsBeatmap => BeatmapDetails.Beatmap;
|
||||
public new BeatmapCarousel Carousel => base.Carousel;
|
||||
|
40
osu.Game.Tests/Visual/UserInterface/TestSceneModDisplay.cs
Normal file
40
osu.Game.Tests/Visual/UserInterface/TestSceneModDisplay.cs
Normal file
@ -0,0 +1,40 @@
|
||||
// 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.Framework.Graphics;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Osu.Mods;
|
||||
using osu.Game.Screens.Play.HUD;
|
||||
|
||||
namespace osu.Game.Tests.Visual.UserInterface
|
||||
{
|
||||
public class TestSceneModDisplay : OsuTestScene
|
||||
{
|
||||
[TestCase(ExpansionMode.ExpandOnHover)]
|
||||
[TestCase(ExpansionMode.AlwaysExpanded)]
|
||||
[TestCase(ExpansionMode.AlwaysContracted)]
|
||||
public void TestMode(ExpansionMode mode)
|
||||
{
|
||||
AddStep("create mod display", () =>
|
||||
{
|
||||
Child = new ModDisplay
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
ExpansionMode = mode,
|
||||
Current =
|
||||
{
|
||||
Value = new Mod[]
|
||||
{
|
||||
new OsuModHardRock(),
|
||||
new OsuModDoubleTime(),
|
||||
new OsuModDifficultyAdjust(),
|
||||
new OsuModEasy(),
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -37,9 +37,9 @@ namespace osu.Game.Tests
|
||||
trackStore = audioManager.GetTrackStore(getZipReader());
|
||||
}
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
~WaveformTestBeatmap()
|
||||
{
|
||||
base.Dispose(isDisposing);
|
||||
// Remove the track store from the audio manager
|
||||
trackStore?.Dispose();
|
||||
}
|
||||
|
||||
|
@ -36,8 +36,9 @@ namespace osu.Game.Beatmaps
|
||||
using (var stream = new LineBufferedReader(store.GetStream(getPathForFile(BeatmapInfo.Path))))
|
||||
return Decoder.GetDecoder<Beatmap>(stream).Decode(stream);
|
||||
}
|
||||
catch
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Error(e, "Beatmap failed to load");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -59,8 +60,9 @@ namespace osu.Game.Beatmaps
|
||||
{
|
||||
return textureStore.Get(getPathForFile(Metadata.BackgroundFile));
|
||||
}
|
||||
catch
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Error(e, "Background failed to load");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -74,8 +76,9 @@ namespace osu.Game.Beatmaps
|
||||
{
|
||||
return new VideoSprite(textureStore.GetStream(getPathForFile(Metadata.VideoFile)));
|
||||
}
|
||||
catch
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Error(e, "Video failed to load");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -86,8 +89,9 @@ namespace osu.Game.Beatmaps
|
||||
{
|
||||
return (trackStore ??= AudioManager.GetTrackStore(store)).Get(getPathForFile(Metadata.AudioFile));
|
||||
}
|
||||
catch
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Error(e, "Track failed to load");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -115,8 +119,9 @@ namespace osu.Game.Beatmaps
|
||||
var trackData = store.GetStream(getPathForFile(Metadata.AudioFile));
|
||||
return trackData == null ? null : new Waveform(trackData);
|
||||
}
|
||||
catch
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Error(e, "Waveform failed to load");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ namespace osu.Game.Beatmaps.Drawables
|
||||
public class BeatmapSetOnlineStatusPill : CircularContainer
|
||||
{
|
||||
private readonly OsuSpriteText statusText;
|
||||
private readonly Box background;
|
||||
|
||||
private BeatmapSetOnlineStatus status;
|
||||
|
||||
@ -43,6 +44,12 @@ namespace osu.Game.Beatmaps.Drawables
|
||||
set => statusText.Padding = value;
|
||||
}
|
||||
|
||||
public Color4 BackgroundColour
|
||||
{
|
||||
get => background.Colour;
|
||||
set => background.Colour = value;
|
||||
}
|
||||
|
||||
public BeatmapSetOnlineStatusPill()
|
||||
{
|
||||
AutoSizeAxes = Axes.Both;
|
||||
@ -50,7 +57,7 @@ namespace osu.Game.Beatmaps.Drawables
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
background = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4.Black,
|
||||
|
@ -17,10 +17,11 @@ using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using osu.Game.Skinning;
|
||||
using osu.Framework.Graphics.Video;
|
||||
using osu.Framework.Logging;
|
||||
|
||||
namespace osu.Game.Beatmaps
|
||||
{
|
||||
public abstract class WorkingBeatmap : IWorkingBeatmap, IDisposable
|
||||
public abstract class WorkingBeatmap : IWorkingBeatmap
|
||||
{
|
||||
public readonly BeatmapInfo BeatmapInfo;
|
||||
|
||||
@ -133,11 +134,29 @@ namespace osu.Game.Beatmaps
|
||||
return converted;
|
||||
}
|
||||
|
||||
public override string ToString() => BeatmapInfo.ToString();
|
||||
private CancellationTokenSource loadCancellation = new CancellationTokenSource();
|
||||
|
||||
public bool BeatmapLoaded => beatmapLoadTask?.IsCompleted ?? false;
|
||||
/// <summary>
|
||||
/// Beings loading the contents of this <see cref="WorkingBeatmap"/> asynchronously.
|
||||
/// </summary>
|
||||
public void BeginAsyncLoad()
|
||||
{
|
||||
loadBeatmapAsync();
|
||||
}
|
||||
|
||||
public Task<IBeatmap> LoadBeatmapAsync() => beatmapLoadTask ??= Task.Factory.StartNew(() =>
|
||||
/// <summary>
|
||||
/// Cancels the asynchronous loading of the contents of this <see cref="WorkingBeatmap"/>.
|
||||
/// </summary>
|
||||
public void CancelAsyncLoad()
|
||||
{
|
||||
loadCancellation?.Cancel();
|
||||
loadCancellation = new CancellationTokenSource();
|
||||
|
||||
if (beatmapLoadTask?.IsCompleted != true)
|
||||
beatmapLoadTask = null;
|
||||
}
|
||||
|
||||
private Task<IBeatmap> loadBeatmapAsync() => beatmapLoadTask ??= Task.Factory.StartNew(() =>
|
||||
{
|
||||
// Todo: Handle cancellation during beatmap parsing
|
||||
var b = GetBeatmap() ?? new Beatmap();
|
||||
@ -149,7 +168,11 @@ namespace osu.Game.Beatmaps
|
||||
b.BeatmapInfo = BeatmapInfo;
|
||||
|
||||
return b;
|
||||
}, beatmapCancellation.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default);
|
||||
}, loadCancellation.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default);
|
||||
|
||||
public override string ToString() => BeatmapInfo.ToString();
|
||||
|
||||
public bool BeatmapLoaded => beatmapLoadTask?.IsCompleted ?? false;
|
||||
|
||||
public IBeatmap Beatmap
|
||||
{
|
||||
@ -157,16 +180,25 @@ namespace osu.Game.Beatmaps
|
||||
{
|
||||
try
|
||||
{
|
||||
return LoadBeatmapAsync().Result;
|
||||
return loadBeatmapAsync().Result;
|
||||
}
|
||||
catch (TaskCanceledException)
|
||||
catch (AggregateException ae)
|
||||
{
|
||||
// This is the exception that is generally expected here, which occurs via natural cancellation of the asynchronous load
|
||||
if (ae.InnerExceptions.FirstOrDefault() is TaskCanceledException)
|
||||
return null;
|
||||
|
||||
Logger.Error(ae, "Beatmap failed to load");
|
||||
return null;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Error(e, "Beatmap failed to load");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private readonly CancellationTokenSource beatmapCancellation = new CancellationTokenSource();
|
||||
protected abstract IBeatmap GetBeatmap();
|
||||
private Task<IBeatmap> beatmapLoadTask;
|
||||
|
||||
@ -217,40 +249,11 @@ namespace osu.Game.Beatmaps
|
||||
/// </summary>
|
||||
public virtual void RecycleTrack() => track.Recycle();
|
||||
|
||||
#region Disposal
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
private bool isDisposed;
|
||||
|
||||
protected virtual void Dispose(bool isDisposing)
|
||||
{
|
||||
if (isDisposed)
|
||||
return;
|
||||
|
||||
isDisposed = true;
|
||||
|
||||
// recycling logic is not here for the time being, as components which use
|
||||
// retrieved objects from WorkingBeatmap may not hold a reference to the WorkingBeatmap itself.
|
||||
// this should be fine as each retrieved component do have their own finalizers.
|
||||
|
||||
// cancelling the beatmap load is safe for now since the retrieval is a synchronous
|
||||
// operation. if we add an async retrieval method this may need to be reconsidered.
|
||||
beatmapCancellation?.Cancel();
|
||||
total_count.Value--;
|
||||
}
|
||||
|
||||
~WorkingBeatmap()
|
||||
{
|
||||
Dispose(false);
|
||||
total_count.Value--;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public class RecyclableLazy<T>
|
||||
{
|
||||
private Lazy<T> lazy;
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using JetBrains.Annotations;
|
||||
using osu.Framework.Bindables;
|
||||
@ -16,6 +17,10 @@ namespace osu.Game.Configuration
|
||||
/// An attribute to mark a bindable as being exposed to the user via settings controls.
|
||||
/// Can be used in conjunction with <see cref="SettingSourceExtensions.CreateSettingsControls"/> to automatically create UI controls.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// All controls with <see cref="OrderPosition"/> set will be placed first in ascending order.
|
||||
/// All controls with no <see cref="OrderPosition"/> will come afterward in default order.
|
||||
/// </remarks>
|
||||
[MeansImplicitUse]
|
||||
[AttributeUsage(AttributeTargets.Property)]
|
||||
public class SettingSourceAttribute : Attribute
|
||||
@ -24,18 +29,26 @@ namespace osu.Game.Configuration
|
||||
|
||||
public string Description { get; }
|
||||
|
||||
public int? OrderPosition { get; }
|
||||
|
||||
public SettingSourceAttribute(string label, string description = null)
|
||||
{
|
||||
Label = label ?? string.Empty;
|
||||
Description = description ?? string.Empty;
|
||||
}
|
||||
|
||||
public SettingSourceAttribute(string label, string description, int orderPosition)
|
||||
: this(label, description)
|
||||
{
|
||||
OrderPosition = orderPosition;
|
||||
}
|
||||
}
|
||||
|
||||
public static class SettingSourceExtensions
|
||||
{
|
||||
public static IEnumerable<Drawable> CreateSettingsControls(this object obj)
|
||||
{
|
||||
foreach (var (attr, property) in obj.GetSettingsSourceProperties())
|
||||
foreach (var (attr, property) in obj.GetOrderedSettingsSourceProperties())
|
||||
{
|
||||
object value = property.GetValue(obj);
|
||||
|
||||
@ -116,5 +129,15 @@ namespace osu.Game.Configuration
|
||||
yield return (attr, property);
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<(SettingSourceAttribute, PropertyInfo)> GetOrderedSettingsSourceProperties(this object obj)
|
||||
{
|
||||
var original = obj.GetSettingsSourceProperties();
|
||||
|
||||
var orderedRelative = original.Where(attr => attr.Item1.OrderPosition != null).OrderBy(attr => attr.Item1.OrderPosition);
|
||||
var unordered = original.Except(orderedRelative);
|
||||
|
||||
return orderedRelative.Concat(unordered);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -49,14 +49,7 @@ namespace osu.Game.Graphics.UserInterface
|
||||
public GradientLine()
|
||||
{
|
||||
RelativeSizeAxes = Axes.X;
|
||||
Size = new Vector2(0.8f, 1.5f);
|
||||
|
||||
ColumnDimensions = new[]
|
||||
{
|
||||
new Dimension(),
|
||||
new Dimension(mode: GridSizeMode.Relative, size: 0.4f),
|
||||
new Dimension(),
|
||||
};
|
||||
Size = new Vector2(0.8f, 1f);
|
||||
|
||||
Content = new[]
|
||||
{
|
||||
@ -65,16 +58,12 @@ namespace osu.Game.Graphics.UserInterface
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = ColourInfo.GradientHorizontal(Color4.Transparent, Color4.White)
|
||||
Colour = ColourInfo.GradientHorizontal(Color4.Transparent, Colour)
|
||||
},
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = ColourInfo.GradientHorizontal(Color4.White, Color4.Transparent)
|
||||
Colour = ColourInfo.GradientHorizontal(Colour, Color4.Transparent)
|
||||
},
|
||||
}
|
||||
};
|
||||
|
@ -26,6 +26,9 @@ namespace osu.Game.Online.API.Requests.Responses
|
||||
[JsonProperty(@"end_date")]
|
||||
public DateTimeOffset EndDate;
|
||||
|
||||
[JsonProperty(@"participant_count")]
|
||||
public int? Participants;
|
||||
|
||||
public override string ToString() => Name;
|
||||
}
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ namespace osu.Game.Online.Leaderboards
|
||||
|
||||
private List<ScoreComponentLabel> statisticsLabels;
|
||||
|
||||
[Resolved]
|
||||
[Resolved(CanBeNull = true)]
|
||||
private DialogOverlay dialogOverlay { get; set; }
|
||||
|
||||
public LeaderboardScore(ScoreInfo score, int rank, bool allowHighlight = true)
|
||||
|
@ -1,9 +1,10 @@
|
||||
// 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.Collections.Generic;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
@ -12,7 +13,7 @@ using osu.Game.Rulesets.Mods;
|
||||
|
||||
namespace osu.Game.Online.Multiplayer
|
||||
{
|
||||
public class PlaylistItem
|
||||
public class PlaylistItem : IEquatable<PlaylistItem>
|
||||
{
|
||||
[JsonProperty("id")]
|
||||
public int ID { get; set; }
|
||||
@ -24,24 +25,16 @@ namespace osu.Game.Online.Multiplayer
|
||||
public int RulesetID { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public BeatmapInfo Beatmap
|
||||
{
|
||||
get => beatmap;
|
||||
set
|
||||
{
|
||||
beatmap = value;
|
||||
BeatmapID = value?.OnlineBeatmapID ?? 0;
|
||||
}
|
||||
}
|
||||
public readonly Bindable<BeatmapInfo> Beatmap = new Bindable<BeatmapInfo>();
|
||||
|
||||
[JsonIgnore]
|
||||
public RulesetInfo Ruleset { get; set; }
|
||||
public readonly Bindable<RulesetInfo> Ruleset = new Bindable<RulesetInfo>();
|
||||
|
||||
[JsonIgnore]
|
||||
public readonly List<Mod> AllowedMods = new List<Mod>();
|
||||
public readonly BindableList<Mod> AllowedMods = new BindableList<Mod>();
|
||||
|
||||
[JsonIgnore]
|
||||
public readonly List<Mod> RequiredMods = new List<Mod>();
|
||||
public readonly BindableList<Mod> RequiredMods = new BindableList<Mod>();
|
||||
|
||||
[JsonProperty("beatmap")]
|
||||
private APIBeatmap apiBeatmap { get; set; }
|
||||
@ -64,16 +57,20 @@ namespace osu.Game.Online.Multiplayer
|
||||
set => requiredModsBacking = value;
|
||||
}
|
||||
|
||||
private BeatmapInfo beatmap;
|
||||
public PlaylistItem()
|
||||
{
|
||||
Beatmap.BindValueChanged(beatmap => BeatmapID = beatmap.NewValue?.OnlineBeatmapID ?? 0);
|
||||
Ruleset.BindValueChanged(ruleset => RulesetID = ruleset.NewValue?.ID ?? 0);
|
||||
}
|
||||
|
||||
public void MapObjects(BeatmapManager beatmaps, RulesetStore rulesets)
|
||||
{
|
||||
// If we don't have an api beatmap, the request occurred as a result of room creation, so we can query the local beatmap instead
|
||||
// Todo: Is this a bug? Room creation only returns the beatmap ID
|
||||
Beatmap = apiBeatmap == null ? beatmaps.QueryBeatmap(b => b.OnlineBeatmapID == BeatmapID) : apiBeatmap.ToBeatmap(rulesets);
|
||||
Ruleset = rulesets.GetRuleset(RulesetID);
|
||||
Beatmap.Value = apiBeatmap == null ? beatmaps.QueryBeatmap(b => b.OnlineBeatmapID == BeatmapID) : apiBeatmap.ToBeatmap(rulesets);
|
||||
Ruleset.Value = rulesets.GetRuleset(RulesetID);
|
||||
|
||||
Ruleset rulesetInstance = Ruleset.CreateInstance();
|
||||
Ruleset rulesetInstance = Ruleset.Value.CreateInstance();
|
||||
|
||||
if (allowedModsBacking != null)
|
||||
{
|
||||
@ -94,5 +91,14 @@ namespace osu.Game.Online.Multiplayer
|
||||
|
||||
public bool ShouldSerializeID() => false;
|
||||
public bool ShouldSerializeapiBeatmap() => false;
|
||||
|
||||
public bool Equals(PlaylistItem other) => ID == other?.ID && BeatmapID == other.BeatmapID && RulesetID == other.RulesetID;
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
// ReSharper disable NonReadonlyMemberInGetHashCode
|
||||
return HashCode.Combine(ID, BeatmapID, RulesetID);
|
||||
// ReSharper restore NonReadonlyMemberInGetHashCode
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,6 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using osu.Framework.Allocation;
|
||||
@ -31,10 +30,6 @@ namespace osu.Game.Online.Multiplayer
|
||||
[JsonProperty("playlist")]
|
||||
public BindableList<PlaylistItem> Playlist { get; private set; } = new BindableList<PlaylistItem>();
|
||||
|
||||
[Cached]
|
||||
[JsonIgnore]
|
||||
public Bindable<PlaylistItem> CurrentItem { get; private set; } = new Bindable<PlaylistItem>();
|
||||
|
||||
[Cached]
|
||||
[JsonProperty("channel_id")]
|
||||
public Bindable<int> ChannelId { get; private set; } = new Bindable<int>();
|
||||
@ -65,23 +60,11 @@ namespace osu.Game.Online.Multiplayer
|
||||
|
||||
[Cached]
|
||||
[JsonIgnore]
|
||||
public Bindable<IEnumerable<User>> Participants { get; private set; } = new Bindable<IEnumerable<User>>(Enumerable.Empty<User>());
|
||||
public BindableList<User> Participants { get; private set; } = new BindableList<User>();
|
||||
|
||||
[Cached]
|
||||
public Bindable<int> ParticipantCount { get; private set; } = new Bindable<int>();
|
||||
|
||||
public Room()
|
||||
{
|
||||
Playlist.ItemsAdded += updateCurrent;
|
||||
Playlist.ItemsRemoved += updateCurrent;
|
||||
updateCurrent(Playlist);
|
||||
}
|
||||
|
||||
private void updateCurrent(IEnumerable<PlaylistItem> playlist)
|
||||
{
|
||||
CurrentItem.Value = playlist.FirstOrDefault();
|
||||
}
|
||||
|
||||
// todo: TEMPORARY
|
||||
[JsonProperty("participant_count")]
|
||||
private int? participantCount
|
||||
@ -130,17 +113,18 @@ namespace osu.Game.Online.Multiplayer
|
||||
Type.Value = other.Type.Value;
|
||||
MaxParticipants.Value = other.MaxParticipants.Value;
|
||||
ParticipantCount.Value = other.ParticipantCount.Value;
|
||||
Participants.Value = other.Participants.Value.ToArray();
|
||||
EndDate.Value = other.EndDate.Value;
|
||||
|
||||
if (DateTimeOffset.Now >= EndDate.Value)
|
||||
Status.Value = new RoomStatusEnded();
|
||||
|
||||
// Todo: Temporary, should only remove/add new items (requires framework changes)
|
||||
if (Playlist.Count == 0)
|
||||
Playlist.AddRange(other.Playlist);
|
||||
else if (other.Playlist.Count > 0)
|
||||
Playlist.First().ID = other.Playlist.First().ID;
|
||||
foreach (var removedItem in Playlist.Except(other.Playlist).ToArray())
|
||||
Playlist.Remove(removedItem);
|
||||
Playlist.AddRange(other.Playlist.Except(Playlist).ToArray());
|
||||
|
||||
foreach (var removedItem in Participants.Except(other.Participants).ToArray())
|
||||
Participants.Remove(removedItem);
|
||||
Participants.AddRange(other.Participants.Except(Participants).ToArray());
|
||||
|
||||
Position = other.Position;
|
||||
}
|
||||
|
@ -401,15 +401,14 @@ namespace osu.Game
|
||||
if (nextBeatmap?.Track != null)
|
||||
nextBeatmap.Track.Completed += currentTrackCompleted;
|
||||
|
||||
using (var oldBeatmap = beatmap.OldValue)
|
||||
{
|
||||
if (oldBeatmap?.Track != null)
|
||||
oldBeatmap.Track.Completed -= currentTrackCompleted;
|
||||
}
|
||||
var oldBeatmap = beatmap.OldValue;
|
||||
if (oldBeatmap?.Track != null)
|
||||
oldBeatmap.Track.Completed -= currentTrackCompleted;
|
||||
|
||||
updateModDefaults();
|
||||
|
||||
nextBeatmap?.LoadBeatmapAsync();
|
||||
oldBeatmap?.CancelAsyncLoad();
|
||||
nextBeatmap?.BeginAsyncLoad();
|
||||
}
|
||||
|
||||
private void modsChanged(ValueChangedEvent<IReadOnlyList<Mod>> mods)
|
||||
|
@ -150,7 +150,7 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons
|
||||
},
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = BeatmapSet.Value.OnlineInfo.HasVideo && noVideo ? "without Video" : string.Empty,
|
||||
Text = getVideoSuffixText(),
|
||||
Font = OsuFont.GetFont(size: 11, weight: FontWeight.Bold)
|
||||
},
|
||||
};
|
||||
@ -163,5 +163,13 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons
|
||||
private void userChanged(ValueChangedEvent<User> e) => button.Enabled.Value = !(e.NewValue is GuestUser);
|
||||
|
||||
private void enabledChanged(ValueChangedEvent<bool> e) => this.FadeColour(e.NewValue ? Color4.White : Color4.Gray, 200, Easing.OutQuint);
|
||||
|
||||
private string getVideoSuffixText()
|
||||
{
|
||||
if (!BeatmapSet.Value.OnlineInfo.HasVideo)
|
||||
return string.Empty;
|
||||
|
||||
return noVideo ? "without Video" : "with Video";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,6 @@
|
||||
|
||||
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;
|
||||
@ -14,7 +13,6 @@ using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Overlays.Direct;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Overlays.BeatmapSet.Buttons
|
||||
{
|
||||
@ -22,7 +20,7 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons
|
||||
{
|
||||
private const float transition_duration = 500;
|
||||
|
||||
private readonly Box bg, progress;
|
||||
private readonly Box background, progress;
|
||||
private readonly PlayButton playButton;
|
||||
|
||||
private PreviewTrack preview => playButton.Preview;
|
||||
@ -40,10 +38,10 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
bg = new Box
|
||||
background = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4.Black.Opacity(0.25f),
|
||||
Alpha = 0.5f
|
||||
},
|
||||
new Container
|
||||
{
|
||||
@ -71,9 +69,10 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
private void load(OsuColour colours, OverlayColourProvider colourProvider)
|
||||
{
|
||||
progress.Colour = colours.Yellow;
|
||||
background.Colour = colourProvider.Background6;
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
@ -91,13 +90,13 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons
|
||||
|
||||
protected override bool OnHover(HoverEvent e)
|
||||
{
|
||||
bg.FadeColour(Color4.Black.Opacity(0.5f), 100);
|
||||
background.FadeTo(0.75f, 80);
|
||||
return base.OnHover(e);
|
||||
}
|
||||
|
||||
protected override void OnHoverLost(HoverLostEvent e)
|
||||
{
|
||||
bg.FadeColour(Color4.Black.Opacity(0.25f), 100);
|
||||
background.FadeTo(0.5f, 80);
|
||||
base.OnHoverLost(e);
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,6 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
@ -10,7 +9,6 @@ using osu.Game.Beatmaps;
|
||||
using osu.Game.Overlays.BeatmapSet.Buttons;
|
||||
using osu.Game.Screens.Select.Details;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Overlays.BeatmapSet
|
||||
{
|
||||
@ -21,6 +19,7 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
private readonly PreviewButton preview;
|
||||
private readonly BasicStats basic;
|
||||
private readonly AdvancedStats advanced;
|
||||
private readonly DetailBox ratingBox;
|
||||
|
||||
private BeatmapSetInfo beatmapSet;
|
||||
|
||||
@ -54,6 +53,7 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
private void updateDisplay()
|
||||
{
|
||||
Ratings.Metrics = BeatmapSet?.Metrics;
|
||||
ratingBox.Alpha = BeatmapSet?.OnlineInfo?.Status > 0 ? 1 : 0;
|
||||
}
|
||||
|
||||
public Details()
|
||||
@ -86,7 +86,7 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
Margin = new MarginPadding { Vertical = 7.5f },
|
||||
},
|
||||
},
|
||||
new DetailBox
|
||||
ratingBox = new DetailBox
|
||||
{
|
||||
Child = Ratings = new UserRatings
|
||||
{
|
||||
@ -107,6 +107,8 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
private class DetailBox : Container
|
||||
{
|
||||
private readonly Container content;
|
||||
private readonly Box background;
|
||||
|
||||
protected override Container<Drawable> Content => content;
|
||||
|
||||
public DetailBox()
|
||||
@ -116,10 +118,10 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
background = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4.Black.Opacity(0.5f),
|
||||
Alpha = 0.5f
|
||||
},
|
||||
content = new Container
|
||||
{
|
||||
@ -129,6 +131,12 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OverlayColourProvider colourProvider)
|
||||
{
|
||||
background.Colour = colourProvider.Background6;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
// 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.
|
||||
|
||||
using System.Linq;
|
||||
@ -30,6 +30,7 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
private const float buttons_spacing = 5;
|
||||
|
||||
private readonly UpdateableBeatmapSetCover cover;
|
||||
private readonly Box coverGradient;
|
||||
private readonly OsuSpriteText title, artist;
|
||||
private readonly AuthorInfo author;
|
||||
private readonly FillFlowContainer downloadButtonsContainer;
|
||||
@ -93,10 +94,9 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Masking = true,
|
||||
},
|
||||
new Box
|
||||
coverGradient = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = ColourInfo.GradientVertical(Color4.Black.Opacity(0.3f), Color4.Black.Opacity(0.8f)),
|
||||
RelativeSizeAxes = Axes.Both
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -106,8 +106,7 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Padding = new MarginPadding
|
||||
{
|
||||
Top = 20,
|
||||
Bottom = 30,
|
||||
Vertical = BeatmapSetOverlay.Y_PADDING,
|
||||
Left = BeatmapSetOverlay.X_PADDING,
|
||||
Right = BeatmapSetOverlay.X_PADDING + BeatmapSetOverlay.RIGHT_WIDTH,
|
||||
},
|
||||
@ -130,11 +129,12 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
{
|
||||
Direction = FillDirection.Horizontal,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Margin = new MarginPadding { Top = 15 },
|
||||
Children = new Drawable[]
|
||||
{
|
||||
title = new OsuSpriteText
|
||||
{
|
||||
Font = OsuFont.GetFont(size: 37, weight: FontWeight.Bold, italics: true)
|
||||
Font = OsuFont.GetFont(size: 30, weight: FontWeight.SemiBold, italics: true)
|
||||
},
|
||||
externalLink = new ExternalLinkButton
|
||||
{
|
||||
@ -144,7 +144,7 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
},
|
||||
}
|
||||
},
|
||||
artist = new OsuSpriteText { Font = OsuFont.GetFont(size: 25, weight: FontWeight.SemiBold, italics: true) },
|
||||
artist = new OsuSpriteText { Font = OsuFont.GetFont(size: 20, weight: FontWeight.Medium, italics: true) },
|
||||
new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
@ -187,7 +187,7 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
Anchor = Anchor.BottomRight,
|
||||
Origin = Anchor.BottomRight,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Margin = new MarginPadding { Top = BeatmapSetOverlay.TOP_PADDING, Right = BeatmapSetOverlay.X_PADDING },
|
||||
Margin = new MarginPadding { Top = BeatmapSetOverlay.Y_PADDING, Right = BeatmapSetOverlay.X_PADDING },
|
||||
Direction = FillDirection.Vertical,
|
||||
Spacing = new Vector2(10),
|
||||
Children = new Drawable[]
|
||||
@ -197,7 +197,7 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
Anchor = Anchor.TopRight,
|
||||
Origin = Anchor.TopRight,
|
||||
TextSize = 14,
|
||||
TextPadding = new MarginPadding { Horizontal = 25, Vertical = 8 }
|
||||
TextPadding = new MarginPadding { Horizontal = 35, Vertical = 10 }
|
||||
},
|
||||
Details = new Details(),
|
||||
},
|
||||
@ -215,8 +215,11 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
private void load(OverlayColourProvider colourProvider)
|
||||
{
|
||||
coverGradient.Colour = ColourInfo.GradientVertical(colourProvider.Background6.Opacity(0.3f), colourProvider.Background6.Opacity(0.8f));
|
||||
onlineStatusPill.BackgroundColour = colourProvider.Background6;
|
||||
|
||||
State.BindValueChanged(_ => updateDownloadButtons());
|
||||
|
||||
BeatmapSet.BindValueChanged(setInfo =>
|
||||
|
@ -38,6 +38,8 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
public Info()
|
||||
{
|
||||
MetadataSection source, tags, genre, language;
|
||||
OsuSpriteText unrankedPlaceholder;
|
||||
|
||||
RelativeSizeAxes = Axes.X;
|
||||
Height = 220;
|
||||
Masking = true;
|
||||
@ -110,6 +112,14 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Padding = new MarginPadding { Top = 20, Horizontal = 15 },
|
||||
},
|
||||
unrankedPlaceholder = new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Alpha = 0,
|
||||
Text = "Unranked beatmap",
|
||||
Font = OsuFont.GetFont(size: 12)
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -122,6 +132,9 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
tags.Text = b.NewValue?.Metadata.Tags ?? string.Empty;
|
||||
genre.Text = b.NewValue?.OnlineInfo?.Genre?.Name ?? string.Empty;
|
||||
language.Text = b.NewValue?.OnlineInfo?.Language?.Name ?? string.Empty;
|
||||
var setHasLeaderboard = b.NewValue?.OnlineInfo?.Status > 0;
|
||||
successRate.Alpha = setHasLeaderboard ? 1 : 0;
|
||||
unrankedPlaceholder.Alpha = setHasLeaderboard ? 0 : 1;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -26,10 +26,10 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
private void load(OverlayColourProvider colourProvider)
|
||||
{
|
||||
AccentColour = colours.Blue;
|
||||
LineColour = Color4.Gray;
|
||||
AccentColour = colourProvider.Highlight1;
|
||||
LineColour = colourProvider.Background1;
|
||||
}
|
||||
|
||||
private class ScopeSelectorTabItem : PageTabItem
|
||||
|
@ -77,9 +77,9 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
new TableColumn("rank", Anchor.CentreRight, new Dimension(GridSizeMode.AutoSize)),
|
||||
new TableColumn("", Anchor.Centre, new Dimension(GridSizeMode.Absolute, 70)), // grade
|
||||
new TableColumn("score", Anchor.CentreLeft, new Dimension(GridSizeMode.AutoSize)),
|
||||
new TableColumn("accuracy", Anchor.CentreLeft, new Dimension(GridSizeMode.AutoSize)),
|
||||
new TableColumn("accuracy", Anchor.CentreLeft, new Dimension(GridSizeMode.Distributed, minSize: 60, maxSize: 70)),
|
||||
new TableColumn("player", Anchor.CentreLeft, new Dimension(GridSizeMode.Distributed, minSize: 150)),
|
||||
new TableColumn("max combo", Anchor.CentreLeft, new Dimension(GridSizeMode.Distributed, minSize: 70, maxSize: 90))
|
||||
new TableColumn("max combo", Anchor.CentreLeft, new Dimension(GridSizeMode.Distributed, minSize: 70, maxSize: 110))
|
||||
};
|
||||
|
||||
foreach (var statistic in score.SortedStatistics)
|
||||
|
@ -30,7 +30,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
RelativeSizeAxes = Axes.X;
|
||||
Height = 25;
|
||||
|
||||
CornerRadius = 3;
|
||||
CornerRadius = 5;
|
||||
Masking = true;
|
||||
|
||||
InternalChildren = new Drawable[]
|
||||
|
@ -164,7 +164,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Masking = true,
|
||||
CornerRadius = 10,
|
||||
CornerRadius = 5,
|
||||
Child = loading = new DimmedLoadingLayer(iconScale: 0.8f)
|
||||
{
|
||||
Alpha = 0,
|
||||
|
@ -96,13 +96,14 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
Font = OsuFont.GetFont(size: 10, weight: FontWeight.Bold)
|
||||
Font = OsuFont.GetFont(size: 10)
|
||||
},
|
||||
flag = new UpdateableFlag
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
Size = new Vector2(19, 13),
|
||||
Margin = new MarginPadding { Top = 3 }, // makes spacing look more even
|
||||
ShowPlaceholderOnNull = false,
|
||||
},
|
||||
}
|
||||
|
@ -42,7 +42,7 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
int playCount = beatmap?.OnlineInfo?.PlayCount ?? 0;
|
||||
|
||||
var rate = playCount != 0 ? (float)passCount / playCount : 0;
|
||||
successPercent.Text = rate.ToString("0%");
|
||||
successPercent.Text = rate.ToString("0.#%");
|
||||
successRate.Length = rate;
|
||||
percentContainer.ResizeWidthTo(successRate.Length, 250, Easing.InOutCubic);
|
||||
|
||||
@ -105,10 +105,10 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
private void load(OsuColour colours, OverlayColourProvider colourProvider)
|
||||
{
|
||||
successRate.AccentColour = colours.Green;
|
||||
successRate.BackgroundColour = colours.GrayD;
|
||||
successRate.BackgroundColour = colourProvider.Background6;
|
||||
|
||||
updateDisplay();
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ namespace osu.Game.Overlays
|
||||
public class BeatmapSetOverlay : FullscreenOverlay
|
||||
{
|
||||
public const float X_PADDING = 40;
|
||||
public const float TOP_PADDING = 25;
|
||||
public const float Y_PADDING = 25;
|
||||
public const float RIGHT_WIDTH = 275;
|
||||
protected readonly Header Header;
|
||||
|
||||
|
@ -19,7 +19,7 @@ namespace osu.Game.Overlays.Direct
|
||||
public DownloadProgressBar(BeatmapSetInfo beatmapSet)
|
||||
: base(beatmapSet)
|
||||
{
|
||||
AddInternal(progressBar = new ProgressBar
|
||||
AddInternal(progressBar = new InteractionDisabledProgressBar
|
||||
{
|
||||
Height = 0,
|
||||
Alpha = 0,
|
||||
@ -64,5 +64,11 @@ namespace osu.Game.Overlays.Direct
|
||||
}
|
||||
}, true);
|
||||
}
|
||||
|
||||
private class InteractionDisabledProgressBar : ProgressBar
|
||||
{
|
||||
public override bool HandlePositionalInput => false;
|
||||
public override bool HandleNonPositionalInput => false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,25 +6,14 @@ using osu.Framework.Bindables;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Users;
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Allocation;
|
||||
|
||||
namespace osu.Game.Overlays.Rankings
|
||||
{
|
||||
public class RankingsOverlayHeader : TabControlOverlayHeader<RankingsScope>
|
||||
{
|
||||
public readonly Bindable<RulesetInfo> Ruleset = new Bindable<RulesetInfo>();
|
||||
public readonly Bindable<Spotlight> Spotlight = new Bindable<Spotlight>();
|
||||
public readonly Bindable<Country> Country = new Bindable<Country>();
|
||||
|
||||
public IEnumerable<Spotlight> Spotlights
|
||||
{
|
||||
get => spotlightsContainer.Spotlights;
|
||||
set => spotlightsContainer.Spotlights = value;
|
||||
}
|
||||
|
||||
protected override ScreenTitle CreateTitle() => new RankingsTitle
|
||||
{
|
||||
Scope = { BindTarget = Current }
|
||||
@ -35,35 +24,11 @@ namespace osu.Game.Overlays.Rankings
|
||||
Current = Ruleset
|
||||
};
|
||||
|
||||
private SpotlightsContainer spotlightsContainer;
|
||||
|
||||
protected override Drawable CreateContent() => new FillFlowContainer
|
||||
protected override Drawable CreateContent() => new CountryFilter
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Direction = FillDirection.Vertical,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new CountryFilter
|
||||
{
|
||||
Current = Country
|
||||
},
|
||||
spotlightsContainer = new SpotlightsContainer
|
||||
{
|
||||
Spotlight = { BindTarget = Spotlight }
|
||||
}
|
||||
}
|
||||
Current = Country
|
||||
};
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
Current.BindValueChanged(onCurrentChanged, true);
|
||||
base.LoadComplete();
|
||||
}
|
||||
|
||||
private void onCurrentChanged(ValueChangedEvent<RankingsScope> scope) =>
|
||||
spotlightsContainer.FadeTo(scope.NewValue == RankingsScope.Spotlights ? 1 : 0, 200, Easing.OutQuint);
|
||||
|
||||
private class RankingsTitle : ScreenTitle
|
||||
{
|
||||
public readonly Bindable<RankingsScope> Scope = new Bindable<RankingsScope>();
|
||||
@ -81,48 +46,6 @@ namespace osu.Game.Overlays.Rankings
|
||||
|
||||
protected override Drawable CreateIcon() => new ScreenTitleTextureIcon(@"Icons/rankings");
|
||||
}
|
||||
|
||||
private class SpotlightsContainer : CompositeDrawable
|
||||
{
|
||||
public readonly Bindable<Spotlight> Spotlight = new Bindable<Spotlight>();
|
||||
|
||||
public IEnumerable<Spotlight> Spotlights
|
||||
{
|
||||
get => dropdown.Items;
|
||||
set => dropdown.Items = value;
|
||||
}
|
||||
|
||||
private readonly OsuDropdown<Spotlight> dropdown;
|
||||
private readonly Box background;
|
||||
|
||||
public SpotlightsContainer()
|
||||
{
|
||||
Height = 100;
|
||||
RelativeSizeAxes = Axes.X;
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
background = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
dropdown = new OsuDropdown<Spotlight>
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Width = 0.8f,
|
||||
Current = Spotlight,
|
||||
Y = 20,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OverlayColourProvider colourProvider)
|
||||
{
|
||||
background.Colour = colourProvider.Dark3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum RankingsScope
|
||||
|
@ -1,18 +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 Newtonsoft.Json;
|
||||
|
||||
namespace osu.Game.Overlays.Rankings
|
||||
{
|
||||
public class Spotlight
|
||||
{
|
||||
[JsonProperty("id")]
|
||||
public int Id;
|
||||
|
||||
[JsonProperty("text")]
|
||||
public string Text;
|
||||
|
||||
public override string ToString() => Text;
|
||||
}
|
||||
}
|
@ -14,11 +14,14 @@ using osuTK;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Game.Online.API.Requests;
|
||||
|
||||
namespace osu.Game.Overlays.Rankings
|
||||
{
|
||||
public class SpotlightSelector : CompositeDrawable, IHasCurrentValue<APISpotlight>
|
||||
public class SpotlightSelector : VisibilityContainer, IHasCurrentValue<APISpotlight>
|
||||
{
|
||||
private const int duration = 300;
|
||||
|
||||
private readonly Box background;
|
||||
private readonly SpotlightsDropdown dropdown;
|
||||
|
||||
@ -36,50 +39,60 @@ namespace osu.Game.Overlays.Rankings
|
||||
set => dropdown.Items = value;
|
||||
}
|
||||
|
||||
protected override bool StartHidden => true;
|
||||
|
||||
private readonly InfoColumn startDateColumn;
|
||||
private readonly InfoColumn endDateColumn;
|
||||
private readonly InfoColumn mapCountColumn;
|
||||
private readonly InfoColumn participantsColumn;
|
||||
private readonly Container content;
|
||||
|
||||
public SpotlightSelector()
|
||||
{
|
||||
RelativeSizeAxes = Axes.X;
|
||||
Height = 100;
|
||||
|
||||
InternalChildren = new Drawable[]
|
||||
Add(content = new Container
|
||||
{
|
||||
background = new Box
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Padding = new MarginPadding { Horizontal = UserProfileOverlay.CONTENT_X_MARGIN, Vertical = 10 },
|
||||
Children = new Drawable[]
|
||||
background = new Box
|
||||
{
|
||||
dropdown = new SpotlightsDropdown
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Padding = new MarginPadding { Horizontal = UserProfileOverlay.CONTENT_X_MARGIN, Vertical = 10 },
|
||||
Children = new Drawable[]
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Current = Current,
|
||||
Depth = -float.MaxValue
|
||||
},
|
||||
new FillFlowContainer
|
||||
{
|
||||
Anchor = Anchor.BottomRight,
|
||||
Origin = Anchor.BottomRight,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Horizontal,
|
||||
Spacing = new Vector2(15, 0),
|
||||
Children = new Drawable[]
|
||||
dropdown = new SpotlightsDropdown
|
||||
{
|
||||
startDateColumn = new InfoColumn(@"Start Date"),
|
||||
endDateColumn = new InfoColumn(@"End Date"),
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Current = Current,
|
||||
Depth = -float.MaxValue
|
||||
},
|
||||
new FillFlowContainer
|
||||
{
|
||||
Anchor = Anchor.BottomRight,
|
||||
Origin = Anchor.BottomRight,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Horizontal,
|
||||
Spacing = new Vector2(15, 0),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
startDateColumn = new InfoColumn(@"Start Date"),
|
||||
endDateColumn = new InfoColumn(@"End Date"),
|
||||
mapCountColumn = new InfoColumn(@"Map Count"),
|
||||
participantsColumn = new InfoColumn(@"Participants")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
@ -88,18 +101,17 @@ namespace osu.Game.Overlays.Rankings
|
||||
background.Colour = colourProvider.Dark3;
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
public void ShowInfo(GetSpotlightRankingsResponse response)
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
Current.BindValueChanged(onCurrentChanged);
|
||||
startDateColumn.Value = dateToString(response.Spotlight.StartDate);
|
||||
endDateColumn.Value = dateToString(response.Spotlight.EndDate);
|
||||
mapCountColumn.Value = response.BeatmapSets.Count.ToString();
|
||||
participantsColumn.Value = response.Spotlight.Participants?.ToString("N0");
|
||||
}
|
||||
|
||||
private void onCurrentChanged(ValueChangedEvent<APISpotlight> spotlight)
|
||||
{
|
||||
startDateColumn.Value = dateToString(spotlight.NewValue.StartDate);
|
||||
endDateColumn.Value = dateToString(spotlight.NewValue.EndDate);
|
||||
}
|
||||
protected override void PopIn() => content.FadeIn(duration, Easing.OutQuint);
|
||||
|
||||
protected override void PopOut() => content.FadeOut(duration, Easing.OutQuint);
|
||||
|
||||
private string dateToString(DateTimeOffset date) => date.ToString("yyyy-MM-dd");
|
||||
|
||||
|
161
osu.Game/Overlays/Rankings/SpotlightsLayout.cs
Normal file
161
osu.Game/Overlays/Rankings/SpotlightsLayout.cs
Normal file
@ -0,0 +1,161 @@
|
||||
// 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.Graphics;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osuTK;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Online.API.Requests;
|
||||
using osu.Game.Overlays.Rankings.Tables;
|
||||
using System.Linq;
|
||||
using osu.Game.Overlays.Direct;
|
||||
using System.Threading;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
|
||||
namespace osu.Game.Overlays.Rankings
|
||||
{
|
||||
public class SpotlightsLayout : CompositeDrawable
|
||||
{
|
||||
public readonly Bindable<RulesetInfo> Ruleset = new Bindable<RulesetInfo>();
|
||||
|
||||
private readonly Bindable<APISpotlight> selectedSpotlight = new Bindable<APISpotlight>();
|
||||
|
||||
[Resolved]
|
||||
private IAPIProvider api { get; set; }
|
||||
|
||||
[Resolved]
|
||||
private RulesetStore rulesets { get; set; }
|
||||
|
||||
private CancellationTokenSource cancellationToken;
|
||||
private GetSpotlightRankingsRequest getRankingsRequest;
|
||||
private GetSpotlightsRequest spotlightsRequest;
|
||||
|
||||
private SpotlightSelector selector;
|
||||
private Container content;
|
||||
private DimmedLoadingLayer loading;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
RelativeSizeAxes = Axes.X;
|
||||
AutoSizeAxes = Axes.Y;
|
||||
InternalChild = new ReverseChildIDFillFlowContainer<Drawable>
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Direction = FillDirection.Vertical,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
selector = new SpotlightSelector
|
||||
{
|
||||
Current = selectedSpotlight,
|
||||
},
|
||||
new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
content = new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Margin = new MarginPadding { Vertical = 10 }
|
||||
},
|
||||
loading = new DimmedLoadingLayer()
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
selector.Show();
|
||||
|
||||
selectedSpotlight.BindValueChanged(onSpotlightChanged);
|
||||
Ruleset.BindValueChanged(onRulesetChanged);
|
||||
|
||||
getSpotlights();
|
||||
}
|
||||
|
||||
private void getSpotlights()
|
||||
{
|
||||
spotlightsRequest = new GetSpotlightsRequest();
|
||||
spotlightsRequest.Success += response => selector.Spotlights = response.Spotlights;
|
||||
api.Queue(spotlightsRequest);
|
||||
}
|
||||
|
||||
private void onRulesetChanged(ValueChangedEvent<RulesetInfo> ruleset)
|
||||
{
|
||||
if (!selector.Spotlights.Any())
|
||||
return;
|
||||
|
||||
selectedSpotlight.TriggerChange();
|
||||
}
|
||||
|
||||
private void onSpotlightChanged(ValueChangedEvent<APISpotlight> spotlight)
|
||||
{
|
||||
loading.Show();
|
||||
|
||||
cancellationToken?.Cancel();
|
||||
getRankingsRequest?.Cancel();
|
||||
|
||||
getRankingsRequest = new GetSpotlightRankingsRequest(Ruleset.Value, spotlight.NewValue.Id);
|
||||
getRankingsRequest.Success += onSuccess;
|
||||
api.Queue(getRankingsRequest);
|
||||
}
|
||||
|
||||
private void onSuccess(GetSpotlightRankingsResponse response)
|
||||
{
|
||||
LoadComponentAsync(createContent(response), loaded =>
|
||||
{
|
||||
selector.ShowInfo(response);
|
||||
|
||||
content.Clear();
|
||||
content.Add(loaded);
|
||||
|
||||
loading.Hide();
|
||||
}, (cancellationToken = new CancellationTokenSource()).Token);
|
||||
}
|
||||
|
||||
private Drawable createContent(GetSpotlightRankingsResponse response) => new FillFlowContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Y,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Direction = FillDirection.Vertical,
|
||||
Spacing = new Vector2(0, 20),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new ScoresTable(1, response.Users),
|
||||
new FillFlowContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Y,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Spacing = new Vector2(10),
|
||||
Children = response.BeatmapSets.Select(b => new DirectGridPanel(b.ToBeatmapSet(rulesets))
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
}).ToList()
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
{
|
||||
base.Dispose(isDisposing);
|
||||
|
||||
spotlightsRequest?.Cancel();
|
||||
getRankingsRequest?.Cancel();
|
||||
cancellationToken?.Cancel();
|
||||
}
|
||||
}
|
||||
}
|
@ -24,7 +24,7 @@ namespace osu.Game.Overlays
|
||||
private readonly Bindable<RulesetInfo> ruleset = new Bindable<RulesetInfo>();
|
||||
|
||||
private readonly BasicScrollContainer scrollFlow;
|
||||
private readonly Container tableContainer;
|
||||
private readonly Container contentContainer;
|
||||
private readonly DimmedLoadingLayer loading;
|
||||
private readonly Box background;
|
||||
|
||||
@ -69,13 +69,13 @@ namespace osu.Game.Overlays
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
tableContainer = new Container
|
||||
contentContainer = new Container
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Margin = new MarginPadding { Vertical = 10 }
|
||||
Margin = new MarginPadding { Bottom = 10 }
|
||||
},
|
||||
loading = new DimmedLoadingLayer(),
|
||||
}
|
||||
@ -112,7 +112,13 @@ namespace osu.Game.Overlays
|
||||
Scheduler.AddOnce(loadNewContent);
|
||||
}, true);
|
||||
|
||||
ruleset.BindValueChanged(_ => Scheduler.AddOnce(loadNewContent), true);
|
||||
ruleset.BindValueChanged(_ =>
|
||||
{
|
||||
if (Scope.Value == RankingsScope.Spotlights)
|
||||
return;
|
||||
|
||||
Scheduler.AddOnce(loadNewContent);
|
||||
}, true);
|
||||
|
||||
base.LoadComplete();
|
||||
}
|
||||
@ -134,17 +140,26 @@ namespace osu.Game.Overlays
|
||||
cancellationToken?.Cancel();
|
||||
lastRequest?.Cancel();
|
||||
|
||||
if (Scope.Value == RankingsScope.Spotlights)
|
||||
{
|
||||
loadContent(new SpotlightsLayout
|
||||
{
|
||||
Ruleset = { BindTarget = ruleset }
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
var request = createScopedRequest();
|
||||
lastRequest = request;
|
||||
|
||||
if (request == null)
|
||||
{
|
||||
loadTable(null);
|
||||
loadContent(null);
|
||||
return;
|
||||
}
|
||||
|
||||
request.Success += () => loadTable(createTableFromResponse(request));
|
||||
request.Failure += _ => loadTable(null);
|
||||
request.Success += () => loadContent(createTableFromResponse(request));
|
||||
request.Failure += _ => loadContent(null);
|
||||
|
||||
api.Queue(request);
|
||||
}
|
||||
@ -189,21 +204,21 @@ namespace osu.Game.Overlays
|
||||
return null;
|
||||
}
|
||||
|
||||
private void loadTable(Drawable table)
|
||||
private void loadContent(Drawable content)
|
||||
{
|
||||
scrollFlow.ScrollToStart();
|
||||
|
||||
if (table == null)
|
||||
if (content == null)
|
||||
{
|
||||
tableContainer.Clear();
|
||||
contentContainer.Clear();
|
||||
loading.Hide();
|
||||
return;
|
||||
}
|
||||
|
||||
LoadComponentAsync(table, t =>
|
||||
LoadComponentAsync(content, loaded =>
|
||||
{
|
||||
loading.Hide();
|
||||
tableContainer.Child = table;
|
||||
contentContainer.Child = loaded;
|
||||
}, (cancellationToken = new CancellationTokenSource()).Token);
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,6 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using osu.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
@ -20,17 +18,12 @@ namespace osu.Game.Rulesets.Edit
|
||||
/// <summary>
|
||||
/// A blueprint which governs the creation of a new <see cref="HitObject"/> to actualisation.
|
||||
/// </summary>
|
||||
public abstract class PlacementBlueprint : CompositeDrawable, IStateful<PlacementState>
|
||||
public abstract class PlacementBlueprint : CompositeDrawable
|
||||
{
|
||||
/// <summary>
|
||||
/// Invoked when <see cref="State"/> has changed.
|
||||
/// Whether the <see cref="HitObject"/> is currently mid-placement, but has not necessarily finished being placed.
|
||||
/// </summary>
|
||||
public event Action<PlacementState> StateChanged;
|
||||
|
||||
/// <summary>
|
||||
/// Whether the <see cref="HitObject"/> is currently being placed, but has not necessarily finished being placed.
|
||||
/// </summary>
|
||||
public bool PlacementBegun { get; private set; }
|
||||
public bool PlacementActive { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="HitObject"/> that is being placed.
|
||||
@ -53,8 +46,6 @@ namespace osu.Game.Rulesets.Edit
|
||||
// This is required to allow the blueprint's position to be updated via OnMouseMove/Handle
|
||||
// on the same frame it is made visible via a PlacementState change.
|
||||
AlwaysPresent = true;
|
||||
|
||||
Alpha = 0;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
@ -67,48 +58,29 @@ namespace osu.Game.Rulesets.Edit
|
||||
ApplyDefaultsToHitObject();
|
||||
}
|
||||
|
||||
private PlacementState state;
|
||||
|
||||
public PlacementState State
|
||||
{
|
||||
get => state;
|
||||
set
|
||||
{
|
||||
if (state == value)
|
||||
return;
|
||||
|
||||
state = value;
|
||||
|
||||
if (state == PlacementState.Shown)
|
||||
Show();
|
||||
else
|
||||
Hide();
|
||||
|
||||
StateChanged?.Invoke(value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Signals that the placement of <see cref="HitObject"/> has started.
|
||||
/// </summary>
|
||||
/// <param name="startTime">The start time of <see cref="HitObject"/> at the placement point. If null, the current clock time is used.</param>
|
||||
protected void BeginPlacement(double? startTime = null)
|
||||
/// <param name="commitStart">Whether this call is committing a value for HitObject.StartTime and continuing with further adjustments.</param>
|
||||
protected void BeginPlacement(double? startTime = null, bool commitStart = false)
|
||||
{
|
||||
HitObject.StartTime = startTime ?? EditorClock.CurrentTime;
|
||||
placementHandler.BeginPlacement(HitObject);
|
||||
PlacementBegun = true;
|
||||
PlacementActive |= commitStart;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Signals that the placement of <see cref="HitObject"/> has finished.
|
||||
/// This will destroy this <see cref="PlacementBlueprint"/>, and add the <see cref="HitObject"/> to the <see cref="Beatmap"/>.
|
||||
/// This will destroy this <see cref="PlacementBlueprint"/>, and add the HitObject.StartTime to the <see cref="Beatmap"/>.
|
||||
/// </summary>
|
||||
/// <param name="commit">Whether the object should be committed.</param>
|
||||
public void EndPlacement(bool commit)
|
||||
{
|
||||
if (!PlacementBegun)
|
||||
if (!PlacementActive)
|
||||
BeginPlacement();
|
||||
placementHandler.EndPlacement(HitObject, commit);
|
||||
PlacementActive = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -142,10 +114,4 @@ namespace osu.Game.Rulesets.Edit
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum PlacementState
|
||||
{
|
||||
Hidden,
|
||||
Shown,
|
||||
}
|
||||
}
|
||||
|
@ -28,7 +28,11 @@ namespace osu.Game.Rulesets.Mods
|
||||
|
||||
public override Type[] IncompatibleMods => new[] { typeof(ModEasy), typeof(ModHardRock) };
|
||||
|
||||
[SettingSource("Drain Rate", "Override a beatmap's set HP.")]
|
||||
protected const int FIRST_SETTING_ORDER = 1;
|
||||
|
||||
protected const int LAST_SETTING_ORDER = 2;
|
||||
|
||||
[SettingSource("HP Drain", "Override a beatmap's set HP.", FIRST_SETTING_ORDER)]
|
||||
public BindableNumber<float> DrainRate { get; } = new BindableFloat
|
||||
{
|
||||
Precision = 0.1f,
|
||||
@ -38,7 +42,7 @@ namespace osu.Game.Rulesets.Mods
|
||||
Value = 5,
|
||||
};
|
||||
|
||||
[SettingSource("Overall Difficulty", "Override a beatmap's set OD.")]
|
||||
[SettingSource("Accuracy", "Override a beatmap's set OD.", LAST_SETTING_ORDER)]
|
||||
public BindableNumber<float> OverallDifficulty { get; } = new BindableFloat
|
||||
{
|
||||
Precision = 0.1f,
|
||||
|
@ -62,20 +62,8 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
||||
/// </summary>
|
||||
private void refreshTool()
|
||||
{
|
||||
placementBlueprintContainer.Clear();
|
||||
|
||||
currentPlacement?.EndPlacement(false);
|
||||
currentPlacement = null;
|
||||
|
||||
var blueprint = CurrentTool?.CreatePlacementBlueprint();
|
||||
|
||||
if (blueprint != null)
|
||||
{
|
||||
placementBlueprintContainer.Child = currentPlacement = blueprint;
|
||||
|
||||
// Fixes a 1-frame position discrepancy due to the first mouse move event happening in the next frame
|
||||
updatePlacementPosition(inputManager.CurrentState.Mouse.Position);
|
||||
}
|
||||
removePlacement();
|
||||
createPlacement();
|
||||
}
|
||||
|
||||
private void updatePlacementPosition(Vector2 screenSpacePosition)
|
||||
@ -103,18 +91,16 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
||||
{
|
||||
base.Update();
|
||||
|
||||
if (currentPlacement != null)
|
||||
{
|
||||
if (composer.CursorInPlacementArea)
|
||||
currentPlacement.State = PlacementState.Shown;
|
||||
else if (currentPlacement?.PlacementBegun == false)
|
||||
currentPlacement.State = PlacementState.Hidden;
|
||||
}
|
||||
if (composer.CursorInPlacementArea)
|
||||
createPlacement();
|
||||
else if (currentPlacement?.PlacementActive == false)
|
||||
removePlacement();
|
||||
}
|
||||
|
||||
protected sealed override SelectionBlueprint CreateBlueprintFor(HitObject hitObject)
|
||||
{
|
||||
var drawable = drawableHitObjects.FirstOrDefault(d => d.HitObject == hitObject);
|
||||
|
||||
if (drawable == null)
|
||||
return null;
|
||||
|
||||
@ -129,6 +115,30 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
||||
base.AddBlueprintFor(hitObject);
|
||||
}
|
||||
|
||||
private void createPlacement()
|
||||
{
|
||||
if (currentPlacement != null) return;
|
||||
|
||||
var blueprint = CurrentTool?.CreatePlacementBlueprint();
|
||||
|
||||
if (blueprint != null)
|
||||
{
|
||||
placementBlueprintContainer.Child = currentPlacement = blueprint;
|
||||
|
||||
// Fixes a 1-frame position discrepancy due to the first mouse move event happening in the next frame
|
||||
updatePlacementPosition(inputManager.CurrentState.Mouse.Position);
|
||||
}
|
||||
}
|
||||
|
||||
private void removePlacement()
|
||||
{
|
||||
if (currentPlacement == null) return;
|
||||
|
||||
currentPlacement.EndPlacement(false);
|
||||
currentPlacement.Expire();
|
||||
currentPlacement = null;
|
||||
}
|
||||
|
||||
private HitObjectCompositionTool currentTool;
|
||||
|
||||
/// <summary>
|
||||
@ -137,6 +147,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
||||
public HitObjectCompositionTool CurrentTool
|
||||
{
|
||||
get => currentTool;
|
||||
|
||||
set
|
||||
{
|
||||
if (currentTool == value)
|
||||
|
@ -6,10 +6,13 @@ using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Framework.Threading;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
using osuTK.Input;
|
||||
|
||||
namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
||||
{
|
||||
@ -52,6 +55,45 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
||||
HoverColour = OsuColour.Gray(0.25f);
|
||||
FlashColour = OsuColour.Gray(0.5f);
|
||||
}
|
||||
|
||||
private ScheduledDelegate repeatSchedule;
|
||||
|
||||
/// <summary>
|
||||
/// The initial delay before mouse down repeat begins.
|
||||
/// </summary>
|
||||
private const int repeat_initial_delay = 250;
|
||||
|
||||
/// <summary>
|
||||
/// The delay between mouse down repeats after the initial repeat.
|
||||
/// </summary>
|
||||
private const int repeat_tick_rate = 70;
|
||||
|
||||
protected override bool OnClick(ClickEvent e)
|
||||
{
|
||||
// don't actuate a click since we are manually handling repeats.
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override bool OnMouseDown(MouseDownEvent e)
|
||||
{
|
||||
if (e.Button == MouseButton.Left)
|
||||
{
|
||||
Action clickAction = () => base.OnClick(new ClickEvent(e.CurrentState, e.Button));
|
||||
|
||||
// run once for initial down
|
||||
clickAction();
|
||||
|
||||
Scheduler.Add(repeatSchedule = new ScheduledDelegate(clickAction, Clock.CurrentTime + repeat_initial_delay, repeat_tick_rate));
|
||||
}
|
||||
|
||||
return base.OnMouseDown(e);
|
||||
}
|
||||
|
||||
protected override void OnMouseUp(MouseUpEvent e)
|
||||
{
|
||||
repeatSchedule?.Cancel();
|
||||
base.OnMouseUp(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -95,7 +95,7 @@ namespace osu.Game.Screens.Menu
|
||||
private void updateAmplitudes()
|
||||
{
|
||||
var track = beatmap.Value.TrackLoaded ? beatmap.Value.Track : null;
|
||||
var effect = beatmap.Value.BeatmapLoaded ? beatmap.Value.Beatmap.ControlPointInfo.EffectPointAt(track?.CurrentTime ?? Time.Current) : null;
|
||||
var effect = beatmap.Value.BeatmapLoaded ? beatmap.Value.Beatmap?.ControlPointInfo.EffectPointAt(track?.CurrentTime ?? Time.Current) : null;
|
||||
|
||||
float[] temporalAmplitudes = track?.CurrentAmplitudes.FrequencyAmplitudes;
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
// 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 osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Localisation;
|
||||
@ -25,7 +26,10 @@ namespace osu.Game.Screens.Multi.Components
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
CurrentItem.BindValueChanged(_ => updateText(), true);
|
||||
Playlist.ItemsAdded += _ => updateText();
|
||||
Playlist.ItemsRemoved += _ => updateText();
|
||||
|
||||
updateText();
|
||||
}
|
||||
|
||||
private float textSize = OsuFont.DEFAULT_FONT_SIZE;
|
||||
@ -54,7 +58,7 @@ namespace osu.Game.Screens.Multi.Components
|
||||
|
||||
textFlow.Clear();
|
||||
|
||||
var beatmap = CurrentItem.Value?.Beatmap;
|
||||
var beatmap = Playlist.FirstOrDefault()?.Beatmap;
|
||||
|
||||
if (beatmap == null)
|
||||
{
|
||||
@ -70,7 +74,7 @@ namespace osu.Game.Screens.Multi.Components
|
||||
{
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = new LocalisedString((beatmap.Metadata.ArtistUnicode, beatmap.Metadata.Artist)),
|
||||
Text = new LocalisedString((beatmap.Value.Metadata.ArtistUnicode, beatmap.Value.Metadata.Artist)),
|
||||
Font = OsuFont.GetFont(size: TextSize),
|
||||
},
|
||||
new OsuSpriteText
|
||||
@ -80,10 +84,10 @@ namespace osu.Game.Screens.Multi.Components
|
||||
},
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = new LocalisedString((beatmap.Metadata.TitleUnicode, beatmap.Metadata.Title)),
|
||||
Text = new LocalisedString((beatmap.Value.Metadata.TitleUnicode, beatmap.Value.Metadata.Title)),
|
||||
Font = OsuFont.GetFont(size: TextSize),
|
||||
}
|
||||
}, LinkAction.OpenBeatmap, beatmap.OnlineBeatmapID.ToString(), "Open beatmap");
|
||||
}, LinkAction.OpenBeatmap, beatmap.Value.OnlineBeatmapID.ToString(), "Open beatmap");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
// 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 osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
@ -12,6 +13,8 @@ namespace osu.Game.Screens.Multi.Components
|
||||
{
|
||||
public class BeatmapTypeInfo : MultiplayerComposite
|
||||
{
|
||||
private LinkFlowContainer beatmapAuthor;
|
||||
|
||||
public BeatmapTypeInfo()
|
||||
{
|
||||
AutoSizeAxes = Axes.Both;
|
||||
@ -20,8 +23,6 @@ namespace osu.Game.Screens.Multi.Components
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
LinkFlowContainer beatmapAuthor;
|
||||
|
||||
InternalChild = new FillFlowContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
@ -50,18 +51,23 @@ namespace osu.Game.Screens.Multi.Components
|
||||
}
|
||||
};
|
||||
|
||||
CurrentItem.BindValueChanged(item =>
|
||||
Playlist.ItemsAdded += _ => updateInfo();
|
||||
Playlist.ItemsRemoved += _ => updateInfo();
|
||||
|
||||
updateInfo();
|
||||
}
|
||||
|
||||
private void updateInfo()
|
||||
{
|
||||
beatmapAuthor.Clear();
|
||||
|
||||
var beatmap = Playlist.FirstOrDefault()?.Beatmap;
|
||||
|
||||
if (beatmap != null)
|
||||
{
|
||||
beatmapAuthor.Clear();
|
||||
|
||||
var beatmap = item.NewValue?.Beatmap;
|
||||
|
||||
if (beatmap != null)
|
||||
{
|
||||
beatmapAuthor.AddText("mapped by ", s => s.Colour = OsuColour.Gray(0.8f));
|
||||
beatmapAuthor.AddUserLink(beatmap.Metadata.Author);
|
||||
}
|
||||
}, true);
|
||||
beatmapAuthor.AddText("mapped by ", s => s.Colour = OsuColour.Gray(0.8f));
|
||||
beatmapAuthor.AddUserLink(beatmap.Value.Metadata.Author);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
// 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 osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Beatmaps.Drawables;
|
||||
using osu.Game.Online.Multiplayer;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Screens.Multi.Components
|
||||
@ -46,17 +46,22 @@ namespace osu.Game.Screens.Multi.Components
|
||||
},
|
||||
};
|
||||
|
||||
CurrentItem.BindValueChanged(item => updateBeatmap(item.NewValue), true);
|
||||
|
||||
Type.BindValueChanged(type => gameTypeContainer.Child = new DrawableGameType(type.NewValue) { Size = new Vector2(height) }, true);
|
||||
|
||||
Playlist.ItemsAdded += _ => updateBeatmap();
|
||||
Playlist.ItemsRemoved += _ => updateBeatmap();
|
||||
|
||||
updateBeatmap();
|
||||
}
|
||||
|
||||
private void updateBeatmap(PlaylistItem item)
|
||||
private void updateBeatmap()
|
||||
{
|
||||
var item = Playlist.FirstOrDefault();
|
||||
|
||||
if (item?.Beatmap != null)
|
||||
{
|
||||
drawableRuleset.FadeIn(transition_duration);
|
||||
drawableRuleset.Child = new DifficultyIcon(item.Beatmap, item.Ruleset) { Size = new Vector2(height) };
|
||||
drawableRuleset.Child = new DifficultyIcon(item.Beatmap.Value, item.Ruleset.Value) { Size = new Vector2(height) };
|
||||
}
|
||||
else
|
||||
drawableRuleset.FadeOut(transition_duration);
|
||||
|
@ -1,6 +1,7 @@
|
||||
// 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 osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Beatmaps.Drawables;
|
||||
@ -10,6 +11,7 @@ namespace osu.Game.Screens.Multi.Components
|
||||
public class MultiplayerBackgroundSprite : MultiplayerComposite
|
||||
{
|
||||
private readonly BeatmapSetCoverType beatmapSetCoverType;
|
||||
private UpdateableBeatmapBackgroundSprite sprite;
|
||||
|
||||
public MultiplayerBackgroundSprite(BeatmapSetCoverType beatmapSetCoverType = BeatmapSetCoverType.Cover)
|
||||
{
|
||||
@ -19,11 +21,17 @@ namespace osu.Game.Screens.Multi.Components
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
UpdateableBeatmapBackgroundSprite sprite;
|
||||
|
||||
InternalChild = sprite = CreateBackgroundSprite();
|
||||
|
||||
CurrentItem.BindValueChanged(item => sprite.Beatmap.Value = item.NewValue?.Beatmap, true);
|
||||
Playlist.ItemsAdded += _ => updateBeatmap();
|
||||
Playlist.ItemsRemoved += _ => updateBeatmap();
|
||||
|
||||
updateBeatmap();
|
||||
}
|
||||
|
||||
private void updateBeatmap()
|
||||
{
|
||||
sprite.Beatmap.Value = Playlist.FirstOrDefault()?.Beatmap.Value;
|
||||
}
|
||||
|
||||
protected virtual UpdateableBeatmapBackgroundSprite CreateBackgroundSprite() => new UpdateableBeatmapBackgroundSprite(beatmapSetCoverType) { RelativeSizeAxes = Axes.Both };
|
||||
|
@ -68,7 +68,7 @@ namespace osu.Game.Screens.Multi.Lounge.Components
|
||||
{
|
||||
bool matchingFilter = true;
|
||||
|
||||
matchingFilter &= r.Room.Playlist.Count == 0 || r.Room.Playlist.Any(i => i.Ruleset.Equals(criteria.Ruleset));
|
||||
matchingFilter &= r.Room.Playlist.Count == 0 || r.Room.Playlist.Any(i => i.Ruleset.Value.Equals(criteria.Ruleset));
|
||||
|
||||
if (!string.IsNullOrEmpty(criteria.SearchString))
|
||||
matchingFilter &= r.FilterTerms.Any(term => term.IndexOf(criteria.SearchString, StringComparison.InvariantCultureIgnoreCase) >= 0);
|
||||
|
@ -2,6 +2,7 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
@ -32,6 +33,7 @@ namespace osu.Game.Screens.Multi.Match.Components
|
||||
public Action RequestBeatmapSelection;
|
||||
|
||||
private MatchBeatmapPanel beatmapPanel;
|
||||
private ModDisplay modDisplay;
|
||||
|
||||
public Header()
|
||||
{
|
||||
@ -43,7 +45,6 @@ namespace osu.Game.Screens.Multi.Match.Components
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
BeatmapSelectButton beatmapButton;
|
||||
ModDisplay modDisplay;
|
||||
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
@ -119,9 +120,12 @@ namespace osu.Game.Screens.Multi.Match.Components
|
||||
},
|
||||
};
|
||||
|
||||
CurrentItem.BindValueChanged(item => modDisplay.Current.Value = item.NewValue?.RequiredMods?.ToArray() ?? Array.Empty<Mod>(), true);
|
||||
|
||||
beatmapButton.Action = () => RequestBeatmapSelection?.Invoke();
|
||||
|
||||
Playlist.ItemsAdded += _ => updateMods();
|
||||
Playlist.ItemsRemoved += _ => updateMods();
|
||||
|
||||
updateMods();
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
@ -130,6 +134,13 @@ namespace osu.Game.Screens.Multi.Match.Components
|
||||
ShowBeatmapPanel.BindValueChanged(value => beatmapPanel.FadeTo(value.NewValue ? 1 : 0, 200, Easing.OutQuint), true);
|
||||
}
|
||||
|
||||
private void updateMods()
|
||||
{
|
||||
var item = Playlist.FirstOrDefault();
|
||||
|
||||
modDisplay.Current.Value = item?.RequiredMods?.ToArray() ?? Array.Empty<Mod>();
|
||||
}
|
||||
|
||||
private class BeatmapSelectButton : HeaderButton
|
||||
{
|
||||
[Resolved(typeof(Room), nameof(Room.RoomID))]
|
||||
|
@ -2,6 +2,7 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
@ -18,6 +19,8 @@ namespace osu.Game.Screens.Multi.Match.Components
|
||||
{
|
||||
public Action OnStart;
|
||||
|
||||
private ReadyButton readyButton;
|
||||
|
||||
public Info()
|
||||
{
|
||||
RelativeSizeAxes = Axes.X;
|
||||
@ -27,7 +30,6 @@ namespace osu.Game.Screens.Multi.Match.Components
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
ReadyButton readyButton;
|
||||
HostInfo hostInfo;
|
||||
|
||||
InternalChildren = new Drawable[]
|
||||
@ -89,9 +91,17 @@ namespace osu.Game.Screens.Multi.Match.Components
|
||||
},
|
||||
};
|
||||
|
||||
CurrentItem.BindValueChanged(item => readyButton.Beatmap.Value = item.NewValue?.Beatmap, true);
|
||||
|
||||
hostInfo.Host.BindTo(Host);
|
||||
|
||||
Playlist.ItemsAdded += _ => updateBeatmap();
|
||||
Playlist.ItemsRemoved += _ => updateBeatmap();
|
||||
|
||||
updateBeatmap();
|
||||
}
|
||||
|
||||
private void updateBeatmap()
|
||||
{
|
||||
readyButton.Beatmap.Value = Playlist.FirstOrDefault()?.Beatmap.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
// 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 System.Threading;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Online.API.Requests;
|
||||
using osu.Game.Overlays.Direct;
|
||||
@ -32,10 +32,13 @@ namespace osu.Game.Screens.Multi.Match.Components
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
CurrentItem.BindValueChanged(item => loadNewPanel(item.NewValue?.Beatmap), true);
|
||||
Playlist.ItemsAdded += _ => loadNewPanel();
|
||||
Playlist.ItemsRemoved += _ => loadNewPanel();
|
||||
|
||||
loadNewPanel();
|
||||
}
|
||||
|
||||
private void loadNewPanel(BeatmapInfo beatmap)
|
||||
private void loadNewPanel()
|
||||
{
|
||||
loadCancellation?.Cancel();
|
||||
request?.Cancel();
|
||||
@ -44,6 +47,8 @@ namespace osu.Game.Screens.Multi.Match.Components
|
||||
panel?.Expire();
|
||||
panel = null;
|
||||
|
||||
var beatmap = Playlist.FirstOrDefault()?.Beatmap.Value;
|
||||
|
||||
if (beatmap?.OnlineBeatmapID == null)
|
||||
return;
|
||||
|
||||
|
@ -51,9 +51,9 @@ namespace osu.Game.Screens.Multi.Match.Components
|
||||
},
|
||||
};
|
||||
|
||||
Participants.BindValueChanged(participants =>
|
||||
Participants.ItemsAdded += users =>
|
||||
{
|
||||
usersFlow.Children = participants.NewValue.Select(u =>
|
||||
usersFlow.AddRange(users.Select(u =>
|
||||
{
|
||||
var panel = new UserPanel(u)
|
||||
{
|
||||
@ -65,8 +65,13 @@ namespace osu.Game.Screens.Multi.Match.Components
|
||||
panel.OnLoadComplete += d => d.FadeInFromZero(60);
|
||||
|
||||
return panel;
|
||||
}).ToList();
|
||||
}, true);
|
||||
}).ToList());
|
||||
};
|
||||
|
||||
Participants.ItemsRemoved += users =>
|
||||
{
|
||||
usersFlow.RemoveAll(p => users.Contains(p.User));
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
@ -40,9 +41,6 @@ namespace osu.Game.Screens.Multi.Match
|
||||
[Resolved(typeof(Room))]
|
||||
protected BindableList<PlaylistItem> Playlist { get; private set; }
|
||||
|
||||
[Resolved(typeof(Room))]
|
||||
protected Bindable<PlaylistItem> CurrentItem { get; private set; }
|
||||
|
||||
[Resolved]
|
||||
private BeatmapManager beatmapManager { get; set; }
|
||||
|
||||
@ -52,6 +50,7 @@ namespace osu.Game.Screens.Multi.Match
|
||||
[Resolved(CanBeNull = true)]
|
||||
private OsuGame game { get; set; }
|
||||
|
||||
private readonly Bindable<PlaylistItem> selectedItem = new Bindable<PlaylistItem>();
|
||||
private MatchLeaderboard leaderboard;
|
||||
|
||||
public MatchSubScreen(Room room)
|
||||
@ -165,7 +164,16 @@ namespace osu.Game.Screens.Multi.Match
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
CurrentItem.BindValueChanged(currentItemChanged, true);
|
||||
Playlist.ItemsAdded += _ => updateSelectedItem();
|
||||
Playlist.ItemsRemoved += _ => updateSelectedItem();
|
||||
|
||||
updateSelectedItem();
|
||||
}
|
||||
|
||||
private void updateSelectedItem()
|
||||
{
|
||||
selectedItem.Value = Playlist.FirstOrDefault();
|
||||
currentItemChanged();
|
||||
}
|
||||
|
||||
public override bool OnExiting(IScreen next)
|
||||
@ -180,16 +188,18 @@ namespace osu.Game.Screens.Multi.Match
|
||||
/// <summary>
|
||||
/// Handles propagation of the current playlist item's content to game-wide mechanisms.
|
||||
/// </summary>
|
||||
private void currentItemChanged(ValueChangedEvent<PlaylistItem> e)
|
||||
private void currentItemChanged()
|
||||
{
|
||||
var item = selectedItem.Value;
|
||||
|
||||
// Retrieve the corresponding local beatmap, since we can't directly use the playlist's beatmap info
|
||||
var localBeatmap = e.NewValue?.Beatmap == null ? null : beatmapManager.QueryBeatmap(b => b.OnlineBeatmapID == e.NewValue.Beatmap.OnlineBeatmapID);
|
||||
var localBeatmap = item?.Beatmap == null ? null : beatmapManager.QueryBeatmap(b => b.OnlineBeatmapID == item.Beatmap.Value.OnlineBeatmapID);
|
||||
|
||||
Beatmap.Value = beatmapManager.GetWorkingBeatmap(localBeatmap);
|
||||
Mods.Value = e.NewValue?.RequiredMods?.ToArray() ?? Array.Empty<Mod>();
|
||||
Mods.Value = item?.RequiredMods?.ToArray() ?? Array.Empty<Mod>();
|
||||
|
||||
if (e.NewValue?.Ruleset != null)
|
||||
Ruleset.Value = e.NewValue.Ruleset;
|
||||
if (item?.Ruleset != null)
|
||||
Ruleset.Value = item.Ruleset.Value;
|
||||
|
||||
previewTrackManager.StopAnyPlaying(this);
|
||||
}
|
||||
@ -202,11 +212,11 @@ namespace osu.Game.Screens.Multi.Match
|
||||
if (Beatmap.Value != beatmapManager.DefaultBeatmap)
|
||||
return;
|
||||
|
||||
if (CurrentItem.Value == null)
|
||||
if (selectedItem.Value == null)
|
||||
return;
|
||||
|
||||
// Try to retrieve the corresponding local beatmap
|
||||
var localBeatmap = beatmapManager.QueryBeatmap(b => b.OnlineBeatmapID == CurrentItem.Value.Beatmap.OnlineBeatmapID);
|
||||
var localBeatmap = beatmapManager.QueryBeatmap(b => b.OnlineBeatmapID == selectedItem.Value.Beatmap.Value.OnlineBeatmapID);
|
||||
|
||||
if (localBeatmap != null)
|
||||
Beatmap.Value = beatmapManager.GetWorkingBeatmap(localBeatmap);
|
||||
@ -223,7 +233,7 @@ namespace osu.Game.Screens.Multi.Match
|
||||
{
|
||||
default:
|
||||
case GameTypeTimeshift _:
|
||||
multiplayer?.Start(() => new TimeshiftPlayer(CurrentItem.Value)
|
||||
multiplayer?.Start(() => new TimeshiftPlayer(selectedItem.Value)
|
||||
{
|
||||
Exited = () => leaderboard.RefreshScores()
|
||||
});
|
||||
|
@ -2,7 +2,6 @@
|
||||
// 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.Bindables;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
@ -32,10 +31,7 @@ namespace osu.Game.Screens.Multi
|
||||
protected BindableList<PlaylistItem> Playlist { get; private set; }
|
||||
|
||||
[Resolved(typeof(Room))]
|
||||
protected Bindable<PlaylistItem> CurrentItem { get; private set; }
|
||||
|
||||
[Resolved(typeof(Room))]
|
||||
protected Bindable<IEnumerable<User>> Participants { get; private set; }
|
||||
protected BindableList<User> Participants { get; private set; }
|
||||
|
||||
[Resolved(typeof(Room))]
|
||||
protected Bindable<int> ParticipantCount { get; private set; }
|
||||
|
@ -50,10 +50,10 @@ namespace osu.Game.Screens.Multi.Play
|
||||
bool failed = false;
|
||||
|
||||
// Sanity checks to ensure that TimeshiftPlayer matches the settings for the current PlaylistItem
|
||||
if (Beatmap.Value.BeatmapInfo.OnlineBeatmapID != playlistItem.Beatmap.OnlineBeatmapID)
|
||||
if (Beatmap.Value.BeatmapInfo.OnlineBeatmapID != playlistItem.Beatmap.Value.OnlineBeatmapID)
|
||||
throw new InvalidOperationException("Current Beatmap does not match PlaylistItem's Beatmap");
|
||||
|
||||
if (ruleset.Value.ID != playlistItem.Ruleset.ID)
|
||||
if (ruleset.Value.ID != playlistItem.Ruleset.Value.ID)
|
||||
throw new InvalidOperationException("Current Ruleset does not match PlaylistItem's Ruleset");
|
||||
|
||||
if (!playlistItem.RequiredMods.All(m => Mods.Value.Any(m.Equals)))
|
||||
|
@ -24,7 +24,7 @@ namespace osu.Game.Screens.Play.HUD
|
||||
|
||||
public bool DisplayUnrankedText = true;
|
||||
|
||||
public bool AllowExpand = true;
|
||||
public ExpansionMode ExpansionMode = ExpansionMode.ExpandOnHover;
|
||||
|
||||
private readonly Bindable<IReadOnlyList<Mod>> current = new Bindable<IReadOnlyList<Mod>>();
|
||||
|
||||
@ -110,11 +110,15 @@ namespace osu.Game.Screens.Play.HUD
|
||||
|
||||
private void expand()
|
||||
{
|
||||
if (AllowExpand)
|
||||
if (ExpansionMode != ExpansionMode.AlwaysContracted)
|
||||
IconsContainer.TransformSpacingTo(new Vector2(5, 0), 500, Easing.OutQuint);
|
||||
}
|
||||
|
||||
private void contract() => IconsContainer.TransformSpacingTo(new Vector2(-25, 0), 500, Easing.OutQuint);
|
||||
private void contract()
|
||||
{
|
||||
if (ExpansionMode != ExpansionMode.AlwaysExpanded)
|
||||
IconsContainer.TransformSpacingTo(new Vector2(-25, 0), 500, Easing.OutQuint);
|
||||
}
|
||||
|
||||
protected override bool OnHover(HoverEvent e)
|
||||
{
|
||||
@ -128,4 +132,22 @@ namespace osu.Game.Screens.Play.HUD
|
||||
base.OnHoverLost(e);
|
||||
}
|
||||
}
|
||||
|
||||
public enum ExpansionMode
|
||||
{
|
||||
/// <summary>
|
||||
/// The <see cref="ModDisplay"/> will expand only when hovered.
|
||||
/// </summary>
|
||||
ExpandOnHover,
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="ModDisplay"/> will always be expanded.
|
||||
/// </summary>
|
||||
AlwaysExpanded,
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="ModDisplay"/> will always be contracted.
|
||||
/// </summary>
|
||||
AlwaysContracted
|
||||
}
|
||||
}
|
||||
|
@ -229,6 +229,17 @@ namespace osu.Game.Screens.Select
|
||||
if (item != null)
|
||||
{
|
||||
select(item);
|
||||
|
||||
// if we got here and the set is filtered, it means we were bypassing filters.
|
||||
// in this case, reapplying the filter is necessary to ensure the panel is in the correct place
|
||||
// (since it is forcefully being included in the carousel).
|
||||
if (set.Filtered.Value)
|
||||
{
|
||||
Debug.Assert(bypassFilters);
|
||||
|
||||
applyActiveCriteria(false, true);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -62,7 +62,7 @@ namespace osu.Game.Screens.Select.Carousel
|
||||
/// <summary>
|
||||
/// All beatmaps which are not filtered and valid for display.
|
||||
/// </summary>
|
||||
protected IEnumerable<BeatmapInfo> ValidBeatmaps => Beatmaps.Where(b => !b.Filtered.Value).Select(b => b.Beatmap);
|
||||
protected IEnumerable<BeatmapInfo> ValidBeatmaps => Beatmaps.Where(b => !b.Filtered.Value || b.State.Value == CarouselItemState.Selected).Select(b => b.Beatmap);
|
||||
|
||||
private int compareUsingAggregateMax(CarouselBeatmapSet other, Func<BeatmapInfo, double> func)
|
||||
{
|
||||
|
@ -16,7 +16,7 @@ namespace osu.Game.Screens.Select.Carousel
|
||||
/// <summary>
|
||||
/// This item is not in a hidden state.
|
||||
/// </summary>
|
||||
public bool Visible => State.Value != CarouselItemState.Collapsed && !Filtered.Value;
|
||||
public bool Visible => State.Value == CarouselItemState.Selected || (State.Value != CarouselItemState.Collapsed && !Filtered.Value);
|
||||
|
||||
public virtual List<DrawableCarouselItem> Drawables
|
||||
{
|
||||
|
@ -91,7 +91,7 @@ namespace osu.Game.Screens.Select
|
||||
|
||||
public FooterModDisplay()
|
||||
{
|
||||
AllowExpand = false;
|
||||
ExpansionMode = ExpansionMode.AlwaysContracted;
|
||||
IconsContainer.Margin = new MarginPadding();
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Humanizer;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
@ -21,11 +22,11 @@ namespace osu.Game.Screens.Select
|
||||
public string ShortTitle => "song selection";
|
||||
public override string Title => ShortTitle.Humanize();
|
||||
|
||||
[Resolved(typeof(Room))]
|
||||
protected Bindable<PlaylistItem> CurrentItem { get; private set; }
|
||||
|
||||
public override bool AllowEditing => false;
|
||||
|
||||
[Resolved(typeof(Room), nameof(Room.Playlist))]
|
||||
protected BindableList<PlaylistItem> Playlist { get; private set; }
|
||||
|
||||
[Resolved]
|
||||
private BeatmapManager beatmaps { get; set; }
|
||||
|
||||
@ -38,8 +39,8 @@ namespace osu.Game.Screens.Select
|
||||
{
|
||||
var item = new PlaylistItem
|
||||
{
|
||||
Beatmap = Beatmap.Value.BeatmapInfo,
|
||||
Ruleset = Ruleset.Value,
|
||||
Beatmap = { Value = Beatmap.Value.BeatmapInfo },
|
||||
Ruleset = { Value = Ruleset.Value },
|
||||
RulesetID = Ruleset.Value.ID ?? 0
|
||||
};
|
||||
|
||||
@ -58,11 +59,13 @@ namespace osu.Game.Screens.Select
|
||||
if (base.OnExiting(next))
|
||||
return true;
|
||||
|
||||
if (CurrentItem.Value != null)
|
||||
var firstItem = Playlist.FirstOrDefault();
|
||||
|
||||
if (firstItem != null)
|
||||
{
|
||||
Ruleset.Value = CurrentItem.Value.Ruleset;
|
||||
Beatmap.Value = beatmaps.GetWorkingBeatmap(CurrentItem.Value.Beatmap);
|
||||
Mods.Value = CurrentItem.Value.RequiredMods?.ToArray() ?? Array.Empty<Mod>();
|
||||
Ruleset.Value = firstItem.Ruleset.Value;
|
||||
Beatmap.Value = beatmaps.GetWorkingBeatmap(firstItem.Beatmap.Value);
|
||||
Mods.Value = firstItem.RequiredMods?.ToArray() ?? Array.Empty<Mod>();
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -376,16 +376,22 @@ namespace osu.Game.Screens.Select
|
||||
|
||||
private void workingBeatmapChanged(ValueChangedEvent<WorkingBeatmap> e)
|
||||
{
|
||||
if (e.NewValue is DummyWorkingBeatmap) return;
|
||||
if (e.NewValue is DummyWorkingBeatmap || !this.IsCurrentScreen()) return;
|
||||
|
||||
if (this.IsCurrentScreen() && !Carousel.SelectBeatmap(e.NewValue?.BeatmapInfo, false))
|
||||
if (!Carousel.SelectBeatmap(e.NewValue.BeatmapInfo, false))
|
||||
{
|
||||
// If selecting new beatmap without bypassing filters failed, there's possibly a ruleset mismatch
|
||||
if (e.NewValue?.BeatmapInfo?.Ruleset != null && !e.NewValue.BeatmapInfo.Ruleset.Equals(decoupledRuleset.Value))
|
||||
// A selection may not have been possible with filters applied.
|
||||
|
||||
// There was possibly a ruleset mismatch. This is a case we can help things along by updating the game-wide ruleset to match.
|
||||
if (e.NewValue.BeatmapInfo.Ruleset != null && !e.NewValue.BeatmapInfo.Ruleset.Equals(decoupledRuleset.Value))
|
||||
{
|
||||
Ruleset.Value = e.NewValue.BeatmapInfo.Ruleset;
|
||||
Carousel.SelectBeatmap(e.NewValue.BeatmapInfo);
|
||||
transferRulesetValue();
|
||||
}
|
||||
|
||||
// Even if a ruleset mismatch was not the cause (ie. a text filter is applied),
|
||||
// we still want to forcefully show the new beatmap, bypassing filters.
|
||||
Carousel.SelectBeatmap(e.NewValue.BeatmapInfo);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -191,9 +191,9 @@ namespace osu.Game.Tests.Visual
|
||||
track = audio?.Tracks.GetVirtual(length);
|
||||
}
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
~ClockBackedTestWorkingBeatmap()
|
||||
{
|
||||
base.Dispose(isDisposing);
|
||||
// Remove the track store from the audio manager
|
||||
store?.Dispose();
|
||||
}
|
||||
|
||||
|
@ -26,11 +26,12 @@ namespace osu.Game.Users
|
||||
{
|
||||
public class UserPanel : OsuClickableContainer, IHasContextMenu
|
||||
{
|
||||
private readonly User user;
|
||||
private const float height = 100;
|
||||
private const float content_padding = 10;
|
||||
private const float status_height = 30;
|
||||
|
||||
public readonly User User;
|
||||
|
||||
[Resolved(canBeNull: true)]
|
||||
private OsuColour colours { get; set; }
|
||||
|
||||
@ -54,7 +55,7 @@ namespace osu.Game.Users
|
||||
if (user == null)
|
||||
throw new ArgumentNullException(nameof(user));
|
||||
|
||||
this.user = user;
|
||||
User = user;
|
||||
|
||||
Height = height - status_height;
|
||||
}
|
||||
@ -86,7 +87,7 @@ namespace osu.Game.Users
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
User = user,
|
||||
User = User,
|
||||
}, 300, 5000)
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
@ -106,7 +107,7 @@ namespace osu.Game.Users
|
||||
new UpdateableAvatar
|
||||
{
|
||||
Size = new Vector2(height - status_height - content_padding * 2),
|
||||
User = user,
|
||||
User = User,
|
||||
Masking = true,
|
||||
CornerRadius = 5,
|
||||
OpenOnClick = { Value = false },
|
||||
@ -125,7 +126,7 @@ namespace osu.Game.Users
|
||||
{
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = user.Username,
|
||||
Text = User.Username,
|
||||
Font = OsuFont.GetFont(weight: FontWeight.SemiBold, size: 18, italics: true),
|
||||
},
|
||||
infoContainer = new FillFlowContainer
|
||||
@ -138,7 +139,7 @@ namespace osu.Game.Users
|
||||
Spacing = new Vector2(5f, 0f),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new UpdateableFlag(user.Country)
|
||||
new UpdateableFlag(User.Country)
|
||||
{
|
||||
Width = 30f,
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
@ -191,12 +192,12 @@ namespace osu.Game.Users
|
||||
}
|
||||
});
|
||||
|
||||
if (user.IsSupporter)
|
||||
if (User.IsSupporter)
|
||||
{
|
||||
infoContainer.Add(new SupporterIcon
|
||||
{
|
||||
Height = 20f,
|
||||
SupportLevel = user.SupportLevel
|
||||
SupportLevel = User.SupportLevel
|
||||
});
|
||||
}
|
||||
|
||||
@ -206,7 +207,7 @@ namespace osu.Game.Users
|
||||
base.Action = ViewProfile = () =>
|
||||
{
|
||||
Action?.Invoke();
|
||||
profile?.ShowUser(user);
|
||||
profile?.ShowUser(User);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -23,7 +23,7 @@
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2019.1230.0" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2020.207.0" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2020.213.0" />
|
||||
<PackageReference Include="Sentry" Version="2.0.2" />
|
||||
<PackageReference Include="SharpCompress" Version="0.24.0" />
|
||||
<PackageReference Include="NUnit" Version="3.12.0" />
|
||||
|
@ -74,7 +74,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2019.1230.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.iOS" Version="2020.207.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.iOS" Version="2020.213.0" />
|
||||
</ItemGroup>
|
||||
<!-- Xamarin.iOS does not automatically handle transitive dependencies from NuGet packages. -->
|
||||
<ItemGroup Label="Transitive Dependencies">
|
||||
@ -82,7 +82,7 @@
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2020.207.0" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2020.213.0" />
|
||||
<PackageReference Include="SharpCompress" Version="0.24.0" />
|
||||
<PackageReference Include="NUnit" Version="3.12.0" />
|
||||
<PackageReference Include="SharpRaven" Version="2.4.0" />
|
||||
|
Loading…
Reference in New Issue
Block a user