1
0
mirror of https://github.com/ppy/osu.git synced 2025-02-06 21:02:59 +08:00

Merge pull request #30838 from smoogipoo/better-room-status

Improve multiplayer room status handling
This commit is contained in:
Bartłomiej Dach 2024-12-12 13:05:59 +09:00 committed by GitHub
commit 88241d5b95
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 124 additions and 267 deletions

View File

@ -14,7 +14,6 @@ using osu.Game.Graphics.Sprites;
using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.Multiplayer; using osu.Game.Online.Multiplayer;
using osu.Game.Online.Rooms; using osu.Game.Online.Rooms;
using osu.Game.Online.Rooms.RoomStatuses;
using osu.Game.Overlays; using osu.Game.Overlays;
using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu;
using osu.Game.Screens.OnlinePlay.Lounge; using osu.Game.Screens.OnlinePlay.Lounge;
@ -76,7 +75,6 @@ namespace osu.Game.Tests.Visual.Multiplayer
createLoungeRoom(new Room createLoungeRoom(new Room
{ {
Name = "Multiplayer room", Name = "Multiplayer room",
Status = new RoomStatusOpen(),
EndDate = DateTimeOffset.Now.AddDays(1), EndDate = DateTimeOffset.Now.AddDays(1),
Type = MatchType.HeadToHead, Type = MatchType.HeadToHead,
Playlist = [item1], Playlist = [item1],
@ -85,7 +83,6 @@ namespace osu.Game.Tests.Visual.Multiplayer
createLoungeRoom(new Room createLoungeRoom(new Room
{ {
Name = "Private room", Name = "Private room",
Status = new RoomStatusOpenPrivate(),
Password = "*", Password = "*",
EndDate = DateTimeOffset.Now.AddDays(1), EndDate = DateTimeOffset.Now.AddDays(1),
Type = MatchType.HeadToHead, Type = MatchType.HeadToHead,
@ -95,36 +92,38 @@ namespace osu.Game.Tests.Visual.Multiplayer
createLoungeRoom(new Room createLoungeRoom(new Room
{ {
Name = "Playlist room with multiple beatmaps", Name = "Playlist room with multiple beatmaps",
Status = new RoomStatusPlaying(), Status = RoomStatus.Playing,
EndDate = DateTimeOffset.Now.AddDays(1), EndDate = DateTimeOffset.Now.AddDays(1),
Playlist = [item1, item2], Playlist = [item1, item2],
CurrentPlaylistItem = item1 CurrentPlaylistItem = item1
}), }),
createLoungeRoom(new Room createLoungeRoom(new Room
{ {
Name = "Finished room", Name = "Closing soon",
Status = new RoomStatusEnded(), EndDate = DateTimeOffset.Now.AddSeconds(5),
}),
createLoungeRoom(new Room
{
Name = "Closed room",
EndDate = DateTimeOffset.Now, EndDate = DateTimeOffset.Now,
}), }),
createLoungeRoom(new Room createLoungeRoom(new Room
{ {
Name = "Spotlight room", Name = "Spotlight room",
Status = new RoomStatusOpen(),
Category = RoomCategory.Spotlight, Category = RoomCategory.Spotlight,
}), }),
createLoungeRoom(new Room createLoungeRoom(new Room
{ {
Name = "Featured artist room", Name = "Featured artist room",
Status = new RoomStatusOpen(),
Category = RoomCategory.FeaturedArtist, Category = RoomCategory.FeaturedArtist,
}), }),
} }
}; };
}); });
AddUntilStep("wait for panel load", () => rooms.Count == 6); AddUntilStep("wait for panel load", () => rooms.Count == 7);
AddUntilStep("correct status text", () => rooms.ChildrenOfType<OsuSpriteText>().Count(s => s.Text.ToString().StartsWith("Currently playing", StringComparison.Ordinal)) == 2); AddUntilStep("correct status text", () => rooms.ChildrenOfType<OsuSpriteText>().Count(s => s.Text.ToString().StartsWith("Currently playing", StringComparison.Ordinal)) == 2);
AddUntilStep("correct status text", () => rooms.ChildrenOfType<OsuSpriteText>().Count(s => s.Text.ToString().StartsWith("Ready to play", StringComparison.Ordinal)) == 4); AddUntilStep("correct status text", () => rooms.ChildrenOfType<OsuSpriteText>().Count(s => s.Text.ToString().StartsWith("Ready to play", StringComparison.Ordinal)) == 5);
} }
[Test] [Test]
@ -136,7 +135,6 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddStep("create room", () => Child = drawableRoom = createLoungeRoom(room = new Room AddStep("create room", () => Child = drawableRoom = createLoungeRoom(room = new Room
{ {
Name = "Room with password", Name = "Room with password",
Status = new RoomStatusOpen(),
Type = MatchType.HeadToHead, Type = MatchType.HeadToHead,
})); }));

