Make Room.Playlist non-bindable

This commit is contained in:
Dan Balasescu 2024-11-14 17:57:32 +09:00
parent b16edbbf52
commit 34c0f72dd6
No known key found for this signature in database
41 changed files with 490 additions and 361 deletions

View File

@ -42,13 +42,13 @@ namespace osu.Game.Tests.Visual.DailyChallenge
RoomID = 1234,
Name = "Daily Challenge: June 4, 2024",
Playlist =
{
[
new PlaylistItem(TestResources.CreateTestBeatmapSetInfo().Beatmaps.First())
{
RequiredMods = [new APIMod(new OsuModTraceable())],
AllowedMods = [new APIMod(new OsuModDoubleTime())]
}
},
],
EndDate = DateTimeOffset.Now.AddHours(12),
Category = RoomCategory.DailyChallenge
};
@ -65,13 +65,13 @@ namespace osu.Game.Tests.Visual.DailyChallenge
RoomID = 1234,
Name = "Daily Challenge: June 4, 2024",
Playlist =
{
[
new PlaylistItem(TestResources.CreateTestBeatmapSetInfo().Beatmaps.First())
{
RequiredMods = [new APIMod(new OsuModTraceable())],
AllowedMods = [new APIMod(new OsuModDoubleTime())]
}
},
],
EndDate = DateTimeOffset.Now.AddHours(12),
Category = RoomCategory.DailyChallenge
};
@ -94,13 +94,13 @@ namespace osu.Game.Tests.Visual.DailyChallenge
RoomID = 1234,
Name = "Daily Challenge: June 4, 2024",
Playlist =
{
[
new PlaylistItem(TestResources.CreateTestBeatmapSetInfo().Beatmaps.First())
{
RequiredMods = [new APIMod(new OsuModTraceable())],
AllowedMods = [new APIMod(new OsuModDoubleTime())]
}
},
],
EndDate = DateTimeOffset.Now.AddHours(12),
Category = RoomCategory.DailyChallenge
};

View File

@ -71,13 +71,13 @@ namespace osu.Game.Tests.Visual.DailyChallenge
RoomID = roomId,
Name = "Daily Challenge: June 4, 2024",
Playlist =
{
[
new PlaylistItem(CreateAPIBeatmap(new OsuRuleset().RulesetInfo))
{
RequiredMods = [new APIMod(new OsuModTraceable())],
AllowedMods = [new APIMod(new OsuModDoubleTime())]
}
},
],
StartDate = DateTimeOffset.Now,
EndDate = DateTimeOffset.Now.AddHours(24),
Category = RoomCategory.DailyChallenge

View File

@ -45,9 +45,9 @@ namespace osu.Game.Tests.Visual.Menus
RoomID = 1234,
Name = "Aug 8, 2024",
Playlist =
{
[
new PlaylistItem(beatmap)
},
],
StartDate = DateTimeOffset.Now.AddMinutes(-30),
EndDate = DateTimeOffset.Now.AddSeconds(60)
});

View File

@ -76,12 +76,12 @@ namespace osu.Game.Tests.Visual.Multiplayer
Name = "Test Room",
QueueMode = Mode,
Playlist =
{
[
new PlaylistItem(InitialBeatmap)
{
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
}
}
]
}));
AddUntilStep("wait for room open", () => this.ChildrenOfType<MultiplayerMatchSubScreen>().FirstOrDefault()?.IsLoaded == true);

View File

@ -79,7 +79,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
Status = new RoomStatusOpen(),
EndDate = DateTimeOffset.Now.AddDays(1),
Type = MatchType.HeadToHead,
Playlist = { item1 },
Playlist = [item1],
CurrentPlaylistItem = item1
}),
createLoungeRoom(new Room
@ -89,7 +89,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
Password = "*",
EndDate = DateTimeOffset.Now.AddDays(1),
Type = MatchType.HeadToHead,
Playlist = { item3 },
Playlist = [item3],
CurrentPlaylistItem = item3
}),
createLoungeRoom(new Room
@ -97,7 +97,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
Name = "Playlist room with multiple beatmaps",
Status = new RoomStatusPlaying(),
EndDate = DateTimeOffset.Now.AddDays(1),
Playlist = { item1, item2 },
Playlist = [item1, item2],
CurrentPlaylistItem = item1
}),
createLoungeRoom(new Room

View File

@ -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.Graphics;
using osu.Game.Online.API;
using osu.Game.Online.Rooms;
@ -23,7 +24,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
SelectedRoom.Value = new Room();
Child = new MatchBeatmapDetailArea
Child = new MatchBeatmapDetailArea(SelectedRoom.Value)
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
@ -35,7 +36,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
private void createNewItem()
{
SelectedRoom.Value.Playlist.Add(new PlaylistItem(new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo)
SelectedRoom.Value.Playlist = SelectedRoom.Value.Playlist.Append(new PlaylistItem(new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo)
{
ID = SelectedRoom.Value.Playlist.Count,
RulesetID = new OsuRuleset().RulesetInfo.OnlineID,
@ -45,7 +46,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
new APIMod(new OsuModDoubleTime()),
new APIMod(new OsuModAutoplay())
}
});
}).ToArray();
}
}
}

View File

@ -119,7 +119,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
room.Value = new Room
{
Playlist = { item },
Playlist = [item],
CurrentPlaylistItem = item
};

View File

