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:
commit
d570054b8c
@ -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)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
|
@ -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
|
||||
|
@ -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; }
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
},
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user