mirror of
https://github.com/ppy/osu.git
synced 2026-06-03 13:44:34 +08:00
Merge branch 'master' into multiple_keys
This commit is contained in:
@@ -43,7 +43,6 @@ namespace osu.Game.Tests.Visual.DailyChallenge
|
||||
{
|
||||
var room = new Room
|
||||
{
|
||||
RoomID = 1234,
|
||||
Name = "Daily Challenge: June 4, 2024",
|
||||
Playlist =
|
||||
[
|
||||
@@ -66,7 +65,6 @@ namespace osu.Game.Tests.Visual.DailyChallenge
|
||||
{
|
||||
var room = new Room
|
||||
{
|
||||
RoomID = 1234,
|
||||
Name = "Daily Challenge: June 4, 2024",
|
||||
Playlist =
|
||||
[
|
||||
@@ -99,7 +97,6 @@ namespace osu.Game.Tests.Visual.DailyChallenge
|
||||
{
|
||||
var room = new Room
|
||||
{
|
||||
RoomID = 1234,
|
||||
Name = "Daily Challenge: June 4, 2024",
|
||||
Playlist =
|
||||
[
|
||||
@@ -114,7 +111,7 @@ namespace osu.Game.Tests.Visual.DailyChallenge
|
||||
};
|
||||
|
||||
AddStep("add room", () => API.Perform(new CreateRoomRequest(room)));
|
||||
AddStep("set daily challenge info", () => metadataClient.DailyChallengeInfo.Value = new DailyChallengeInfo { RoomID = 1234 });
|
||||
AddStep("set daily challenge info", () => metadataClient.DailyChallengeInfo.Value = new DailyChallengeInfo { RoomID = room.RoomID!.Value });
|
||||
|
||||
Screens.OnlinePlay.DailyChallenge.DailyChallenge screen = null!;
|
||||
AddStep("push screen", () => LoadScreen(screen = new Screens.OnlinePlay.DailyChallenge.DailyChallenge(room)));
|
||||
@@ -128,7 +125,6 @@ namespace osu.Game.Tests.Visual.DailyChallenge
|
||||
{
|
||||
var room = new Room
|
||||
{
|
||||
RoomID = 1234,
|
||||
Name = "Daily Challenge: June 4, 2024",
|
||||
Playlist =
|
||||
[
|
||||
@@ -143,7 +139,7 @@ namespace osu.Game.Tests.Visual.DailyChallenge
|
||||
};
|
||||
|
||||
AddStep("add room", () => API.Perform(new CreateRoomRequest(room)));
|
||||
AddStep("set daily challenge info", () => metadataClient.DailyChallengeInfo.Value = new DailyChallengeInfo { RoomID = 1234 });
|
||||
AddStep("set daily challenge info", () => metadataClient.DailyChallengeInfo.Value = new DailyChallengeInfo { RoomID = room.RoomID!.Value });
|
||||
|
||||
Screens.OnlinePlay.DailyChallenge.DailyChallenge screen = null!;
|
||||
AddStep("push screen", () => LoadScreen(screen = new Screens.OnlinePlay.DailyChallenge.DailyChallenge(room)));
|
||||
|
||||
@@ -44,17 +44,17 @@ namespace osu.Game.Tests.Visual.DailyChallenge
|
||||
[Test]
|
||||
public void TestDailyChallenge()
|
||||
{
|
||||
startChallenge(1234);
|
||||
startChallenge();
|
||||
AddStep("push screen", () => LoadScreen(new DailyChallengeIntro(room)));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestPlayIntroOnceFlag()
|
||||
{
|
||||
startChallenge(1234);
|
||||
startChallenge();
|
||||
AddStep("set intro played flag", () => Dependencies.Get<SessionStatics>().SetValue(Static.DailyChallengeIntroPlayed, true));
|
||||
|
||||
startChallenge(1235);
|
||||
startChallenge();
|
||||
|
||||
AddAssert("intro played flag reset", () => Dependencies.Get<SessionStatics>().Get<bool>(Static.DailyChallengeIntroPlayed), () => Is.False);
|
||||
|
||||
@@ -62,13 +62,12 @@ namespace osu.Game.Tests.Visual.DailyChallenge
|
||||
AddUntilStep("intro played flag set", () => Dependencies.Get<SessionStatics>().Get<bool>(Static.DailyChallengeIntroPlayed), () => Is.True);
|
||||
}
|
||||
|
||||
private void startChallenge(int roomId)
|
||||
private void startChallenge()
|
||||
{
|
||||
AddStep("add room", () =>
|
||||
{
|
||||
API.Perform(new CreateRoomRequest(room = new Room
|
||||
{
|
||||
RoomID = roomId,
|
||||
Name = "Daily Challenge: June 4, 2024",
|
||||
Playlist =
|
||||
[
|
||||
@@ -83,7 +82,7 @@ namespace osu.Game.Tests.Visual.DailyChallenge
|
||||
Category = RoomCategory.DailyChallenge
|
||||
}));
|
||||
});
|
||||
AddStep("signal client", () => metadataClient.DailyChallengeUpdated(new DailyChallengeInfo { RoomID = roomId }));
|
||||
AddStep("signal client", () => metadataClient.DailyChallengeUpdated(new DailyChallengeInfo { RoomID = room.RoomID!.Value }));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Platform;
|
||||
@@ -32,7 +31,6 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
private BeatmapManager beatmaps = null!;
|
||||
private BeatmapSetInfo importedSet = null!;
|
||||
private BeatmapInfo importedBeatmap = null!;
|
||||
private Room room = null!;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(GameHost host, AudioManager audio)
|
||||
@@ -47,19 +45,17 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
base.SetUpSteps();
|
||||
|
||||
AddStep("create room", () => room = CreateDefaultRoom());
|
||||
AddStep("join room", () => JoinRoom(room));
|
||||
AddStep("join room", () => JoinRoom(CreateDefaultRoom()));
|
||||
WaitForJoined();
|
||||
|
||||
AddStep("create list", () =>
|
||||
{
|
||||
Child = list = new MultiplayerPlaylist(room)
|
||||
Child = list = new MultiplayerPlaylist
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Size = new Vector2(0.4f, 0.8f),
|
||||
SelectedItem = new Bindable<PlaylistItem?>()
|
||||
Size = new Vector2(0.4f, 0.8f)
|
||||
};
|
||||
});
|
||||
|
||||
@@ -158,37 +154,36 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
assertQueueTabCount(0);
|
||||
}
|
||||
|
||||
[Ignore("Expired items are initially removed from the room.")]
|
||||
[Test]
|
||||
public void TestJoinRoomWithMixedItemsAddedInCorrectLists()
|
||||
{
|
||||
AddStep("leave room", () => MultiplayerClient.LeaveRoom());
|
||||
AddUntilStep("wait for room part", () => !RoomJoined);
|
||||
|
||||
AddStep("join room with items", () =>
|
||||
AddStep("join room with expired items", () =>
|
||||
{
|
||||
API.Queue(new CreateRoomRequest(new Room
|
||||
{
|
||||
Name = "test name",
|
||||
Playlist =
|
||||
[
|
||||
new PlaylistItem(new TestBeatmap(Ruleset.Value).BeatmapInfo)
|
||||
{
|
||||
RulesetID = Ruleset.Value.OnlineID
|
||||
},
|
||||
new PlaylistItem(new TestBeatmap(Ruleset.Value).BeatmapInfo)
|
||||
{
|
||||
RulesetID = Ruleset.Value.OnlineID,
|
||||
Expired = true
|
||||
}
|
||||
]
|
||||
}));
|
||||
Room room = CreateDefaultRoom();
|
||||
room.Playlist =
|
||||
[
|
||||
new PlaylistItem(new TestBeatmap(Ruleset.Value).BeatmapInfo)
|
||||
{
|
||||
RulesetID = Ruleset.Value.OnlineID
|
||||
},
|
||||
new PlaylistItem(new TestBeatmap(Ruleset.Value).BeatmapInfo)
|
||||
{
|
||||
RulesetID = Ruleset.Value.OnlineID,
|
||||
Expired = true
|
||||
}
|
||||
];
|
||||
|
||||
JoinRoom(room);
|
||||
});
|
||||
|
||||
AddUntilStep("wait for room join", () => RoomJoined);
|
||||
WaitForJoined();
|
||||
|
||||
assertItemInQueueListStep(1, 0);
|
||||
assertItemInHistoryListStep(2, 0);
|
||||
// IDs are offset by 1 because we've joined two rooms in this test.
|
||||
assertItemInQueueListStep(2, 0);
|
||||
assertItemInHistoryListStep(3, 0);
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
||||
@@ -49,13 +49,15 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
|
||||
AddStep("create playlist", () =>
|
||||
{
|
||||
Child = playlist = new MultiplayerQueueList(room)
|
||||
Child = playlist = new MultiplayerQueueList
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Size = new Vector2(500, 300),
|
||||
Size = new Vector2(500, 300)
|
||||
};
|
||||
|
||||
playlist.Items.ReplaceRange(0, playlist.Items.Count, MultiplayerClient.ClientAPIRoom!.Playlist);
|
||||
|
||||
MultiplayerClient.ClientAPIRoom!.PropertyChanged += (_, e) =>
|
||||
{
|
||||
if (e.PropertyName == nameof(Room.Playlist))
|
||||
@@ -132,6 +134,18 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
assertDeleteButtonVisibility(1, false);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestChangeExistingItem()
|
||||
{
|
||||
AddStep("change beatmap", () => MultiplayerClient.EditPlaylistItem(new MultiplayerPlaylistItem
|
||||
{
|
||||
ID = playlist.Items[0].ID,
|
||||
BeatmapID = 1337
|
||||
}).WaitSafely());
|
||||
|
||||
AddUntilStep("first playlist item has new beatmap", () => playlist.Items[0].Beatmap.OnlineID, () => Is.EqualTo(1337));
|
||||
}
|
||||
|
||||
private void addPlaylistItem(Func<int> userId)
|
||||
{
|
||||
long itemId = -1;
|
||||
|
||||
@@ -5,6 +5,7 @@ using System;
|
||||
using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions.ObjectExtensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Online.Multiplayer;
|
||||
@@ -19,12 +20,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match.Playlist
|
||||
{
|
||||
public readonly Bindable<MultiplayerPlaylistDisplayMode> DisplayMode = new Bindable<MultiplayerPlaylistDisplayMode>();
|
||||
|
||||
public required Bindable<PlaylistItem?> SelectedItem
|
||||
{
|
||||
get => selectedItem;
|
||||
set => selectedItem.Current = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when an item requests to be edited.
|
||||
/// </summary>
|
||||
@@ -33,18 +28,11 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match.Playlist
|
||||
[Resolved]
|
||||
private MultiplayerClient client { get; set; } = null!;
|
||||
|
||||
private readonly Room room;
|
||||
private readonly BindableWithCurrent<PlaylistItem?> selectedItem = new BindableWithCurrent<PlaylistItem?>();
|
||||
private MultiplayerPlaylistTabControl playlistTabControl = null!;
|
||||
private MultiplayerQueueList queueList = null!;
|
||||
private MultiplayerHistoryList historyList = null!;
|
||||
private bool firstPopulation = true;
|
||||
|
||||
public MultiplayerPlaylist(Room room)
|
||||
{
|
||||
this.room = room;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
@@ -65,17 +53,15 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match.Playlist
|
||||
Masking = true,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
queueList = new MultiplayerQueueList(room)
|
||||
queueList = new MultiplayerQueueList
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
SelectedItem = { BindTarget = selectedItem },
|
||||
RequestEdit = item => RequestEdit?.Invoke(item)
|
||||
},
|
||||
historyList = new MultiplayerHistoryList
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Alpha = 0,
|
||||
SelectedItem = { BindTarget = selectedItem }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -89,10 +75,12 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match.Playlist
|
||||
base.LoadComplete();
|
||||
|
||||
DisplayMode.BindValueChanged(onDisplayModeChanged, true);
|
||||
|
||||
client.ItemAdded += playlistItemAdded;
|
||||
client.ItemRemoved += playlistItemRemoved;
|
||||
client.ItemChanged += playlistItemChanged;
|
||||
client.RoomUpdated += onRoomUpdated;
|
||||
|
||||
updateState();
|
||||
}
|
||||
|
||||
@@ -121,28 +109,28 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match.Playlist
|
||||
|
||||
firstPopulation = false;
|
||||
}
|
||||
|
||||
PlaylistItem? currentItem = client.Room == null ? null : new PlaylistItem(client.Room.CurrentPlaylistItem);
|
||||
queueList.SelectedItem.Value = currentItem;
|
||||
historyList.SelectedItem.Value = currentItem;
|
||||
}
|
||||
|
||||
private void playlistItemAdded(MultiplayerPlaylistItem item) => Schedule(() => addItemToLists(item));
|
||||
private void playlistItemAdded(MultiplayerPlaylistItem item) => Scheduler.Add(() => addItemToLists(item));
|
||||
|
||||
private void playlistItemRemoved(long item) => Schedule(() => removeItemFromLists(item));
|
||||
private void playlistItemRemoved(long item) => Scheduler.Add(() => removeItemFromLists(item));
|
||||
|
||||
private void playlistItemChanged(MultiplayerPlaylistItem item) => Schedule(() =>
|
||||
private void playlistItemChanged(MultiplayerPlaylistItem item) => Scheduler.Add(() =>
|
||||
{
|
||||
if (client.Room == null)
|
||||
return;
|
||||
|
||||
var newApiItem = new PlaylistItem(item);
|
||||
var existingApiItemInQueue = queueList.Items.SingleOrDefault(i => i.ID == item.ID);
|
||||
var existingItem = queueList.Items.SingleOrDefault(i => i.ID == item.ID);
|
||||
|
||||
// Test if the only change between the two playlist items is the order.
|
||||
if (existingApiItemInQueue != null && existingApiItemInQueue.With(playlistOrder: newApiItem.PlaylistOrder).Equals(newApiItem))
|
||||
if (existingItem != null && existingItem.With(playlistOrder: item.PlaylistOrder).Equals(new PlaylistItem(item)))
|
||||
{
|
||||
// Set the new playlist order directly without refreshing the DrawablePlaylistItem.
|
||||
existingApiItemInQueue.PlaylistOrder = newApiItem.PlaylistOrder;
|
||||
|
||||
// The following isn't really required, but is here for safety and explicitness.
|
||||
// MultiplayerQueueList internally binds to changes in Playlist to invalidate its own layout, which is mutated on every playlist operation.
|
||||
// Set the new order directly and refresh the flow layout as an optimisation to avoid refreshing the items' visual state.
|
||||
existingItem.PlaylistOrder = item.PlaylistOrder;
|
||||
queueList.Invalidate();
|
||||
}
|
||||
else
|
||||
@@ -154,22 +142,35 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match.Playlist
|
||||
|
||||
private void addItemToLists(MultiplayerPlaylistItem item)
|
||||
{
|
||||
var apiItem = client.Room?.Playlist.SingleOrDefault(i => i.ID == item.ID);
|
||||
|
||||
// Item could have been removed from the playlist while the local player was in gameplay.
|
||||
if (apiItem == null)
|
||||
if (client.Room == null)
|
||||
return;
|
||||
|
||||
if (item.Expired)
|
||||
historyList.Items.Add(new PlaylistItem(apiItem));
|
||||
historyList.Items.Add(new PlaylistItem(item));
|
||||
else
|
||||
queueList.Items.Add(new PlaylistItem(apiItem));
|
||||
queueList.Items.Add(new PlaylistItem(item));
|
||||
}
|
||||
|
||||
private void removeItemFromLists(long item)
|
||||
private void removeItemFromLists(long itemId)
|
||||
{
|
||||
queueList.Items.RemoveAll(i => i.ID == item);
|
||||
historyList.Items.RemoveAll(i => i.ID == item);
|
||||
if (client.Room == null)
|
||||
return;
|
||||
|
||||
queueList.Items.RemoveAll(i => i.ID == itemId);
|
||||
historyList.Items.RemoveAll(i => i.ID == itemId);
|
||||
}
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
{
|
||||
base.Dispose(isDisposing);
|
||||
|
||||
if (client.IsNotNull())
|
||||
{
|
||||
client.ItemAdded -= playlistItemAdded;
|
||||
client.ItemRemoved -= playlistItemRemoved;
|
||||
client.ItemChanged -= playlistItemChanged;
|
||||
client.RoomUpdated -= onRoomUpdated;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Extensions.ObjectExtensions;
|
||||
@@ -20,50 +19,20 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match.Playlist
|
||||
/// </summary>
|
||||
public partial class MultiplayerQueueList : DrawableRoomPlaylist
|
||||
{
|
||||
private readonly Room room;
|
||||
|
||||
private QueueFillFlowContainer flow = null!;
|
||||
|
||||
public MultiplayerQueueList(Room room)
|
||||
public MultiplayerQueueList()
|
||||
{
|
||||
this.room = room;
|
||||
ShowItemOwners = true;
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
room.PropertyChanged += onRoomPropertyChanged;
|
||||
updateRoomPlaylist();
|
||||
}
|
||||
|
||||
private void onRoomPropertyChanged(object? sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.PropertyName == nameof(Room.Playlist))
|
||||
updateRoomPlaylist();
|
||||
}
|
||||
|
||||
private void updateRoomPlaylist()
|
||||
=> flow.InvalidateLayout();
|
||||
|
||||
protected override FillFlowContainer<RearrangeableListItem<PlaylistItem>> CreateListFillFlowContainer() => flow = new QueueFillFlowContainer
|
||||
protected override FillFlowContainer<RearrangeableListItem<PlaylistItem>> CreateListFillFlowContainer() => new QueueFillFlowContainer
|
||||
{
|
||||
Spacing = new Vector2(0, 2)
|
||||
};
|
||||
|
||||
protected override DrawableRoomPlaylistItem CreateDrawablePlaylistItem(PlaylistItem item) => new QueuePlaylistItem(item);
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
{
|
||||
base.Dispose(isDisposing);
|
||||
room.PropertyChanged -= onRoomPropertyChanged;
|
||||
}
|
||||
|
||||
private partial class QueueFillFlowContainer : FillFlowContainer<RearrangeableListItem<PlaylistItem>>
|
||||
{
|
||||
public new void InvalidateLayout() => base.InvalidateLayout();
|
||||
|
||||
public override IEnumerable<Drawable> FlowingChildren => base.FlowingChildren.OfType<RearrangeableListItem<PlaylistItem>>().OrderBy(item => item.Model.PlaylistOrder);
|
||||
}
|
||||
|
||||
|
||||
@@ -145,11 +145,10 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
|
||||
null,
|
||||
new Drawable[]
|
||||
{
|
||||
new MultiplayerPlaylist(Room)
|
||||
new MultiplayerPlaylist
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
RequestEdit = OpenSongSelection,
|
||||
SelectedItem = SelectedItem
|
||||
RequestEdit = OpenSongSelection
|
||||
}
|
||||
},
|
||||
new[]
|
||||
|
||||
@@ -267,7 +267,7 @@ namespace osu.Game.Tests.Visual.OnlinePlay
|
||||
/// <param name="host">The room host.</param>
|
||||
public void AddServerSideRoom(Room room, APIUser host)
|
||||
{
|
||||
room.RoomID ??= currentRoomId++;
|
||||
room.RoomID = currentRoomId++;
|
||||
room.Host = host;
|
||||
|
||||
for (int i = 0; i < room.Playlist.Count; i++)
|
||||
|
||||
Reference in New Issue
Block a user