@ -105,12 +105,12 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
Name = "Test Room",
Playlist =
{
[
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
{
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
}
}
]
});
AddRepeatStep("random stuff happens", performRandomAction, 30);
@ -240,12 +240,12 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
Name = "Test Room",
Playlist =
{
[
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
{
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
}
}
]
});
AddUntilStep("Check participant count correct", () => multiplayerClient.ClientAPIRoom?.ParticipantCount == 1);
@ -261,12 +261,12 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
Name = "Test Room",
Playlist =
{
[
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
{
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
}
}
]
}, API.LocalUser.Value);
});
@ -290,12 +290,12 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
Name = "Test Room",
Playlist =
{
[
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
{
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
}
}
]
}, API.LocalUser.Value);
});
@ -320,12 +320,12 @@ namespace osu.Game.Tests.Visual.Multiplayer
Name = "Test Room",
Password = "password",
Playlist =
{
[
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
{
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
}
}
]
});
AddUntilStep("room has password", () => multiplayerClient.ClientAPIRoom?.Password == "password");
@ -341,12 +341,12 @@ namespace osu.Game.Tests.Visual.Multiplayer
Name = "Test Room",
Password = "password",
Playlist =
{
[
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
{
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
}
}
]
}, API.LocalUser.Value);
});
@ -373,12 +373,12 @@ namespace osu.Game.Tests.Visual.Multiplayer
Name = "Test Room",
Password = "password",
Playlist =
{
[
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
{
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
}
}
]
});
AddStep("change password", () => multiplayerClient.ChangeSettings(password: "password2"));
@ -403,12 +403,12 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
Name = "Test Room",
Playlist =
{
[
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
{
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
}
}
]
});
pressReadyButton();
@ -431,7 +431,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
return new Room
{
Name = "Test Room",
Playlist = { item }
Playlist = [item]
};
});
@ -472,7 +472,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
return new Room
{
Name = "Test Room",
Playlist = { item }
Playlist = [item]
};
});
@ -513,7 +513,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
return new Room
{
Name = "Test Room",
Playlist = { item }
Playlist = [item]
};
});
@ -550,12 +550,12 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
Name = "Test Room",
Playlist =
{
[
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
{
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
}
}
]
});
AddStep("join other user (ready, host)", () =>
@ -583,12 +583,12 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
Name = "Test Room",
Playlist =
{
[
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
{
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
}
}
]
});
AddStep("delete beatmap", () => beatmaps.Delete(importedSet));
@ -622,12 +622,12 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
Name = "Test Room",
Playlist =
{
[
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
{
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
}
}
]
});
AddStep("disconnect", () => multiplayerClient.Disconnect());
@ -641,13 +641,13 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
Name = "Test Room",
Playlist =
{
[
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
{
RulesetID = new OsuRuleset().RulesetInfo.OnlineID,
AllowedMods = new[] { new APIMod(new OsuModHidden()) }
}
}
]
});
AddStep("open mod overlay", () => this.ChildrenOfType<UserModSelectButton>().Single().TriggerClick());
@ -681,12 +681,12 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
Name = "Test Room",
Playlist =
{
[
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
{
RulesetID = new OsuRuleset().RulesetInfo.OnlineID,
}
}
]
});
enterGameplay();
@ -726,12 +726,12 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
Name = "Test Room",
Playlist =
{
[
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
{
RulesetID = new OsuRuleset().RulesetInfo.OnlineID,
}
}
]
});
enterGameplay();
@ -756,12 +756,12 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
Name = "Test Room",
Playlist =
{
[
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
{
RulesetID = new OsuRuleset().RulesetInfo.OnlineID,
}
}
]
});
pressReadyButton();
@ -794,12 +794,12 @@ namespace osu.Game.Tests.Visual.Multiplayer
Name = "Test Room",
QueueMode = QueueMode.AllPlayers,
Playlist =
{
[
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
{
RulesetID = new OsuRuleset().RulesetInfo.OnlineID,
}
}
]
}, API.LocalUser.Value);
});
@ -811,11 +811,14 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddStep("change server-side settings", () =>
{
roomManager.ServerSideRooms[0].Name = "New name";
roomManager.ServerSideRooms[0].Playlist.Add(new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
{
ID = 2,
RulesetID = new OsuRuleset().RulesetInfo.OnlineID,
});
roomManager.ServerSideRooms[0].Playlist =
[
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
{
ID = 2,
RulesetID = new OsuRuleset().RulesetInfo.OnlineID,
}
];
});
AddStep("join room", () => InputManager.Key(Key.Enter));
@ -825,8 +828,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddAssert("local room has correct settings", () =>
{
var localRoom = this.ChildrenOfType<MultiplayerMatchSubScreen>().Single().Room;
return localRoom.Name == roomManager.ServerSideRooms[0].Name
&& localRoom.Playlist.SequenceEqual(roomManager.ServerSideRooms[0].Playlist);
return localRoom.Name == roomManager.ServerSideRooms[0].Name && localRoom.Playlist.Single().ID == 2;
});
}
@ -839,12 +841,12 @@ namespace osu.Game.Tests.Visual.Multiplayer
Name = "Test Room",
QueueMode = QueueMode.AllPlayers,
Playlist =
{
[
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
{
RulesetID = new OsuRuleset().RulesetInfo.OnlineID,
}
}
]
});
AddStep("set spectating state", () => multiplayerClient.ChangeUserState(API.LocalUser.Value.OnlineID, MultiplayerUserState.Spectating));
@ -875,12 +877,12 @@ namespace osu.Game.Tests.Visual.Multiplayer
Name = "Test Room",
QueueMode = QueueMode.AllPlayers,
Playlist =
{
[
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
{
RulesetID = new OsuRuleset().RulesetInfo.OnlineID,
}
}
]
});
AddStep("set spectating state", () => multiplayerClient.ChangeUserState(API.LocalUser.Value.OnlineID, MultiplayerUserState.Spectating));
@ -914,12 +916,12 @@ namespace osu.Game.Tests.Visual.Multiplayer
Name = "Test Room",
QueueMode = QueueMode.AllPlayers,
Playlist =
{
[
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
{
RulesetID = new OsuRuleset().RulesetInfo.OnlineID,
}
}
]
});
enterGameplay();
@ -945,12 +947,12 @@ namespace osu.Game.Tests.Visual.Multiplayer
Name = "Test Room",
QueueMode = QueueMode.AllPlayers,
Playlist =
{
[
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
{
RulesetID = new OsuRuleset().RulesetInfo.OnlineID,
}
}
]
});
enterGameplay();
@ -978,12 +980,12 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
Name = "Test Room",
Playlist =
{
[
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
{
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
}
}
]
});
AddStep("join other user and make host", () =>
@ -1025,7 +1027,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
Name = "Test Room",
QueueMode = QueueMode.AllPlayers,
Playlist =
{
[
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
{
RulesetID = new OsuRuleset().RulesetInfo.OnlineID,
@ -1036,7 +1038,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
RulesetID = new TaikoRuleset().RulesetInfo.OnlineID,
AllowedMods = new[] { new APIMod { Acronym = "HD" } },
},
}
]
});
AddStep("select hidden", () => multiplayerClient.ChangeUserMods(new[] { new APIMod { Acronym = "HD" } }));

View File

@ -100,10 +100,13 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
AddStep("add playlist item", () =>
{
SelectedRoom.Value.Playlist.Add(new PlaylistItem(new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo)
{
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
});
SelectedRoom.Value.Playlist =
[
new PlaylistItem(new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo)
{
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
}
];
});
ClickButtonWhenEnabled<MultiplayerMatchSettingsOverlay.CreateOrUpdateButton>();
@ -117,11 +120,14 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
AddStep("add playlist item", () =>
{
SelectedRoom.Value.Playlist.Add(new PlaylistItem(new TestBeatmap(new TaikoRuleset().RulesetInfo).BeatmapInfo)
{
RulesetID = new TaikoRuleset().RulesetInfo.OnlineID,
AllowedMods = new[] { new APIMod(new TaikoModSwap()) }
});
SelectedRoom.Value.Playlist =
[
new PlaylistItem(new TestBeatmap(new TaikoRuleset().RulesetInfo).BeatmapInfo)
{
RulesetID = new TaikoRuleset().RulesetInfo.OnlineID,
AllowedMods = new[] { new APIMod(new TaikoModSwap()) }
}
];
});
ClickButtonWhenEnabled<MultiplayerMatchSettingsOverlay.CreateOrUpdateButton>();
@ -140,10 +146,13 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddStep("set playlist", () =>
{
SelectedRoom.Value.Playlist.Add(new PlaylistItem(new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo)
{
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
});
SelectedRoom.Value.Playlist =
[
new PlaylistItem(new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo)
{
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
}
];
});
AddAssert("create button enabled", () => this.ChildrenOfType<MultiplayerMatchSettingsOverlay.CreateOrUpdateButton>().Single().Enabled.Value);
@ -155,10 +164,13 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
AddStep("set playlist", () =>
{
SelectedRoom.Value.Playlist.Add(new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First()).BeatmapInfo)
{
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
});
SelectedRoom.Value.Playlist =
[
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First()).BeatmapInfo)
{
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
}
];
});
ClickButtonWhenEnabled<MultiplayerMatchSettingsOverlay.CreateOrUpdateButton>();
@ -184,11 +196,14 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
AddStep("add playlist item with allowed mod", () =>
{
SelectedRoom.Value.Playlist.Add(new PlaylistItem(new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo)
{
RulesetID = new OsuRuleset().RulesetInfo.OnlineID,
AllowedMods = new[] { new APIMod(new OsuModDoubleTime()) }
});
SelectedRoom.Value.Playlist =
[
new PlaylistItem(new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo)
{
RulesetID = new OsuRuleset().RulesetInfo.OnlineID,
AllowedMods = new[] { new APIMod(new OsuModDoubleTime()) }
}
];
});
ClickButtonWhenEnabled<MultiplayerMatchSettingsOverlay.CreateOrUpdateButton>();
@ -211,11 +226,14 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
AddStep("add playlist item with allowed mod", () =>
{
SelectedRoom.Value.Playlist.Add(new PlaylistItem(new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo)
{
RulesetID = new OsuRuleset().RulesetInfo.OnlineID,
AllowedMods = new[] { new APIMod(new OsuModDoubleTime()) }
});
SelectedRoom.Value.Playlist =
[
new PlaylistItem(new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo)
{
RulesetID = new OsuRuleset().RulesetInfo.OnlineID,
AllowedMods = new[] { new APIMod(new OsuModDoubleTime()) }
}
];
});
ClickButtonWhenEnabled<MultiplayerMatchSettingsOverlay.CreateOrUpdateButton>();
@ -233,10 +251,13 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
AddStep("add playlist item with no allowed mods", () =>
{
SelectedRoom.Value.Playlist.Add(new PlaylistItem(new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo)
{
RulesetID = new OsuRuleset().RulesetInfo.OnlineID,
});
SelectedRoom.Value.Playlist =
[
new PlaylistItem(new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo)
{
RulesetID = new OsuRuleset().RulesetInfo.OnlineID,
}
];
});
ClickButtonWhenEnabled<MultiplayerMatchSettingsOverlay.CreateOrUpdateButton>();
@ -254,8 +275,8 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
AddStep("add two playlist items", () =>
{
SelectedRoom.Value.Playlist.AddRange(new[]
{
SelectedRoom.Value.Playlist =
[
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First()).BeatmapInfo)
{
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
@ -264,7 +285,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
}
});
];
});
ClickButtonWhenEnabled<MultiplayerMatchSettingsOverlay.CreateOrUpdateButton>();
@ -291,19 +312,22 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
AddStep("add playlist item", () =>
{
SelectedRoom.Value.Playlist.Add(new PlaylistItem(new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo)
{
RulesetID = new OsuRuleset().RulesetInfo.OnlineID,
RequiredMods = new[]
SelectedRoom.Value.Playlist =
[
new PlaylistItem(new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo)
{
new APIMod(new OsuModDoubleTime { SpeedChange = { Value = 2.0 } }),
new APIMod(new OsuModStrictTracking()),
},
AllowedMods = new[]
{
new APIMod(new OsuModFlashlight()),
RulesetID = new OsuRuleset().RulesetInfo.OnlineID,
RequiredMods = new[]
{
new APIMod(new OsuModDoubleTime { SpeedChange = { Value = 2.0 } }),
new APIMod(new OsuModStrictTracking()),
},
AllowedMods = new[]
{
new APIMod(new OsuModFlashlight()),
}
}
});
];
});
ClickButtonWhenEnabled<MultiplayerMatchSettingsOverlay.CreateOrUpdateButton>();