View File

@ -1,149 +0,0 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System;
using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Extensions;
using osu.Framework.Platform;
using osu.Framework.Screens;
using osu.Framework.Testing;
using osu.Game.Beatmaps;
using osu.Game.Graphics.UserInterface;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.Rooms;
using osu.Game.Online.Rooms.RoomStatuses;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Scoring;
using osu.Game.Screens.OnlinePlay.Playlists;
using osu.Game.Tests.Resources;
using osu.Game.Tests.Visual.OnlinePlay;
namespace osu.Game.Tests.Visual.Playlists
{
public partial class TestScenePlaylistsRoomSubScreen : OnlinePlayTestScene
{
private const double track_length = 10000;
[Resolved]
private IAPIProvider api { get; set; } = null!;
protected new TestRoomManager RoomManager => (TestRoomManager)base.RoomManager;
private BeatmapManager beatmaps = null!;
private RulesetStore rulesets = null!;
private BeatmapSetInfo? importedSet;
[BackgroundDependencyLoader]
private void load(GameHost host, AudioManager audio)
{
Dependencies.Cache(rulesets = new RealmRulesetStore(Realm));
Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, Realm, null, audio, Resources, host, Beatmap.Default));
Dependencies.Cache(new ScoreManager(rulesets, () => beatmaps, LocalStorage, Realm, API));
Dependencies.Cache(Realm);
beatmaps.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely();
Realm.Write(r =>
{
foreach (var set in r.All<BeatmapSetInfo>())
{
foreach (var b in set.Beatmaps)
{
// These will all have a virtual track length of 1000, see WorkingBeatmap.GetVirtualTrack().
b.Length = track_length - 1000;
}
}
});
importedSet = beatmaps.GetAllUsableBeatmapSets().First();
}
[Test]
public void TestStatusUpdateOnEnter()
{
Room room = null!;
PlaylistsRoomSubScreen roomScreen = null!;
AddStep("create room", () =>
{
RoomManager.AddRoom(room = new Room
{
Name = @"Test Room",
Host = new APIUser { Username = @"Host" },
Category = RoomCategory.Normal,
EndDate = DateTimeOffset.Now.AddMinutes(-1)
});
});
AddStep("push screen", () => LoadScreen(roomScreen = new PlaylistsRoomSubScreen(room)));
AddUntilStep("wait for screen load", () => roomScreen.IsCurrentScreen());
AddAssert("status is still ended", () => roomScreen.Room.Status, Is.TypeOf<RoomStatusEnded>);
}
[Test]
public void TestCloseButtonGoesAwayAfterGracePeriod()
{
Room room = null!;
PlaylistsRoomSubScreen roomScreen = null!;
AddStep("create room", () =>
{
RoomManager.AddRoom(room = new Room
{
Name = @"Test Room",
Host = api.LocalUser.Value,
Category = RoomCategory.Normal,
StartDate = DateTimeOffset.Now.AddMinutes(-5).AddSeconds(3),
EndDate = DateTimeOffset.Now.AddMinutes(30)
});
});
AddStep("push screen", () => LoadScreen(roomScreen = new PlaylistsRoomSubScreen(room)));
AddUntilStep("wait for screen load", () => roomScreen.IsCurrentScreen());
AddAssert("close button present", () => roomScreen.ChildrenOfType<DangerousRoundedButton>().Any());
AddUntilStep("wait for close button to disappear", () => !roomScreen.ChildrenOfType<DangerousRoundedButton>().Any());
}
[TestCase(120_000, true)] // Definitely enough time.
[TestCase(45_000, true)] // Enough time.
[TestCase(35_000, false)] // Not enough time to complete beatmap after lenience.
[TestCase(20_000, false)] // Not enough time.
[TestCase(5_000, false)] // Not enough time to complete beatmap before lenience.
[TestCase(37_500, true, 2)] // Enough time to complete beatmap after mods are applied.
public void TestReadyButtonEnablementPeriod(int offsetMs, bool enabled, double rate = 1)
{
Room room = null!;
PlaylistsRoomSubScreen roomScreen = null!;
AddStep("create room", () =>
{
RoomManager.AddRoom(room = new Room
{
Name = @"Test Room",
Host = api.LocalUser.Value,
Category = RoomCategory.Normal,
StartDate = DateTimeOffset.Now,
EndDate = DateTimeOffset.Now.AddMilliseconds(offsetMs),
Playlist =
[
new PlaylistItem(importedSet!.Beatmaps[0])
{
RequiredMods = rate == 1
? []
: [new APIMod(new OsuModDoubleTime { SpeedChange = { Value = rate } })]
}
]
});
});
AddStep("push screen", () => LoadScreen(roomScreen = new PlaylistsRoomSubScreen(room)));
AddUntilStep("wait for screen load", () => roomScreen.IsCurrentScreen());
AddUntilStep("ready button enabled", () => roomScreen.ChildrenOfType<PlaylistsReadyButton>().SingleOrDefault()?.Enabled.Value, () => Is.EqualTo(enabled));
}
}
}

