1
0
mirror of https://github.com/ppy/osu.git synced 2025-02-16 01:42:54 +08:00

Merge pull request #15801 from smoogipoo/playlist-item-add-owner

Add owner avatar to multiplayer playlist items
This commit is contained in:
Dean Herbert 2021-11-27 00:30:35 +09:00 committed by GitHub
commit d570054b8c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 121 additions and 28 deletions

View File

@ -13,6 +13,7 @@ using osu.Framework.Platform;
using osu.Framework.Testing;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Drawables;
using osu.Game.Database;
using osu.Game.Graphics.Containers;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.Rooms;
@ -22,6 +23,7 @@ using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Screens.OnlinePlay;
using osu.Game.Tests.Beatmaps;
using osu.Game.Users.Drawables;
using osuTK;
using osuTK.Input;
@ -34,6 +36,9 @@ namespace osu.Game.Tests.Visual.Multiplayer
private BeatmapManager manager;
private RulesetStore rulesets;
[Cached(typeof(UserLookupCache))]
private readonly TestUserLookupCache userLookupCache = new TestUserLookupCache();
[BackgroundDependencyLoader]
private void load(GameHost host, AudioManager audio)
{
@ -304,6 +309,15 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddUntilStep("wait for items to load", () => playlist.ItemMap.Values.All(i => i.IsLoaded));
}
[TestCase(false)]
[TestCase(true)]
public void TestWithOwner(bool withOwner)
{
createPlaylist(false, false, withOwner);
AddAssert("owner visible", () => playlist.ChildrenOfType<UpdateableAvatar>().All(a => a.IsPresent == withOwner));
}
private void moveToItem(int index, Vector2? offset = null)
=> AddStep($"move mouse to item {index}", () => InputManager.MoveMouseTo(playlist.ChildrenOfType<DifficultyIcon>().ElementAt(index), offset));
@ -327,11 +341,11 @@ namespace osu.Game.Tests.Visual.Multiplayer
=> AddAssert($"delete button {index} {(visible ? "is" : "is not")} visible",
() => (playlist.ChildrenOfType<DrawableRoomPlaylistItem.PlaylistRemoveButton>().ElementAt(2 + index * 2).Alpha > 0) == visible);
private void createPlaylist(bool allowEdit, bool allowSelection)
private void createPlaylist(bool allowEdit, bool allowSelection, bool showItemOwner = false)
{
AddStep("create playlist", () =>
{
Child = playlist = new TestPlaylist(allowEdit, allowSelection)
Child = playlist = new TestPlaylist(allowEdit, allowSelection, showItemOwner)
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
@ -343,6 +357,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
playlist.Items.Add(new PlaylistItem
{
ID = i,
OwnerID = 2,
Beatmap =
{
Value = i % 2 == 1
@ -390,6 +405,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
playlist.Items.Add(new PlaylistItem
{
ID = index++,
OwnerID = 2,
Beatmap = { Value = b },
Ruleset = { Value = new OsuRuleset().RulesetInfo },
RequiredMods =
@ -409,8 +425,8 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
public new IReadOnlyDictionary<PlaylistItem, RearrangeableListItem<PlaylistItem>> ItemMap => base.ItemMap;
public TestPlaylist(bool allowEdit, bool allowSelection)
: base(allowEdit, allowSelection)
public TestPlaylist(bool allowEdit, bool allowSelection, bool showItemOwner = false)
: base(allowEdit, allowSelection, showItemOwner: showItemOwner)
{
}
}

View File

@ -253,7 +253,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
Ruleset = { Value = new OsuRuleset().RulesetInfo },
}
}
});
}, API.LocalUser.Value);
});
AddStep("refresh rooms", () => this.ChildrenOfType<LoungeSubScreen>().Single().UpdateFilter());
@ -283,7 +283,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
Ruleset = { Value = new OsuRuleset().RulesetInfo },
}
}
});
}, API.LocalUser.Value);
});
AddStep("refresh rooms", () => this.ChildrenOfType<LoungeSubScreen>().Single().UpdateFilter());
@ -336,7 +336,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
Ruleset = { Value = new OsuRuleset().RulesetInfo },
}
}
});
}, API.LocalUser.Value);
});
AddStep("refresh rooms", () => this.ChildrenOfType<LoungeSubScreen>().Single().UpdateFilter());
@ -597,7 +597,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
Ruleset = { Value = new OsuRuleset().RulesetInfo },
}
}
});
}, API.LocalUser.Value);
});
AddStep("refresh rooms", () => this.ChildrenOfType<LoungeSubScreen>().Single().UpdateFilter());