View File

@ -48,7 +48,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddStep("create list", () =>
{
Child = list = new MultiplayerPlaylist
Child = list = new MultiplayerPlaylist(SelectedRoom.Value)
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
@ -166,7 +166,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
Name = "test name",
Playlist =
{
[
new PlaylistItem(new TestBeatmap(Ruleset.Value).BeatmapInfo)
{
RulesetID = Ruleset.Value.OnlineID
@ -176,7 +176,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
RulesetID = Ruleset.Value.OnlineID,
Expired = true
}
}
]
});
});

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using System;
using System.Linq;
using NUnit.Framework;
@ -27,10 +25,10 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
public partial class TestSceneMultiplayerQueueList : MultiplayerTestScene
{
private MultiplayerQueueList playlist;
private BeatmapManager beatmaps;
private BeatmapSetInfo importedSet;
private BeatmapInfo importedBeatmap;
private MultiplayerQueueList playlist = null!;
private BeatmapManager beatmaps = null!;
private BeatmapSetInfo importedSet = null!;
private BeatmapInfo importedBeatmap = null!;
[BackgroundDependencyLoader]
private void load(GameHost host, AudioManager audio)
@ -46,12 +44,17 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddStep("create playlist", () =>
{
Child = playlist = new MultiplayerQueueList
Child = playlist = new MultiplayerQueueList(SelectedRoom.Value)
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Size = new Vector2(500, 300),
Items = { BindTarget = MultiplayerClient.ClientAPIRoom!.Playlist }
};
MultiplayerClient.ClientAPIRoom!.PropertyChanged += (_, e) =>
{
if (e.PropertyName == nameof(Room.Playlist))
playlist.Items.ReplaceRange(0, playlist.Items.Count, MultiplayerClient.ClientAPIRoom.Playlist);
};
});

View File

@ -99,12 +99,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
AddStep("create new item", () => songSelect.BeatmapDetails.CreateNewItem());
AddStep("create new item", () => songSelect.BeatmapDetails.CreateNewItem());
AddStep("rearrange", () =>
{
var item = SelectedRoom.Value.Playlist[0];
SelectedRoom.Value.Playlist.RemoveAt(0);
SelectedRoom.Value.Playlist.Add(item);
});
AddStep("rearrange", () => SelectedRoom.Value.Playlist = SelectedRoom.Value.Playlist.Skip(1).Append(SelectedRoom.Value.Playlist[0]).ToArray());
AddStep("create new item", () => songSelect.BeatmapDetails.CreateNewItem());
AddAssert("new item has id 2", () => SelectedRoom.Value.Playlist.Last().ID == 2);

View File

@ -33,11 +33,11 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
AddStep("set playlist", () =>
{
SelectedRoom.Value.Playlist.AddRange(new[]
{
SelectedRoom.Value.Playlist =
[
new PlaylistItem(new BeatmapInfo { StarRating = min }),
new PlaylistItem(new BeatmapInfo { StarRating = max }),
});
];
});
}
}

View File

@ -65,12 +65,12 @@ namespace osu.Game.Tests.Visual.Multiplayer
Name = "Test Room",
Type = MatchType.TeamVersus,
Playlist =
{
[
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
{
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
}
}
]
});
AddUntilStep("room type is team vs", () => multiplayerClient.ClientRoom?.Settings.MatchType == MatchType.TeamVersus);
@ -85,12 +85,12 @@ namespace osu.Game.Tests.Visual.Multiplayer
Name = "Test Room",
Type = MatchType.TeamVersus,
Playlist =
{
[
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
{
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
}
}
]
});
AddUntilStep("user on team 0", () => (multiplayerClient.ClientRoom?.Users.FirstOrDefault()?.MatchState as TeamVersusUserState)?.TeamID == 0);
@ -122,12 +122,12 @@ namespace osu.Game.Tests.Visual.Multiplayer
Name = "Test Room",
Type = MatchType.HeadToHead,
Playlist =
{
[
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
{
RulesetID = new OsuRuleset().RulesetInfo.OnlineID,
}
}
]
});
AddUntilStep("match type head to head", () => multiplayerClient.ClientAPIRoom?.Type == MatchType.HeadToHead);
@ -147,12 +147,12 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
Name = "Test Room",
Playlist =
{
[
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
{
RulesetID = new OsuRuleset().RulesetInfo.OnlineID,
}
}
]
});
AddUntilStep("room type is head to head", () => multiplayerClient.ClientRoom?.Settings.MatchType == MatchType.HeadToHead);

View File