View File

@ -195,6 +195,27 @@ namespace osu.Game.Graphics
} }
} }
/// <summary>
/// Retrieves the accent colour representing a <see cref="Room"/>'s current status.
/// </summary>
public Color4 ForRoomStatus(Room room)
{
if (room.HasEnded)
return YellowDarker;
switch (room.Status)
{
case RoomStatus.Playing:
return Purple;
default:
if (room.HasPassword)
return GreenDark;
return GreenLight;
}
}
/// <summary> /// <summary>
/// Retrieves colour for a <see cref="RankingTier"/>. /// Retrieves colour for a <see cref="RankingTier"/>.
/// See https://www.figma.com/file/YHWhp9wZ089YXgB7pe6L1k/Tier-Colours /// See https://www.figma.com/file/YHWhp9wZ089YXgB7pe6L1k/Tier-Colours

View File

@ -0,0 +1,34 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Localisation;
namespace osu.Game.Localisation
{
public static class RoomStatusPillStrings
{
private const string prefix = @"osu.Game.Resources.Localisation.RoomStatusPill";
/// <summary>
/// "Ended"
/// </summary>
public static LocalisableString Ended => new TranslatableString(getKey(@"ended"), @"Ended");
/// <summary>
/// "Playing"
/// </summary>
public static LocalisableString Playing => new TranslatableString(getKey(@"playing"), @"Playing");
/// <summary>
/// "Open (Private)"
/// </summary>
public static LocalisableString OpenPrivate => new TranslatableString(getKey(@"open_private"), @"Open (Private)");
/// <summary>
/// "Open"
/// </summary>
public static LocalisableString Open => new TranslatableString(getKey(@"open"), @"Open");
private static string getKey(string key) => $@"{prefix}:{key}";
}
}

View File

@ -18,7 +18,6 @@ using osu.Game.Online.API.Requests;
using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.Multiplayer.Countdown; using osu.Game.Online.Multiplayer.Countdown;
using osu.Game.Online.Rooms; using osu.Game.Online.Rooms;
using osu.Game.Online.Rooms.RoomStatuses;
using osu.Game.Overlays.Notifications; using osu.Game.Overlays.Notifications;
using osu.Game.Rulesets; using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
@ -395,15 +394,17 @@ namespace osu.Game.Online.Multiplayer
switch (state) switch (state)
{ {
case MultiplayerRoomState.Open: case MultiplayerRoomState.Open:
APIRoom.Status = APIRoom.HasPassword ? new RoomStatusOpenPrivate() : new RoomStatusOpen(); APIRoom.Status = RoomStatus.Idle;
break; break;
case MultiplayerRoomState.WaitingForLoad:
case MultiplayerRoomState.Playing: case MultiplayerRoomState.Playing:
APIRoom.Status = new RoomStatusPlaying(); APIRoom.Status = RoomStatus.Playing;
break; break;
case MultiplayerRoomState.Closed: case MultiplayerRoomState.Closed:
APIRoom.Status = new RoomStatusEnded(); APIRoom.EndDate = DateTimeOffset.Now;
APIRoom.Status = RoomStatus.Idle;
break; break;
} }
@ -821,7 +822,6 @@ namespace osu.Game.Online.Multiplayer
Room.Settings = settings; Room.Settings = settings;
APIRoom.Name = Room.Settings.Name; APIRoom.Name = Room.Settings.Name;
APIRoom.Password = Room.Settings.Password; APIRoom.Password = Room.Settings.Password;
APIRoom.Status = string.IsNullOrEmpty(Room.Settings.Password) ? new RoomStatusOpen() : new RoomStatusOpenPrivate();
APIRoom.Type = Room.Settings.MatchType; APIRoom.Type = Room.Settings.MatchType;
APIRoom.QueueMode = Room.Settings.QueueMode; APIRoom.QueueMode = Room.Settings.QueueMode;
APIRoom.AutoStartDuration = Room.Settings.AutoStartDuration; APIRoom.AutoStartDuration = Room.Settings.AutoStartDuration;