View File

@ -718,6 +718,7 @@ namespace osu.Game.Online.Multiplayer
var playlistItem = new PlaylistItem
{
ID = item.ID,
OwnerID = item.OwnerID,
Beatmap = { Value = beatmap },
Ruleset = { Value = ruleset },
Expired = item.Expired

View File

@ -18,6 +18,9 @@ namespace osu.Game.Online.Rooms
[JsonProperty("id")]
public long ID { get; set; }
[JsonProperty("owner_id")]
public int OwnerID { get; set; }
[JsonProperty("beatmap_id")]
public int BeatmapID { get; set; }

View File

@ -20,11 +20,13 @@ namespace osu.Game.Screens.OnlinePlay
private readonly bool allowEdit;
private readonly bool allowSelection;
private readonly bool showItemOwner;
public DrawableRoomPlaylist(bool allowEdit, bool allowSelection, bool reverse = false)
public DrawableRoomPlaylist(bool allowEdit, bool allowSelection, bool reverse = false, bool showItemOwner = false)
{
this.allowEdit = allowEdit;
this.allowSelection = allowSelection;
this.showItemOwner = showItemOwner;
((ReversibleFillFlowContainer)ListContainer).Reverse = reverse;
}
@ -56,7 +58,7 @@ namespace osu.Game.Screens.OnlinePlay
Spacing = new Vector2(0, 2)
};
protected override OsuRearrangeableListItem<PlaylistItem> CreateOsuDrawable(PlaylistItem item) => new DrawableRoomPlaylistItem(item, allowEdit, allowSelection)
protected override OsuRearrangeableListItem<PlaylistItem> CreateOsuDrawable(PlaylistItem item) => new DrawableRoomPlaylistItem(item, allowEdit, allowSelection, showItemOwner)
{
SelectedItem = { BindTarget = SelectedItem },
RequestDeletion = requestDeletion

View File

@ -4,17 +4,21 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Input.Events;
using osu.Framework.Localisation;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Drawables;
using osu.Game.Database;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.UserInterface;
@ -26,6 +30,7 @@ using osu.Game.Overlays.BeatmapSet;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods;
using osu.Game.Screens.Play.HUD;
using osu.Game.Users.Drawables;
using osuTK;
using osuTK.Graphics;
@ -34,6 +39,7 @@ namespace osu.Game.Screens.OnlinePlay
public class DrawableRoomPlaylistItem : OsuRearrangeableListItem<PlaylistItem>
{
public const float HEIGHT = 50;
public const float ICON_HEIGHT = 34;
public Action<PlaylistItem> RequestDeletion;
@ -45,6 +51,7 @@ namespace osu.Game.Screens.OnlinePlay
private LinkFlowContainer authorText;
private ExplicitContentBeatmapPill explicitContentPill;
private ModDisplay modDisplay;
private UpdateableAvatar ownerAvatar;
private readonly IBindable<bool> valid = new Bindable<bool>();
@ -54,12 +61,19 @@ namespace osu.Game.Screens.OnlinePlay
public readonly PlaylistItem Item;
[Resolved]
private OsuColour colours { get; set; }
[Resolved]
private UserLookupCache userLookupCache { get; set; }
private readonly bool allowEdit;
private readonly bool allowSelection;
private readonly bool showItemOwner;
protected override bool ShouldBeConsideredForInput(Drawable child) => allowEdit || !allowSelection || SelectedItem.Value == Model;
public DrawableRoomPlaylistItem(PlaylistItem item, bool allowEdit, bool allowSelection)
public DrawableRoomPlaylistItem(PlaylistItem item, bool allowEdit, bool allowSelection, bool showItemOwner)
: base(item)
{
Item = item;
@ -67,6 +81,7 @@ namespace osu.Game.Screens.OnlinePlay
// TODO: edit support should be moved out into a derived class
this.allowEdit = allowEdit;
this.allowSelection = allowSelection;
this.showItemOwner = showItemOwner;
beatmap.BindTo(item.Beatmap);
valid.BindTo(item.Valid);
@ -79,9 +94,6 @@ namespace osu.Game.Screens.OnlinePlay
Colour = OsuColour.Gray(0.5f);
}
[Resolved]
private OsuColour colours { get; set; }
[BackgroundDependencyLoader]
private void load()
{
@ -132,7 +144,14 @@ namespace osu.Game.Screens.OnlinePlay
maskingContainer.BorderColour = colours.Red;
}
difficultyIconContainer.Child = new DifficultyIcon(Item.Beatmap.Value, ruleset.Value, requiredMods, performBackgroundDifficultyLookup: false) { Size = new Vector2(32) };
if (showItemOwner)
{
ownerAvatar.Show();
userLookupCache.GetUserAsync(Item.OwnerID)
.ContinueWith(u => Schedule(() => ownerAvatar.User = u.Result), TaskContinuationOptions.OnlyOnRanToCompletion);
}
difficultyIconContainer.Child = new DifficultyIcon(Item.Beatmap.Value, ruleset.Value, requiredMods, performBackgroundDifficultyLookup: false) { Size = new Vector2(ICON_HEIGHT) };
panelBackground.Beatmap.Value = Item.Beatmap.Value;
@ -186,6 +205,7 @@ namespace osu.Game.Screens.OnlinePlay
new Dimension(GridSizeMode.AutoSize),
new Dimension(),
new Dimension(GridSizeMode.AutoSize),
new Dimension(GridSizeMode.AutoSize)
},
Content = new[]
{
@ -196,7 +216,7 @@ namespace osu.Game.Screens.OnlinePlay
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
AutoSizeAxes = Axes.Both,
Margin = new MarginPadding { Left = 8, Right = 8, },
Margin = new MarginPadding { Left = 8, Right = 8 },
},
new FillFlowContainer
{
@ -259,7 +279,7 @@ namespace osu.Game.Screens.OnlinePlay
Anchor = Anchor.CentreRight,
Origin = Anchor.CentreRight,
Direction = FillDirection.Horizontal,
Margin = new MarginPadding { Left = 8, Right = 10, },
Margin = new MarginPadding { Horizontal = 8 },
AutoSizeAxes = Axes.Both,
Spacing = new Vector2(5),
ChildrenEnumerable = CreateButtons().Select(button => button.With(b =>
@ -267,7 +287,17 @@ namespace osu.Game.Screens.OnlinePlay
b.Anchor = Anchor.Centre;
b.Origin = Anchor.Centre;
}))
}
},
ownerAvatar = new OwnerAvatar
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Size = new Vector2(ICON_HEIGHT),
Margin = new MarginPadding { Right = 8 },
Masking = true,
CornerRadius = 4,
Alpha = showItemOwner ? 1 : 0
},
}
}
},
@ -417,5 +447,31 @@ namespace osu.Game.Screens.OnlinePlay
Beatmap.BindValueChanged(beatmap => backgroundSprite.Beatmap.Value = beatmap.NewValue);
}
}
private class OwnerAvatar : UpdateableAvatar, IHasTooltip
{
public OwnerAvatar()
{
AddInternal(new TooltipArea(this)
{
RelativeSizeAxes = Axes.Both,
Depth = -1
});
}
public LocalisableString TooltipText => User == null ? string.Empty : $"queued by {User.Username}";
private class TooltipArea : Component, IHasTooltip
{
private readonly OwnerAvatar avatar;
public TooltipArea(OwnerAvatar avatar)
{
this.avatar = avatar;
}
public LocalisableString TooltipText => avatar.TooltipText;
}
}
}
}