@ -46,7 +46,7 @@ namespace osu.Game.Tests.Visual.Playlists
AddStep("clear name and beatmap", () =>
{
SelectedRoom.Value.Name = "";
SelectedRoom.Value.Playlist.Clear();
SelectedRoom.Value.Playlist = [];
});
AddAssert("button disabled", () => !settings.ApplyButton.Enabled.Value);
@ -54,7 +54,7 @@ namespace osu.Game.Tests.Visual.Playlists
AddStep("set name", () => SelectedRoom.Value.Name = "Room name");
AddAssert("button disabled", () => !settings.ApplyButton.Enabled.Value);
AddStep("set beatmap", () => SelectedRoom.Value.Playlist.Add(new PlaylistItem(CreateBeatmap(Ruleset.Value).BeatmapInfo)));
AddStep("set beatmap", () => SelectedRoom.Value.Playlist = [new PlaylistItem(CreateBeatmap(Ruleset.Value).BeatmapInfo)]);
AddAssert("button enabled", () => settings.ApplyButton.Enabled.Value);
AddStep("clear name", () => SelectedRoom.Value.Name = "");
@ -73,7 +73,7 @@ namespace osu.Game.Tests.Visual.Playlists
{
settings.NameField.Current.Value = expected_name;
settings.DurationField.Current.Value = expectedDuration;
SelectedRoom.Value.Playlist.Add(new PlaylistItem(CreateBeatmap(Ruleset.Value).BeatmapInfo));
SelectedRoom.Value.Playlist = [new PlaylistItem(CreateBeatmap(Ruleset.Value).BeatmapInfo)];
RoomManager.CreateRequested = r =>
{
@ -99,7 +99,7 @@ namespace osu.Game.Tests.Visual.Playlists
var beatmap = CreateBeatmap(Ruleset.Value).BeatmapInfo;
SelectedRoom.Value.Name = "Test Room";
SelectedRoom.Value.Playlist.Add(new PlaylistItem(beatmap));
SelectedRoom.Value.Playlist = [new PlaylistItem(beatmap)];
errorMessage = $"{not_found_prefix} {beatmap.OnlineID}";
@ -126,7 +126,7 @@ namespace osu.Game.Tests.Visual.Playlists
AddStep("setup", () =>
{
SelectedRoom.Value.Name = "Test Room";
SelectedRoom.Value.Playlist.Add(new PlaylistItem(CreateBeatmap(Ruleset.Value).BeatmapInfo));
SelectedRoom.Value.Playlist = [new PlaylistItem(CreateBeatmap(Ruleset.Value).BeatmapInfo)];
RoomManager.CreateRequested = _ => failText;
});

View File

@ -64,10 +64,13 @@ namespace osu.Game.Tests.Visual.Playlists
room.Host = API.LocalUser.Value;
room.RecentParticipants = [room.Host];
room.EndDate = DateTimeOffset.Now.AddMinutes(5);
room.Playlist.Add(new PlaylistItem(importedBeatmap.Beatmaps.First())
{
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
});
room.Playlist =
[
new PlaylistItem(importedBeatmap.Beatmaps.First())
{
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
}
];
});
AddUntilStep("Progress details are hidden", () => match.ChildrenOfType<RoomLocalUserInfo>().FirstOrDefault()?.Parent!.Alpha == 0);
@ -88,10 +91,13 @@ namespace osu.Game.Tests.Visual.Playlists
room.Host = API.LocalUser.Value;
room.RecentParticipants = [room.Host];
room.EndDate = DateTimeOffset.Now.AddMinutes(5);
room.Playlist.Add(new PlaylistItem(importedBeatmap.Beatmaps.First())
{
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
});
room.Playlist =
[
new PlaylistItem(importedBeatmap.Beatmaps.First())
{
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
}
];
});
AddUntilStep("Progress details are visible", () => match.ChildrenOfType<RoomLocalUserInfo>().FirstOrDefault()?.Parent!.Alpha == 1);
@ -104,10 +110,13 @@ namespace osu.Game.Tests.Visual.Playlists
{
room.Name = "my awesome room";
room.Host = API.LocalUser.Value;
room.Playlist.Add(new PlaylistItem(importedBeatmap.Beatmaps.First())
{
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
});
room.Playlist =
[
new PlaylistItem(importedBeatmap.Beatmaps.First())
{
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
}
];
});
AddAssert("first playlist item selected", () => match.SelectedItem.Value == SelectedRoom.Value.Playlist[0]);
@ -152,19 +161,22 @@ namespace osu.Game.Tests.Visual.Playlists
{
room.Name = "my awesome room";
room.Host = API.LocalUser.Value;
room.Playlist.Add(new PlaylistItem(new BeatmapInfo
{
MD5Hash = realHash,
OnlineID = realOnlineId,
Metadata = new BeatmapMetadata(),
BeatmapSet = new BeatmapSetInfo
room.Playlist =
[
new PlaylistItem(new BeatmapInfo
{
OnlineID = realOnlineSetId,
MD5Hash = realHash,
OnlineID = realOnlineId,
Metadata = new BeatmapMetadata(),
BeatmapSet = new BeatmapSetInfo
{
OnlineID = realOnlineSetId,
}
})
{
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
}
})
{
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
});
];
});
AddAssert("match has default beatmap", () => match.Beatmap.IsDefault);

View File

@ -55,9 +55,9 @@ namespace osu.Game.Tests.Visual.UserInterface
{
RoomID = 1234,
Playlist =
{
[
new PlaylistItem(beatmap)
},
],
StartDate = DateTimeOffset.Now.AddMinutes(-5),
EndDate = DateTimeOffset.Now.AddSeconds(30)
});
@ -133,9 +133,9 @@ namespace osu.Game.Tests.Visual.UserInterface
{
RoomID = 1234,
Playlist =
{
[
new PlaylistItem(beatmap)
},
],
StartDate = DateTimeOffset.Now.AddMinutes(-50),
EndDate = DateTimeOffset.Now.AddSeconds(30)
});

View File

@ -5,7 +5,6 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using osu.Framework.Allocation;
@ -201,8 +200,7 @@ namespace osu.Game.Online.Multiplayer
Debug.Assert(joinedRoom.Playlist.Count > 0);
APIRoom.Playlist.Clear();
APIRoom.Playlist.AddRange(joinedRoom.Playlist.Select(item => new PlaylistItem(item)));
APIRoom.Playlist = joinedRoom.Playlist.Select(item => new PlaylistItem(item)).ToArray();
APIRoom.CurrentPlaylistItem = APIRoom.Playlist.Single(item => item.ID == joinedRoom.Settings.PlaylistItemId);
// The server will null out the end date upon the host joining the room, but the null value is never communicated to the client.
@ -734,7 +732,7 @@ namespace osu.Game.Online.Multiplayer
Debug.Assert(APIRoom != null);
Room.Playlist.Add(item);
APIRoom.Playlist.Add(new PlaylistItem(item));
APIRoom.Playlist = APIRoom.Playlist.Append(new PlaylistItem(item)).ToArray();
ItemAdded?.Invoke(item);
RoomUpdated?.Invoke();
@ -753,7 +751,7 @@ namespace osu.Game.Online.Multiplayer
Debug.Assert(APIRoom != null);
Room.Playlist.Remove(Room.Playlist.Single(existing => existing.ID == playlistItemId));
APIRoom.Playlist.RemoveAll(existing => existing.ID == playlistItemId);
APIRoom.Playlist = APIRoom.Playlist.Where(i => i.ID != playlistItemId).ToArray();
Debug.Assert(Room.Playlist.Count > 0);
@ -771,30 +769,10 @@ namespace osu.Game.Online.Multiplayer
if (Room == null)
return;
try
{
Debug.Assert(APIRoom != null);
Debug.Assert(APIRoom != null);
Room.Playlist[Room.Playlist.IndexOf(Room.Playlist.Single(existing => existing.ID == item.ID))] = item;
int existingIndex = APIRoom.Playlist.IndexOf(APIRoom.Playlist.Single(existing => existing.ID == item.ID));
APIRoom.Playlist.RemoveAt(existingIndex);
APIRoom.Playlist.Insert(existingIndex, new PlaylistItem(item));
}
catch (Exception ex)
{
// Temporary code to attempt to figure out long-term failing tests.
StringBuilder exceptionText = new StringBuilder();
exceptionText.AppendLine("MultiplayerClient test failure investigation");
exceptionText.AppendLine($"Exception : {ex.ToString()}");
exceptionText.AppendLine($"Lookup : {item.ID}");
exceptionText.AppendLine($"Items in Room.Playlist : {string.Join(',', Room.Playlist.Select(i => i.ID))}");
exceptionText.AppendLine($"Items in APIRoom.Playlist: {string.Join(',', APIRoom!.Playlist.Select(i => i.ID))}");
throw new AggregateException(exceptionText.ToString());
}
Room.Playlist[Room.Playlist.IndexOf(Room.Playlist.Single(existing => existing.ID == item.ID))] = item;
APIRoom.Playlist = APIRoom.Playlist.Select((pi, i) => pi.ID == item.ID ? new PlaylistItem(item) : APIRoom.Playlist[i]).ToArray();
ItemChanged?.Invoke(item);
RoomUpdated?.Invoke();