View File

@ -6,12 +6,10 @@ using System.Collections.Generic;
using System.ComponentModel; using System.ComponentModel;
using System.Linq; using System.Linq;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
using Newtonsoft.Json; using Newtonsoft.Json;
using osu.Game.IO.Serialization.Converters; using osu.Game.IO.Serialization.Converters;
using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.Multiplayer; using osu.Game.Online.Multiplayer;
using osu.Game.Online.Rooms.RoomStatuses;
namespace osu.Game.Online.Rooms namespace osu.Game.Online.Rooms
{ {
@ -248,7 +246,7 @@ namespace osu.Game.Online.Rooms
} }
/// <summary> /// <summary>
/// The current room status. /// The current status of the room.
/// </summary> /// </summary>
public RoomStatus Status public RoomStatus Status
{ {
@ -265,18 +263,6 @@ namespace osu.Game.Online.Rooms
set => SetField(ref availability, value); set => SetField(ref availability, value);
} }
[OnDeserialized]
private void onDeserialised(StreamingContext context)
{
// API doesn't populate status so let's do it here.
if (EndDate != null && DateTimeOffset.Now >= EndDate)
Status = new RoomStatusEnded();
else if (HasPassword)
Status = new RoomStatusOpenPrivate();
else
Status = new RoomStatusOpen();
}
[JsonProperty("id")] [JsonProperty("id")]
private long? roomId; private long? roomId;
@ -349,8 +335,9 @@ namespace osu.Game.Online.Rooms
[JsonProperty("channel_id")] [JsonProperty("channel_id")]
private int channelId; private int channelId;
// Not serialised (see: GetRoomsRequest). [JsonProperty("status")]
private RoomStatus status = new RoomStatusOpen(); [JsonConverter(typeof(SnakeCaseStringEnumConverter))]
private RoomStatus status;
// Not yet serialised (not implemented). // Not yet serialised (not implemented).
private RoomAvailability availability; private RoomAvailability availability;
@ -388,6 +375,15 @@ namespace osu.Game.Online.Rooms
RecentParticipants = other.RecentParticipants; RecentParticipants = other.RecentParticipants;
} }
/// <summary>
/// Whether the room is no longer available.
/// </summary>
/// <remarks>
/// This property does not update in real-time and needs to be queried periodically.
/// Subscribe to <see cref="EndDate"/> to be notified of any immediate changes.
/// </remarks>
public bool HasEnded => DateTimeOffset.Now >= EndDate;
[JsonObject(MemberSerialization.OptIn)] [JsonObject(MemberSerialization.OptIn)]
public class RoomPlaylistItemStats public class RoomPlaylistItemStats
{ {

View File

@ -1,19 +1,11 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
#nullable disable
using osu.Game.Graphics;
using osuTK.Graphics;
namespace osu.Game.Online.Rooms namespace osu.Game.Online.Rooms
{ {
public abstract class RoomStatus public enum RoomStatus
{ {
public abstract string Message { get; } Idle,
public abstract Color4 GetAppropriateColour(OsuColour colours); Playing,
public override int GetHashCode() => GetType().GetHashCode();
public override bool Equals(object obj) => GetType() == obj?.GetType();
} }
} }

View File

@ -1,14 +0,0 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Game.Graphics;
using osuTK.Graphics;
namespace osu.Game.Online.Rooms.RoomStatuses
{
public class RoomStatusEnded : RoomStatus
{
public override string Message => "Ended";
public override Color4 GetAppropriateColour(OsuColour colours) => colours.YellowDarker;
}
}

View File

@ -1,14 +0,0 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Game.Graphics;
using osuTK.Graphics;
namespace osu.Game.Online.Rooms.RoomStatuses
{
public class RoomStatusOpen : RoomStatus
{
public override string Message => "Open";
public override Color4 GetAppropriateColour(OsuColour colours) => colours.GreenLight;
}
}

View File

@ -1,14 +0,0 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Game.Graphics;
using osuTK.Graphics;
namespace osu.Game.Online.Rooms.RoomStatuses
{
public class RoomStatusOpenPrivate : RoomStatus
{
public override string Message => "Open (Private)";
public override Color4 GetAppropriateColour(OsuColour colours) => colours.GreenDark;
}
}

View File

@ -1,14 +0,0 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Game.Graphics;
using osuTK.Graphics;
namespace osu.Game.Online.Rooms.RoomStatuses
{
public class RoomStatusPlaying : RoomStatus
{
public override string Message => "Playing";
public override Color4 GetAppropriateColour(OsuColour colours) => colours.Purple;
}
}

View File

@ -29,18 +29,28 @@ namespace osu.Game.Screens.OnlinePlay.Components
base.LoadComplete(); base.LoadComplete();
room.PropertyChanged += onRoomPropertyChanged; room.PropertyChanged += onRoomPropertyChanged;
// Timed update required to track rooms which have hit the end time, see `HasEnded`.
Scheduler.AddDelayed(updateRoomStatus, 1000, true);
updateRoomStatus(); updateRoomStatus();
} }
private void onRoomPropertyChanged(object? sender, PropertyChangedEventArgs e) private void onRoomPropertyChanged(object? sender, PropertyChangedEventArgs e)
{ {
if (e.PropertyName == nameof(Room.Status)) switch (e.PropertyName)
updateRoomStatus(); {
case nameof(Room.Category):
case nameof(Room.Status):
case nameof(Room.EndDate):
case nameof(Room.HasPassword):
updateRoomStatus();
break;
}
} }
private void updateRoomStatus() private void updateRoomStatus()
{ {
this.FadeColour(colours.ForRoomCategory(room.Category) ?? room.Status.GetAppropriateColour(colours), transitionDuration); this.FadeColour(colours.ForRoomCategory(room.Category) ?? colours.ForRoomStatus(room), transitionDuration);
} }
protected override void Dispose(bool isDisposing) protected override void Dispose(bool isDisposing)