View File

@ -19,13 +19,16 @@ namespace osu.Game.Screens.OnlinePlay
{
public Action<PlaylistItem> RequestShowResults;
public DrawableRoomPlaylistWithResults()
: base(false, true)
private readonly bool showItemOwner;
public DrawableRoomPlaylistWithResults(bool showItemOwner = false)
: base(false, true, showItemOwner: showItemOwner)
{
this.showItemOwner = showItemOwner;
}
protected override OsuRearrangeableListItem<PlaylistItem> CreateOsuDrawable(PlaylistItem item) =>
new DrawableRoomPlaylistItemWithResults(item, false, true)
new DrawableRoomPlaylistItemWithResults(item, false, true, showItemOwner)
{
RequestShowResults = () => RequestShowResults(item),
SelectedItem = { BindTarget = SelectedItem },
@ -35,8 +38,8 @@ namespace osu.Game.Screens.OnlinePlay
{
public Action RequestShowResults;
public DrawableRoomPlaylistItemWithResults(PlaylistItem item, bool allowEdit, bool allowSelection)
: base(item, allowEdit, allowSelection)
public DrawableRoomPlaylistItemWithResults(PlaylistItem item, bool allowEdit, bool allowSelection, bool showItemOwner)
: base(item, allowEdit, allowSelection, showItemOwner)
{
}

View File

@ -153,7 +153,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
null,
new Drawable[]
{
playlist = new DrawableRoomPlaylist(false, false, true)
playlist = new DrawableRoomPlaylist(false, false, true, true)
{
RelativeSizeAxes = Axes.Both,
},

View File

@ -299,7 +299,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
return ((IMultiplayerClient)this).LoadRequested();
}
public override async Task AddPlaylistItem(MultiplayerPlaylistItem item)
public async Task AddUserPlaylistItem(int userId, MultiplayerPlaylistItem item)
{
Debug.Assert(Room != null);
Debug.Assert(APIRoom != null);
@ -313,6 +313,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
case QueueMode.HostOnly:
// In host-only mode, the current item is re-used.
item.ID = currentItem.ID;
item.OwnerID = currentItem.OwnerID;
serverSidePlaylist[currentIndex] = item;
await ((IMultiplayerClient)this).PlaylistItemChanged(item).ConfigureAwait(false);
@ -323,6 +324,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
default:
item.ID = serverSidePlaylist.Last().ID + 1;
item.OwnerID = userId;
serverSidePlaylist.Add(item);
await ((IMultiplayerClient)this).PlaylistItemAdded(item).ConfigureAwait(false);
@ -332,6 +334,8 @@ namespace osu.Game.Tests.Visual.Multiplayer
}
}
public override Task AddPlaylistItem(MultiplayerPlaylistItem item) => AddUserPlaylistItem(api.LocalUser.Value.OnlineID, item);
protected override Task<APIBeatmapSet> GetOnlineBeatmapSet(int beatmapId, CancellationToken cancellationToken = default)
{
IBeatmapSetInfo? set = roomManager.ServerSideRooms.SelectMany(r => r.Playlist)

View File

@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.Rooms;
using osu.Game.Screens.OnlinePlay.Components;
using osu.Game.Screens.OnlinePlay.Multiplayer;
@ -55,6 +56,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
/// Adds a room to a local "server-side" list that's returned when a <see cref="GetRoomsRequest"/> is fired.
/// </summary>
/// <param name="room">The room.</param>
public void AddServerSideRoom(Room room) => requestsHandler.AddServerSideRoom(room);
/// <param name="host">The host.</param>
public void AddServerSideRoom(Room room, APIUser host) => requestsHandler.AddServerSideRoom(room, host);
}
}

View File

@ -50,7 +50,7 @@ namespace osu.Game.Tests.Visual.OnlinePlay
apiRoom.HasPassword.Value = !string.IsNullOrEmpty(createRoomRequest.Room.Password.Value);
apiRoom.Password.Value = createRoomRequest.Room.Password.Value;
AddServerSideRoom(apiRoom);
AddServerSideRoom(apiRoom, localUser);
var responseRoom = new APICreatedRoom();
responseRoom.CopyFrom(createResponseRoom(apiRoom, false));
@ -125,11 +125,17 @@ namespace osu.Game.Tests.Visual.OnlinePlay
/// Adds a room to a local "server-side" list that's returned when a <see cref="GetRoomsRequest"/> is fired.
/// </summary>
/// <param name="room">The room.</param>
public void AddServerSideRoom(Room room)
/// <param name="host">The room host.</param>
public void AddServerSideRoom(Room room, APIUser host)
{
room.RoomID.Value ??= currentRoomId++;
room.Host.Value = host;
for (int i = 0; i < room.Playlist.Count; i++)
{
room.Playlist[i].ID = currentPlaylistItemId++;
room.Playlist[i].OwnerID = room.Host.Value.OnlineID;
}
serverSideRooms.Add(room);
}