View File

@ -5,7 +5,6 @@ using System.Collections.Generic;
using System.Linq;
using Humanizer;
using Humanizer.Localisation;
using osu.Framework.Bindables;
using osu.Game.Rulesets;
using osu.Game.Utils;
@ -30,7 +29,7 @@ namespace osu.Game.Online.Rooms
/// or the last-played <see cref="PlaylistItem"/> if all items are expired,
/// or <see langword="null"/> if <paramref name="playlist"/> was empty.
/// </summary>
public static PlaylistItem? GetCurrentItem(this ICollection<PlaylistItem> playlist)
public static PlaylistItem? GetCurrentItem(this IReadOnlyCollection<PlaylistItem> playlist)
{
if (playlist.Count == 0)
return null;
@ -43,7 +42,7 @@ namespace osu.Game.Online.Rooms
/// <summary>
/// Returns the total duration from the <see cref="PlaylistItem"/> in playlist order from the supplied <paramref name="playlist"/>,
/// </summary>
public static string GetTotalDuration(this BindableList<PlaylistItem> playlist, RulesetStore rulesetStore) =>
public static string GetTotalDuration(this IReadOnlyList<PlaylistItem> playlist, RulesetStore rulesetStore) =>
playlist.Select(p =>
{
double rate = 1;

View File

@ -120,18 +120,21 @@ namespace osu.Game.Online.Rooms
#endregion
public PlaylistItem With(Optional<IBeatmapInfo> beatmap = default, Optional<ushort?> playlistOrder = default) => new PlaylistItem(beatmap.GetOr(Beatmap))
public PlaylistItem With(Optional<long> id = default, Optional<IBeatmapInfo> beatmap = default, Optional<ushort?> playlistOrder = default)
{
ID = ID,
OwnerID = OwnerID,
RulesetID = RulesetID,
Expired = Expired,
PlaylistOrder = playlistOrder.GetOr(PlaylistOrder),
PlayedAt = PlayedAt,
AllowedMods = AllowedMods,
RequiredMods = RequiredMods,
valid = { Value = Valid.Value },
};
return new PlaylistItem(beatmap.GetOr(Beatmap))
{
ID = id.GetOr(ID),
OwnerID = OwnerID,
RulesetID = RulesetID,
Expired = Expired,
PlaylistOrder = playlistOrder.GetOr(PlaylistOrder),
PlayedAt = PlayedAt,
AllowedMods = AllowedMods,
RequiredMods = RequiredMods,
valid = { Value = Valid.Value },
};
}
public bool Equals(PlaylistItem? other)
=> ID == other?.ID

View File

@ -8,7 +8,6 @@ using System.Linq;
using System.Runtime.CompilerServices;
using Newtonsoft.Json;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Game.IO.Serialization.Converters;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.Multiplayer;
@ -164,6 +163,15 @@ namespace osu.Game.Online.Rooms
set => SetField(ref maxAttempts, value);
}
/// <summary>
/// The room playlist.
/// </summary>
public IReadOnlyList<PlaylistItem> Playlist
{
get => playlist;
set => SetList(ref playlist, value);
}
/// <summary>
/// Describes the items in the playlist.
/// </summary>
@ -297,6 +305,9 @@ namespace osu.Game.Online.Rooms
[JsonProperty("max_attempts", DefaultValueHandling = DefaultValueHandling.Ignore)]
private int? maxAttempts;
[JsonProperty("playlist")]
private IReadOnlyList<PlaylistItem> playlist = [];
[JsonProperty("playlist_item_stats")]
private RoomPlaylistItemStats? playlistItemStats;
@ -332,10 +343,6 @@ namespace osu.Game.Online.Rooms
// Not yet serialised (not implemented).
private RoomAvailability availability;
[Cached]
[JsonProperty("playlist")]
public readonly BindableList<PlaylistItem> Playlist = new BindableList<PlaylistItem>();
/// <summary>
/// Copies values from another <see cref="Room"/> into this one.
/// </summary>
@ -371,12 +378,7 @@ namespace osu.Game.Online.Rooms
other.RemoveExpiredPlaylistItems();
if (!Playlist.SequenceEqual(other.Playlist))
{
Playlist.Clear();
Playlist.AddRange(other.Playlist);
}
Playlist = other.Playlist;
RecentParticipants = other.RecentParticipants;
}
@ -386,7 +388,7 @@ namespace osu.Game.Online.Rooms
// and display only the non-expired playlist items while the room is still active. In order to achieve this, all expired items are removed from the source Room.
// More refactoring is required before this can be done locally instead - DrawableRoomPlaylist is currently directly bound to the playlist to display items in the room.
if (Status is not RoomStatusEnded)
Playlist.RemoveAll(i => i.Expired);
Playlist = Playlist.Where(i => !i.Expired).ToArray();
}
[JsonObject(MemberSerialization.OptIn)]

View File

@ -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.ComponentModel;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
@ -8,25 +9,31 @@ using osu.Framework.Localisation;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Online.Chat;
using osu.Game.Online.Rooms;
namespace osu.Game.Screens.OnlinePlay.Components
{
public partial class BeatmapTitle : OnlinePlayComposite
{
private readonly Room room;
private readonly LinkFlowContainer textFlow;
public BeatmapTitle()
{
AutoSizeAxes = Axes.Both;
[Resolved]
private OsuColour colours { get; set; } = null!;
public BeatmapTitle(Room room)
{
this.room = room;
AutoSizeAxes = Axes.Both;
InternalChild = textFlow = new LinkFlowContainer { AutoSizeAxes = Axes.Both };
}
[BackgroundDependencyLoader]
private void load()
protected override void LoadComplete()
{
Playlist.CollectionChanged += (_, _) => updateText();
base.LoadComplete();
room.PropertyChanged += onRoomPropertyChanged;
updateText();
}
@ -46,8 +53,11 @@ namespace osu.Game.Screens.OnlinePlay.Components
}
}
[Resolved]
private OsuColour colours { get; set; } = null!;
private void onRoomPropertyChanged(object? sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(Room.Playlist))
updateText();
}
private void updateText()
{
@ -56,7 +66,7 @@ namespace osu.Game.Screens.OnlinePlay.Components
textFlow.Clear();
var beatmap = Playlist.FirstOrDefault()?.Beatmap;
var beatmap = room.Playlist.FirstOrDefault()?.Beatmap;
if (beatmap == null)
{
@ -78,5 +88,11 @@ namespace osu.Game.Screens.OnlinePlay.Components
textFlow.AddLink(title, LinkAction.OpenBeatmap, beatmap.OnlineID.ToString(), "Open beatmap");
}
}
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
room.PropertyChanged -= onRoomPropertyChanged;
}
}
}

View File