View File

@ -7,6 +7,7 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Online.Rooms; using osu.Game.Online.Rooms;
using osu.Game.Localisation;
namespace osu.Game.Screens.OnlinePlay.Lounge.Components namespace osu.Game.Screens.OnlinePlay.Lounge.Components
{ {
@ -35,8 +36,10 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
Pill.Background.Alpha = 1; Pill.Background.Alpha = 1;
room.PropertyChanged += onRoomPropertyChanged; room.PropertyChanged += onRoomPropertyChanged;
updateDisplay();
// Timed update required to track rooms which have hit the end time, see `HasEnded`.
Scheduler.AddDelayed(updateDisplay, 1000, true);
updateDisplay();
FinishTransforms(true); FinishTransforms(true);
} }
@ -46,6 +49,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
{ {
case nameof(Room.Status): case nameof(Room.Status):
case nameof(Room.EndDate): case nameof(Room.EndDate):
case nameof(Room.HasPassword):
updateDisplay(); updateDisplay();
break; break;
} }
@ -53,8 +57,23 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
private void updateDisplay() private void updateDisplay()
{ {
Pill.Background.FadeColour(room.Status.GetAppropriateColour(colours), 100); Pill.Background.FadeColour(colours.ForRoomStatus(room), 100);
TextFlow.Text = room.Status.Message;
if (room.HasEnded)
TextFlow.Text = RoomStatusPillStrings.Ended;
else
{
switch (room.Status)
{
case RoomStatus.Playing:
TextFlow.Text = RoomStatusPillStrings.Playing;
break;
default:
TextFlow.Text = room.HasPassword ? RoomStatusPillStrings.OpenPrivate : RoomStatusPillStrings.Open;
break;
}
}
} }
protected override void Dispose(bool isDisposing) protected override void Dispose(bool isDisposing)

View File