@ -1,12 +1,9 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using System;
using System.ComponentModel;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Graphics.UserInterfaceV2;
@ -14,23 +11,22 @@ using osu.Game.Online.Rooms;
using osu.Game.Screens.OnlinePlay.Playlists;
using osu.Game.Screens.Select;
using osuTK;
using Container = osu.Framework.Graphics.Containers.Container;
namespace osu.Game.Screens.OnlinePlay.Components
{
public partial class MatchBeatmapDetailArea : BeatmapDetailArea
{
public Action CreateNewItem;
public readonly Bindable<PlaylistItem> SelectedItem = new Bindable<PlaylistItem>();
[Resolved(typeof(Room))]
protected BindableList<PlaylistItem> Playlist { get; private set; }
public Action? CreateNewItem;
private readonly Room room;
private readonly GridContainer playlistArea;
private readonly DrawableRoomPlaylist playlist;
public MatchBeatmapDetailArea()
public MatchBeatmapDetailArea(Room room)
{
this.room = room;
Add(playlistArea = new GridContainer
{
RelativeSizeAxes = Axes.Both,
@ -72,10 +68,21 @@ namespace osu.Game.Screens.OnlinePlay.Components
{
base.LoadComplete();
playlist.Items.BindTo(Playlist);
playlist.SelectedItem.BindTo(SelectedItem);
playlist.Items.BindCollectionChanged((_, __) => room.Playlist = playlist.Items.ToArray());
room.PropertyChanged += onRoomPropertyChanged;
updateRoomPlaylist();
}
private void onRoomPropertyChanged(object? sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(Room.Playlist))
updateRoomPlaylist();
}
private void updateRoomPlaylist()
=> playlist.Items.ReplaceRange(0, playlist.Items.Count, room.Playlist);
protected override void OnTabChanged(BeatmapDetailAreaTabItem tab, bool selectedMods)
{
base.OnTabChanged(tab, selectedMods);
@ -93,5 +100,11 @@ namespace osu.Game.Screens.OnlinePlay.Components
}
protected override BeatmapDetailAreaTabItem[] CreateTabItems() => base.CreateTabItems().Prepend(new BeatmapDetailAreaPlaylistTabItem()).ToArray();
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
room.PropertyChanged -= onRoomPropertyChanged;
}
}
}

View File

@ -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.ComponentModel;
using osu.Framework.Allocation;
using osu.Game.Online.Rooms;
using osu.Game.Rulesets;
@ -9,19 +10,38 @@ namespace osu.Game.Screens.OnlinePlay.Components
{
public partial class OverlinedPlaylistHeader : OverlinedHeader
{
private readonly Room room;
[Resolved]
private RulesetStore rulesets { get; set; } = null!;
public OverlinedPlaylistHeader()
public OverlinedPlaylistHeader(Room room)
: base("Playlist")
{
this.room = room;
}
protected override void LoadComplete()
{
base.LoadComplete();
Playlist.BindCollectionChanged((_, _) => Details.Value = Playlist.GetTotalDuration(rulesets), true);
room.PropertyChanged += onRoomPropertyChanged;
updateDuration();
}
private void onRoomPropertyChanged(object? sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(Room.Playlist))
updateDuration();
}
private void updateDuration()
=> Details.Value = room.Playlist.GetTotalDuration(rulesets);
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
room.PropertyChanged -= onRoomPropertyChanged;
}
}
}

View File

@ -80,16 +80,19 @@ namespace osu.Game.Screens.OnlinePlay.Components
{
base.LoadComplete();
Playlist.BindCollectionChanged((_, _) => updateRange());
room.PropertyChanged += onRoomPropertyChanged;
updateRange();
}
private void onRoomPropertyChanged(object? sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(Room.DifficultyRange))
updateRange();
switch (e.PropertyName)
{
case nameof(Room.Playlist):
case nameof(Room.DifficultyRange):
updateRange();
break;
}
}
private void updateRange()
@ -97,7 +100,7 @@ namespace osu.Game.Screens.OnlinePlay.Components
StarDifficulty minDifficulty;
StarDifficulty maxDifficulty;
if (room.DifficultyRange != null && Playlist.Count == 0)
if (room.DifficultyRange != null && room.Playlist.Count == 0)
{
// When Playlist is empty (in lounge) we take retrieved range
minDifficulty = new StarDifficulty(room.DifficultyRange.Min, 0);
@ -106,7 +109,7 @@ namespace osu.Game.Screens.OnlinePlay.Components
else
{
// When Playlist is not empty (in room) we compute actual range
var orderedDifficulties = Playlist.Select(p => p.Beatmap).OrderBy(b => b.StarRating).ToArray();
var orderedDifficulties = room.Playlist.Select(p => p.Beatmap).OrderBy(b => b.StarRating).ToArray();
minDifficulty = new StarDifficulty(orderedDifficulties.Length > 0 ? orderedDifficulties[0].StarRating : 0, 0);
maxDifficulty = new StarDifficulty(orderedDifficulties.Length > 0 ? orderedDifficulties[^1].StarRating : 0, 0);

View File

@ -26,24 +26,27 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
{
base.LoadComplete();
Playlist.BindCollectionChanged((_, _) => updateCount());
room.PropertyChanged += onRoomPropertyChanged;
updateCount();
}
private void onRoomPropertyChanged(object? sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(Room.PlaylistItemStats))
updateCount();
switch (e.PropertyName)
{
case nameof(Room.Playlist):
case nameof(Room.PlaylistItemStats):
updateCount();
break;
}
}
private void updateCount()
{
int activeItems = Playlist.Count > 0 || room.PlaylistItemStats == null
int activeItems = room.Playlist.Count > 0 || room.PlaylistItemStats == null
// For now, use the playlist as the source of truth if it has any items.
// This allows the count to display correctly on the room screen (after joining a room).
? Playlist.Count(i => !i.Expired)
? room.Playlist.Count(i => !i.Expired)
: room.PlaylistItemStats.CountActive;
TextFlow.Clear();

View File

@ -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.ComponentModel;
using osu.Framework.Bindables;
using osu.Framework.Screens;
using osu.Game.Online.Rooms;
@ -19,21 +20,44 @@ namespace osu.Game.Screens.OnlinePlay.Lounge
playlist.BindCollectionChanged((_, _) => PlaylistItem = playlist.GetCurrentItem());
}
protected override void LoadComplete()
{
base.LoadComplete();
SelectedRoom.BindValueChanged(onSelectedRoomChanged, true);
}
private void onSelectedRoomChanged(ValueChangedEvent<Room?> room)
{
if (room.OldValue != null)
playlist.UnbindFrom(room.OldValue.Playlist);
room.OldValue.PropertyChanged -= onRoomPropertyChanged;
if (room.NewValue != null)
playlist.BindTo(room.NewValue.Playlist);
else
playlist.Clear();
room.NewValue.PropertyChanged += onRoomPropertyChanged;
updateCurrentItem();
}
private void onRoomPropertyChanged(object? sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(Room.Playlist))
updateCurrentItem();
}
private void updateCurrentItem()
=> PlaylistItem = SelectedRoom.Value?.Playlist.GetCurrentItem();
public override bool OnExiting(ScreenExitEvent e)
{
// This screen never exits.
return true;
}
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
if (SelectedRoom.Value != null)
SelectedRoom.Value.PropertyChanged -= onRoomPropertyChanged;
}
}
}

View File