@ -26,7 +26,6 @@ using osu.Game.Input.Bindings;
using osu.Game.Online.API; using osu.Game.Online.API;
using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests;
using osu.Game.Online.Rooms; using osu.Game.Online.Rooms;
using osu.Game.Online.Rooms.RoomStatuses;
using osu.Game.Overlays; using osu.Game.Overlays;
using osu.Game.Screens.OnlinePlay.Components; using osu.Game.Screens.OnlinePlay.Components;
using osu.Game.Screens.OnlinePlay.Lounge.Components; using osu.Game.Screens.OnlinePlay.Lounge.Components;
@ -168,7 +167,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge
}) })
}; };
if (Room.Type == MatchType.Playlists && Room.Host?.Id == api.LocalUser.Value.Id && Room.StartDate?.AddMinutes(5) >= DateTimeOffset.Now && Room.Status is not RoomStatusEnded) if (Room.Type == MatchType.Playlists && Room.Host?.Id == api.LocalUser.Value.Id && Room.StartDate?.AddMinutes(5) >= DateTimeOffset.Now && !Room.HasEnded)
{ {
items.Add(new OsuMenuItem("Close playlist", MenuItemType.Destructive, () => items.Add(new OsuMenuItem("Close playlist", MenuItemType.Destructive, () =>
{ {

View File

@ -8,7 +8,6 @@ using osu.Framework.Extensions.ExceptionExtensions;
using osu.Framework.Logging; using osu.Framework.Logging;
using osu.Game.Online.Multiplayer; using osu.Game.Online.Multiplayer;
using osu.Game.Online.Rooms; using osu.Game.Online.Rooms;
using osu.Game.Online.Rooms.RoomStatuses;
using osu.Game.Screens.OnlinePlay.Components; using osu.Game.Screens.OnlinePlay.Components;
namespace osu.Game.Screens.OnlinePlay.Multiplayer namespace osu.Game.Screens.OnlinePlay.Multiplayer
@ -31,7 +30,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
// this is done here as a pre-check to avoid clicking on already closed rooms in the lounge from triggering a server join. // this is done here as a pre-check to avoid clicking on already closed rooms in the lounge from triggering a server join.
// should probably be done at a higher level, but due to the current structure of things this is the easiest place for now. // should probably be done at a higher level, but due to the current structure of things this is the easiest place for now.
if (room.Status is RoomStatusEnded) if (room.HasEnded)
{ {
onError?.Invoke("Cannot join an ended room."); onError?.Invoke("Cannot join an ended room.");
return; return;

View File

@ -9,7 +9,6 @@ using osu.Framework.Graphics.Containers;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
using osu.Game.Online.API; using osu.Game.Online.API;
using osu.Game.Online.Rooms; using osu.Game.Online.Rooms;
using osu.Game.Online.Rooms.RoomStatuses;
using osuTK; using osuTK;
namespace osu.Game.Screens.OnlinePlay.Playlists namespace osu.Game.Screens.OnlinePlay.Playlists
@ -99,7 +98,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
if (room.Host?.Id == api.LocalUser.Value.Id) if (room.Host?.Id == api.LocalUser.Value.Id)
{ {
if (deletionGracePeriodRemaining > TimeSpan.Zero && room.Status is not RoomStatusEnded) if (deletionGracePeriodRemaining > TimeSpan.Zero && !room.HasEnded)
{ {
closeButton.FadeIn(); closeButton.FadeIn();
using (BeginDelayedSequence(deletionGracePeriodRemaining.Value.TotalMilliseconds)) using (BeginDelayedSequence(deletionGracePeriodRemaining.Value.TotalMilliseconds))

View File

@ -16,7 +16,6 @@ using osu.Game.Input;
using osu.Game.Online.API; using osu.Game.Online.API;
using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests;
using osu.Game.Online.Rooms; using osu.Game.Online.Rooms;
using osu.Game.Online.Rooms.RoomStatuses;
using osu.Game.Screens.OnlinePlay.Components; using osu.Game.Screens.OnlinePlay.Components;
using osu.Game.Screens.OnlinePlay.Match; using osu.Game.Screens.OnlinePlay.Match;
using osu.Game.Screens.OnlinePlay.Match.Components; using osu.Game.Screens.OnlinePlay.Match.Components;
@ -286,11 +285,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
DialogOverlay?.Push(new ClosePlaylistDialog(Room, () => DialogOverlay?.Push(new ClosePlaylistDialog(Room, () =>
{ {
var request = new ClosePlaylistRequest(Room.RoomID!.Value); var request = new ClosePlaylistRequest(Room.RoomID!.Value);
request.Success += () => request.Success += () => Room.EndDate = DateTimeOffset.UtcNow;
{
Room.Status = new RoomStatusEnded();
Room.EndDate = DateTimeOffset.UtcNow;
};
API.Queue(request); API.Queue(request);
})); }));
} }