@ -4,6 +4,7 @@
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Extensions;
@ -277,7 +278,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match
drawablePlaylist = new DrawableRoomPlaylist
{
RelativeSizeAxes = Axes.X,
Height = DrawableRoomPlaylistItem.HEIGHT
Height = DrawableRoomPlaylistItem.HEIGHT,
SelectedItem = { BindTarget = SelectedItem }
},
selectBeatmapButton = new RoundedButton
{
@ -365,9 +367,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match
{
base.LoadComplete();
drawablePlaylist.Items.BindTo(Playlist);
drawablePlaylist.SelectedItem.BindTo(SelectedItem);
room.PropertyChanged += onRoomPropertyChanged;
updateRoomName();
@ -377,6 +376,9 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match
updateRoomAutoSkip();
updateRoomMaxParticipants();
updateRoomAutoStartDuration();
updateRoomPlaylist();
drawablePlaylist.Items.BindCollectionChanged((_, __) => room.Playlist = drawablePlaylist.Items.ToArray());
}
private void onRoomPropertyChanged(object? sender, PropertyChangedEventArgs e)
@ -410,6 +412,10 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match
case nameof(Room.AutoStartDuration):
updateRoomAutoStartDuration();
break;
case nameof(Room.Playlist):
updateRoomPlaylist();
break;
}
}
@ -434,11 +440,14 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match
private void updateRoomAutoStartDuration()
=> typeLabel.Text = room.AutoStartDuration.GetLocalisableDescription();
private void updateRoomPlaylist()
=> drawablePlaylist.Items.ReplaceRange(0, drawablePlaylist.Items.Count, room.Playlist);
protected override void Update()
{
base.Update();
ApplyButton.Enabled.Value = Playlist.Count > 0 && NameField.Text.Length > 0 && !operationInProgress.Value;
ApplyButton.Enabled.Value = room.Playlist.Count > 0 && NameField.Text.Length > 0 && !operationInProgress.Value;
playlistContainer.Alpha = room.RoomID == null ? 1 : 0;
}

View File

@ -33,12 +33,18 @@ 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()
{
@ -59,7 +65,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match.Playlist
Masking = true,
Children = new Drawable[]
{
queueList = new MultiplayerQueueList
queueList = new MultiplayerQueueList(room)
{
RelativeSizeAxes = Axes.Both,
SelectedItem = { BindTarget = selectedItem },

View File

@ -1,12 +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.
#nullable disable
using System.Collections.Generic;
using System.ComponentModel;
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.API;
@ -21,28 +20,49 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match.Playlist
/// </summary>
public partial class MultiplayerQueueList : DrawableRoomPlaylist
{
public MultiplayerQueueList()
private readonly Room room;
private QueueFillFlowContainer flow = null!;
public MultiplayerQueueList(Room room)
{
this.room = room;
ShowItemOwners = true;
}
protected override FillFlowContainer<RearrangeableListItem<PlaylistItem>> CreateListFillFlowContainer() => new QueueFillFlowContainer
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
{
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>>
{
[Resolved(typeof(Room), nameof(Room.Playlist))]
private BindableList<PlaylistItem> roomPlaylist { get; set; }
protected override void LoadComplete()
{
base.LoadComplete();
roomPlaylist.BindCollectionChanged((_, _) => InvalidateLayout());
}
public new void InvalidateLayout() => base.InvalidateLayout();
public override IEnumerable<Drawable> FlowingChildren => base.FlowingChildren.OfType<RearrangeableListItem<PlaylistItem>>().OrderBy(item => item.Model.PlaylistOrder);
}
@ -50,10 +70,10 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match.Playlist
private partial class QueuePlaylistItem : DrawableRoomPlaylistItem
{
[Resolved]
private IAPIProvider api { get; set; }
private IAPIProvider api { get; set; } = null!;
[Resolved]
private MultiplayerClient multiplayerClient { get; set; }
private MultiplayerClient multiplayerClient { get; set; } = null!;
public QueuePlaylistItem(PlaylistItem item)
: base(item)
@ -91,7 +111,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match.Playlist
{
base.Dispose(isDisposing);
if (multiplayerClient != null)
if (multiplayerClient.IsNotNull())
multiplayerClient.RoomUpdated -= onRoomUpdated;
}
}

View File

@ -24,6 +24,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
[Resolved]
private OngoingOperationTracker operationTracker { get; set; } = null!;
private readonly Room room;
private readonly IBindable<bool> operationInProgress = new Bindable<bool>();
private readonly PlaylistItem? itemToEdit;
@ -38,6 +39,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
public MultiplayerMatchSongSelect(Room room, PlaylistItem? itemToEdit = null)
: base(room, itemToEdit)
{
this.room = room;
this.itemToEdit = itemToEdit;
}
@ -111,8 +113,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
}
else
{
Playlist.Clear();
Playlist.Add(item);
room.Playlist = [item];
this.Exit();
}

View File

@ -138,7 +138,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
null,
new Drawable[]
{
new MultiplayerPlaylist
new MultiplayerPlaylist(Room)
{
RelativeSizeAxes = Axes.Both,
RequestEdit = OpenSongSelection,

View File

@ -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 osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics.Containers;
using osu.Game.Online.Rooms;
@ -11,9 +9,5 @@ namespace osu.Game.Screens.OnlinePlay
/// <summary>
/// A <see cref="CompositeDrawable"/> that exposes bindables for <see cref="Room"/> properties.
/// </summary>
public partial class OnlinePlayComposite : CompositeDrawable
{
[Resolved(typeof(Room))]
protected BindableList<PlaylistItem> Playlist { get; private set; } = null!;
}
public partial class OnlinePlayComposite : CompositeDrawable;
}

View File

@ -32,9 +32,6 @@ namespace osu.Game.Screens.OnlinePlay
public override bool AllowEditing => false;
[Resolved(typeof(Room), nameof(Room.Playlist))]
protected BindableList<PlaylistItem> Playlist { get; private set; } = null!;
[Resolved]
private RulesetStore rulesets { get; set; } = null!;

View File

@ -329,9 +329,6 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
localUser = api.LocalUser.GetBoundCopy();
localUser.BindValueChanged(populateDurations, true);
playlist.Items.BindTo(Playlist);
Playlist.BindCollectionChanged(onPlaylistChanged, true);
}
protected override void LoadComplete()
@ -345,6 +342,9 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
updateRoomMaxParticipants();
updateRoomDuration();
updateRoomMaxAttempts();
updateRoomPlaylist();
playlist.Items.BindCollectionChanged((_, __) => room.Playlist = playlist.Items.ToArray());
}
private void onRoomPropertyChanged(object? sender, PropertyChangedEventArgs e)
@ -370,6 +370,10 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
case nameof(Room.MaxAttempts):
updateRoomMaxAttempts();
break;
case nameof(Room.Playlist):
updateRoomPlaylist();
break;
}
}
@ -388,6 +392,9 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
private void updateRoomMaxAttempts()
=> MaxAttemptsField.Text = room.MaxAttempts?.ToString();
private void updateRoomPlaylist()
=> playlist.Items.ReplaceRange(0, playlist.Items.Count, room.Playlist);
private void populateDurations(ValueChangedEvent<APIUser> user)
{
// roughly correct (see https://github.com/Humanizr/Humanizer/blob/18167e56c082449cc4fe805b8429e3127a7b7f93/readme.md?plain=1#L427)
@ -421,9 +428,9 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
public void SelectBeatmap() => editPlaylistButton.TriggerClick();
private void onPlaylistChanged(object? sender, NotifyCollectionChangedEventArgs e) =>
playlistLength.Text = $"Length: {Playlist.GetTotalDuration(rulesets)}";
playlistLength.Text = $"Length: {room.Playlist.GetTotalDuration(rulesets)}";
private bool hasValidSettings => room.RoomID == null && NameField.Text.Length > 0 && Playlist.Count > 0
private bool hasValidSettings => room.RoomID == null && NameField.Text.Length > 0 && room.Playlist.Count > 0
&& hasValidDuration;
private bool hasValidDuration => DurationField.Current.Value <= TimeSpan.FromDays(14) || localUser.Value.IsSupporter;
@ -464,7 +471,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
.Select(int.Parse)
.ToArray();
foreach (var item in Playlist)
foreach (var item in room.Playlist)
{
if (invalidBeatmapIDs.Contains(item.Beatmap.OnlineID))
item.MarkInvalid();

View File

@ -38,6 +38,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
private MatchLeaderboard leaderboard = null!;
private SelectionPollingComponent selectionPollingComponent = null!;
private FillFlowContainer progressSection = null!;
private DrawableRoomPlaylist drawablePlaylist = null!;
public PlaylistsRoomSubScreen(Room room)
: base(room, false) // Editing is temporarily not allowed.
@ -77,6 +78,10 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
case nameof(Room.MaxAttempts):
updateRoomMaxAttempts();
break;
case nameof(Room.Playlist):
updateRoomPlaylist();
break;
}
}
@ -93,6 +98,9 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
private void updateRoomMaxAttempts()
=> progressSection.Alpha = Room.MaxAttempts != null ? 1 : 0;
private void updateRoomPlaylist()
=> drawablePlaylist.Items.ReplaceRange(0, drawablePlaylist.Items.Count, Room.Playlist);
protected override Drawable CreateMainContent() => new Container
{
RelativeSizeAxes = Axes.Both,
@ -122,13 +130,12 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
Padding = new MarginPadding { Right = 5 },
Content = new[]
{
new Drawable[] { new OverlinedPlaylistHeader(), },
new Drawable[] { new OverlinedPlaylistHeader(Room), },
new Drawable[]
{
new DrawableRoomPlaylist
drawablePlaylist = new DrawableRoomPlaylist
{
RelativeSizeAxes = Axes.Both,
Items = { BindTarget = Room.Playlist },
SelectedItem = { BindTarget = SelectedItem },
AllowSelection = true,
AllowShowingResults = true,

View File

@ -12,45 +12,34 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
{
public partial class PlaylistsSongSelect : OnlinePlaySongSelect
{
private readonly Room room;
public PlaylistsSongSelect(Room room)
: base(room)
{
this.room = room;
}
protected override BeatmapDetailArea CreateBeatmapDetailArea() => new MatchBeatmapDetailArea
protected override BeatmapDetailArea CreateBeatmapDetailArea() => new MatchBeatmapDetailArea(room)
{
CreateNewItem = createNewItem
CreateNewItem = () => room.Playlist = room.Playlist.Append(createNewItem()).ToArray()
};
protected override bool SelectItem(PlaylistItem item)
{
switch (Playlist.Count)
{
case 0:
createNewItem();
break;
case 1:
Playlist.Clear();
createNewItem();
break;
}
if (room.Playlist.Count <= 1)
room.Playlist = [createNewItem()];
this.Exit();
return true;
}
private void createNewItem()
private PlaylistItem createNewItem() => new PlaylistItem(Beatmap.Value.BeatmapInfo)
{
PlaylistItem item = new PlaylistItem(Beatmap.Value.BeatmapInfo)
{
ID = Playlist.Count == 0 ? 0 : Playlist.Max(p => p.ID) + 1,
RulesetID = Ruleset.Value.OnlineID,
RequiredMods = Mods.Value.Select(m => new APIMod(m)).ToArray(),
AllowedMods = FreeMods.Value.Select(m => new APIMod(m)).ToArray()
};
Playlist.Add(item);
}
ID = room.Playlist.Count == 0 ? 0 : room.Playlist.Max(p => p.ID) + 1,
RulesetID = Ruleset.Value.OnlineID,
RequiredMods = Mods.Value.Select(m => new APIMod(m)).ToArray(),
AllowedMods = FreeMods.Value.Select(m => new APIMod(m)).ToArray()
};
}
}

View File

@ -38,12 +38,12 @@ namespace osu.Game.Tests.Visual.Multiplayer
Name = "test name",
Type = MatchType.HeadToHead,
Playlist =
{
[
new PlaylistItem(new TestBeatmap(Ruleset.Value).BeatmapInfo)
{
RulesetID = Ruleset.Value.OnlineID
}
}
]
};
}

View File

@ -447,7 +447,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
item.PlaylistOrder = existingItem.PlaylistOrder;
ServerRoom.Playlist[ServerRoom.Playlist.IndexOf(existingItem)] = item;
ServerAPIRoom.Playlist[ServerAPIRoom.Playlist.IndexOf(ServerAPIRoom.Playlist.Single(i => i.ID == item.ID))] = new PlaylistItem(item);
ServerAPIRoom.Playlist = ServerAPIRoom.Playlist.Select((pi, i) => pi.ID == item.ID ? new PlaylistItem(item) : ServerAPIRoom.Playlist[i]).ToArray();
await ((IMultiplayerClient)this).PlaylistItemChanged(clone(item)).ConfigureAwait(false);
}
@ -474,7 +474,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
throw new InvalidOperationException("Attempted to remove an item which has already been played.");
ServerRoom.Playlist.Remove(item);
ServerAPIRoom.Playlist.RemoveAll(i => i.ID == item.ID);
ServerAPIRoom.Playlist = ServerAPIRoom.Playlist.Where(i => i.ID != item.ID).ToArray();
await ((IMultiplayerClient)this).PlaylistItemRemoved(clone(playlistItemId)).ConfigureAwait(false);
await updateCurrentItem(ServerRoom).ConfigureAwait(false);
@ -569,7 +569,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
item.ID = ++lastPlaylistItemId;
ServerRoom.Playlist.Add(item);
ServerAPIRoom.Playlist.Add(new PlaylistItem(item));
ServerAPIRoom.Playlist = ServerAPIRoom.Playlist.Append(new PlaylistItem(item)).ToArray();
await ((IMultiplayerClient)this).PlaylistItemAdded(clone(item)).ConfigureAwait(false);
await updatePlaylistOrder(ServerRoom).ConfigureAwait(false);

View File

@ -48,10 +48,13 @@ namespace osu.Game.Tests.Visual.OnlinePlay
RulesetIDs = new[] { ruleset.OnlineID },
};
room.Playlist.Add(new PlaylistItem(new BeatmapInfo { Metadata = new BeatmapMetadata() })
{
RulesetID = ruleset.OnlineID,
});
room.Playlist =
[
new PlaylistItem(new BeatmapInfo { Metadata = new BeatmapMetadata() })
{
RulesetID = ruleset.OnlineID,
}
];
}
CreateRoom(room);

View File

@ -290,19 +290,17 @@ namespace osu.Game.Tests.Visual.OnlinePlay
var result = JsonConvert.DeserializeObject<Room>(JsonConvert.SerializeObject(source));
Debug.Assert(result != null);
// Playlist item IDs and beatmaps aren't serialised.
if (source.CurrentPlaylistItem != null)
{
Debug.Assert(result.CurrentPlaylistItem != null);
result.CurrentPlaylistItem = result.CurrentPlaylistItem.With(new Optional<IBeatmapInfo>(source.CurrentPlaylistItem.Beatmap));
result.CurrentPlaylistItem.ID = source.CurrentPlaylistItem.ID;
}
// When serialising, only beatmap IDs are sent to the server.
// When deserialising, full beatmaps and IDs are expected to arrive.
for (int i = 0; i < source.Playlist.Count; i++)
{
result.Playlist[i] = result.Playlist[i].With(new Optional<IBeatmapInfo>(source.Playlist[i].Beatmap));
result.Playlist[i].ID = source.Playlist[i].ID;
}
PlaylistItem? finalCurrentItem = result.CurrentPlaylistItem?.With(id: source.CurrentPlaylistItem!.ID, beatmap: new Optional<IBeatmapInfo>(source.CurrentPlaylistItem.Beatmap));
PlaylistItem[] finalPlaylist = result.Playlist.Select((pi, i) => pi.With(id: source.Playlist[i].ID, beatmap: new Optional<IBeatmapInfo>(source.Playlist[i].Beatmap))).ToArray();
// When setting the properties, we do a clear-then-add, otherwise equality comparers (that only compare by ID) pass early and members don't get replaced.
result.CurrentPlaylistItem = null;
result.CurrentPlaylistItem = finalCurrentItem;
result.Playlist = [];
result.Playlist = finalPlaylist;
return result;
}