Merge branch 'master' into master

This commit is contained in:
Bartłomiej Dach
2021-11-09 08:40:52 +01:00
committed by GitHub
338 changed files with 3092 additions and 2187 deletions

View File

@ -11,8 +11,8 @@ using osu.Game.Beatmaps;
using osu.Game.Configuration;
using osu.Game.Graphics.Backgrounds;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Skinning;
using osu.Game.Users;
namespace osu.Game.Screens.Backgrounds
{
@ -22,7 +22,7 @@ namespace osu.Game.Screens.Backgrounds
private int currentDisplay;
private const int background_count = 7;
private IBindable<User> user;
private IBindable<APIUser> user;
private Bindable<Skin> skin;
private Bindable<BackgroundSource> mode;
private Bindable<IntroSequence> introSequence;

View File

@ -108,11 +108,20 @@ namespace osu.Game.Screens.Edit.Compose.Components
protected override bool OnMouseDown(MouseDownEvent e)
{
bool selectionPerformed = performMouseDownActions(e);
// even if a selection didn't occur, a drag event may still move the selection.
bool movementPossible = prepareSelectionMovement();
return selectionPerformed || (e.Button == MouseButton.Left && movementPossible);
// check if selection has occurred
if (selectionPerformed)
{
// only unmodified right click should show context menu
bool shouldShowContextMenu = e.Button == MouseButton.Right && !e.ShiftPressed && !e.AltPressed && !e.SuperPressed;
// stop propagation if not showing context menu
return !shouldShowContextMenu;
}
// even if a selection didn't occur, a drag event may still move the selection.
return e.Button == MouseButton.Left && movementPossible;
}
protected SelectionBlueprint<T> ClickedBlueprint { get; private set; }

View File

@ -46,7 +46,7 @@ namespace osu.Game.Screens.Edit.Setup
Empty(),
creatorTextBox = createTextBox<LabelledTextBox>("Creator", metadata.AuthorString),
creatorTextBox = createTextBox<LabelledTextBox>("Creator", metadata.Author.Username),
difficultyTextBox = createTextBox<LabelledTextBox>("Difficulty Name", Beatmap.BeatmapInfo.Version),
sourceTextBox = createTextBox<LabelledTextBox>("Source", metadata.Source),
tagsTextBox = createTextBox<LabelledTextBox>("Tags", metadata.Tags)

View File

@ -14,9 +14,9 @@ using osu.Framework.Utils;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests.Responses;
using osuTK;
using osuTK.Graphics;
using osu.Game.Users;
namespace osu.Game.Screens.Menu
{
@ -34,7 +34,7 @@ namespace osu.Game.Screens.Menu
private readonly OsuScreen nextScreen;
private readonly Bindable<User> currentUser = new Bindable<User>();
private readonly Bindable<APIUser> currentUser = new Bindable<APIUser>();
private FillFlowContainer fill;
private readonly List<ITextPart> expendableText = new List<ITextPart>();
@ -168,7 +168,7 @@ namespace osu.Game.Screens.Menu
if (nextScreen != null)
LoadComponentAsync(nextScreen);
((IBindable<User>)currentUser).BindTo(api.LocalUser);
((IBindable<APIUser>)currentUser).BindTo(api.LocalUser);
}
public override void OnEntering(IScreen last)

View File

@ -393,6 +393,7 @@ namespace osu.Game.Screens.Menu
public class OutlineTriangle : BufferedContainer
{
public OutlineTriangle(bool outlineOnly, float size)
: base(cachedFrameBuffer: true)
{
Size = new Vector2(size);
@ -414,7 +415,6 @@ namespace osu.Game.Screens.Menu
}
Blending = BlendingParameters.Additive;
CacheDrawnFrameBuffer = true;
}
}
}

View File

@ -4,15 +4,15 @@
using osuTK.Graphics;
using osu.Game.Skinning;
using osu.Game.Online.API;
using osu.Game.Users;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Game.Online.API.Requests.Responses;
namespace osu.Game.Screens.Menu
{
internal class MenuLogoVisualisation : LogoVisualisation
{
private IBindable<User> user;
private IBindable<APIUser> user;
private Bindable<Skin> skin;
[BackgroundDependencyLoader]

View File

@ -13,10 +13,10 @@ using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Skinning;
using osu.Game.Online.API;
using osu.Game.Users;
using System;
using osu.Framework.Audio.Track;
using osu.Framework.Bindables;
using osu.Game.Online.API.Requests.Responses;
namespace osu.Game.Screens.Menu
{
@ -35,7 +35,7 @@ namespace osu.Game.Screens.Menu
private const double box_fade_in_time = 65;
private const int box_width = 200;
private IBindable<User> user;
private IBindable<APIUser> user;
private Bindable<Skin> skin;
[Resolved]

View File

@ -8,6 +8,7 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Screens;
using osu.Game.Beatmaps;
using osu.Game.Online.Rooms;
using osuTK;
using osuTK.Graphics;
@ -61,7 +62,10 @@ namespace osu.Game.Screens.OnlinePlay.Components
{
var beatmap = playlistItem?.Beatmap.Value;
if (background?.BeatmapInfo?.BeatmapSet?.OnlineInfo?.Covers.Cover == beatmap?.BeatmapSet?.OnlineInfo?.Covers.Cover)
string? lastCover = (background?.Beatmap?.BeatmapSet as IBeatmapSetOnlineInfo)?.Covers.Cover;
string? newCover = (beatmap?.BeatmapSet as IBeatmapSetOnlineInfo)?.Covers.Cover;
if (lastCover == newCover)
return;
cancellationSource?.Cancel();

View File

@ -7,7 +7,7 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Threading;
using osu.Game.Users;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Users.Drawables;
using osuTK;
@ -92,7 +92,7 @@ namespace osu.Game.Screens.OnlinePlay.Components
private class UserTile : CompositeDrawable
{
public User User
public APIUser User
{
get => avatar.User;
set => avatar.User = value;

View File

@ -13,11 +13,11 @@ namespace osu.Game.Screens.OnlinePlay.Components
{
public class PlaylistItemBackground : Background
{
public readonly BeatmapInfo? BeatmapInfo;
public readonly IBeatmapInfo? Beatmap;
public PlaylistItemBackground(PlaylistItem? playlistItem)
{
BeatmapInfo = playlistItem?.Beatmap.Value;
Beatmap = playlistItem?.Beatmap.Value;
}
[BackgroundDependencyLoader]
@ -26,8 +26,8 @@ namespace osu.Game.Screens.OnlinePlay.Components
Texture? texture = null;
// prefer online cover where available.
if (BeatmapInfo?.BeatmapSet?.OnlineInfo?.Covers.Cover != null)
texture = textures.Get(BeatmapInfo.BeatmapSet.OnlineInfo.Covers.Cover);
if (Beatmap?.BeatmapSet is IBeatmapSetOnlineInfo online)
texture = textures.Get(online.Covers.Cover);
Sprite.Texture = texture ?? beatmaps.DefaultBeatmap.Background;
}
@ -38,7 +38,7 @@ namespace osu.Game.Screens.OnlinePlay.Components
if (ReferenceEquals(this, other)) return true;
return other.GetType() == GetType()
&& ((PlaylistItemBackground)other).BeatmapInfo == BeatmapInfo;
&& ((PlaylistItemBackground)other).Beatmap == Beatmap;
}
}
}

View File

@ -119,7 +119,7 @@ namespace osu.Game.Screens.OnlinePlay.Components
try
{
foreach (var pi in room.Playlist)
pi.MapObjects(beatmaps, rulesets);
pi.MapObjects(rulesets);
var existing = rooms.FirstOrDefault(e => e.RoomID.Value == room.RoomID.Value);
if (existing == null)

View File

@ -80,10 +80,10 @@ namespace osu.Game.Screens.OnlinePlay.Components
private void updateRange(object sender, NotifyCollectionChangedEventArgs e)
{
var orderedDifficulties = Playlist.Select(p => p.Beatmap.Value).OrderBy(b => b.StarDifficulty).ToArray();
var orderedDifficulties = Playlist.Select(p => p.Beatmap.Value).OrderBy(b => b.StarRating).ToArray();
StarDifficulty minDifficulty = new StarDifficulty(orderedDifficulties.Length > 0 ? orderedDifficulties[0].StarDifficulty : 0, 0);
StarDifficulty maxDifficulty = new StarDifficulty(orderedDifficulties.Length > 0 ? orderedDifficulties[^1].StarDifficulty : 0, 0);
StarDifficulty minDifficulty = new StarDifficulty(orderedDifficulties.Length > 0 ? orderedDifficulties[0].StarRating : 0, 0);
StarDifficulty maxDifficulty = new StarDifficulty(orderedDifficulties.Length > 0 ? orderedDifficulties[^1].StarRating : 0, 0);
minDisplay.Current.Value = minDifficulty;
maxDisplay.Current.Value = maxDifficulty;

View File

@ -45,7 +45,7 @@ namespace osu.Game.Screens.OnlinePlay
private ExplicitContentBeatmapPill explicitContentPill;
private ModDisplay modDisplay;
private readonly Bindable<BeatmapInfo> beatmap = new Bindable<BeatmapInfo>();
private readonly Bindable<IBeatmapInfo> beatmap = new Bindable<IBeatmapInfo>();
private readonly Bindable<RulesetInfo> ruleset = new Bindable<RulesetInfo>();
private readonly BindableList<Mod> requiredMods = new BindableList<Mod>();
@ -96,6 +96,7 @@ namespace osu.Game.Screens.OnlinePlay
}
private ScheduledDelegate scheduledRefresh;
private PanelBackground panelBackground;
private void scheduleRefresh()
{
@ -105,23 +106,25 @@ namespace osu.Game.Screens.OnlinePlay
private void refresh()
{
difficultyIconContainer.Child = new DifficultyIcon(beatmap.Value, ruleset.Value, requiredMods, performBackgroundDifficultyLookup: false) { Size = new Vector2(32) };
difficultyIconContainer.Child = new DifficultyIcon(Item.Beatmap.Value, ruleset.Value, requiredMods, performBackgroundDifficultyLookup: false) { Size = new Vector2(32) };
panelBackground.Beatmap.Value = Item.Beatmap.Value;
beatmapText.Clear();
beatmapText.AddLink(Item.Beatmap.Value.GetDisplayTitleRomanisable(), LinkAction.OpenBeatmap, Item.Beatmap.Value.OnlineBeatmapID.ToString(), null, text =>
beatmapText.AddLink(Item.Beatmap.Value.GetDisplayTitleRomanisable(), LinkAction.OpenBeatmap, Item.Beatmap.Value.OnlineID.ToString(), null, text =>
{
text.Truncate = true;
});
authorText.Clear();
if (Item.Beatmap?.Value?.Metadata?.Author != null)
if (!string.IsNullOrEmpty(Item.Beatmap.Value?.Metadata.Author.Username))
{
authorText.AddText("mapped by ");
authorText.AddUserLink(Item.Beatmap.Value?.Metadata.Author);
authorText.AddUserLink(Item.Beatmap.Value.Metadata.Author);
}
bool hasExplicitContent = Item.Beatmap.Value.BeatmapSet.OnlineInfo?.HasExplicitContent == true;
bool hasExplicitContent = (Item.Beatmap.Value.BeatmapSet as IBeatmapSetOnlineInfo)?.HasExplicitContent == true;
explicitContentPill.Alpha = hasExplicitContent ? 1 : 0;
modDisplay.Current.Value = requiredMods.ToArray();
@ -145,10 +148,9 @@ namespace osu.Game.Screens.OnlinePlay
Alpha = 0,
AlwaysPresent = true
},
new PanelBackground
panelBackground = new PanelBackground
{
RelativeSizeAxes = Axes.Both,
Beatmap = { BindTarget = beatmap }
},
new GridContainer
{
@ -181,8 +183,11 @@ namespace osu.Game.Screens.OnlinePlay
{
beatmapText = new LinkFlowContainer(fontParameters)
{
AutoSizeAxes = Axes.Y,
RelativeSizeAxes = Axes.X,
// workaround to ensure only the first line of text shows, emulating truncation (but without ellipsis at the end).
// TODO: remove when text/link flow can support truncation with ellipsis natively.
Height = OsuFont.DEFAULT_FONT_SIZE,
Masking = true
},
new FillFlowContainer
{
@ -334,7 +339,7 @@ namespace osu.Game.Screens.OnlinePlay
// For now, this is the same implementation as in PanelBackground, but supports a beatmap info rather than a working beatmap
private class PanelBackground : Container // todo: should be a buffered container (https://github.com/ppy/osu-framework/issues/3222)
{
public readonly Bindable<BeatmapInfo> Beatmap = new Bindable<BeatmapInfo>();
public readonly Bindable<IBeatmapInfo> Beatmap = new Bindable<IBeatmapInfo>();
public PanelBackground()
{

View File

@ -353,7 +353,10 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
})
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y
// workaround to ensure only the first line of text shows, emulating truncation (but without ellipsis at the end).
// TODO: remove when text/link flow can support truncation with ellipsis natively.
Height = 16,
Masking = true
}
}
}
@ -381,11 +384,10 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
statusText.Text = "Currently playing ";
beatmapText.AddLink(item.NewValue.Beatmap.Value.GetDisplayTitleRomanisable(),
LinkAction.OpenBeatmap,
item.NewValue.Beatmap.Value.OnlineBeatmapID.ToString(),
item.NewValue.Beatmap.Value.OnlineID.ToString(),
creationParameters: s =>
{
s.Truncate = true;
s.RelativeSizeAxes = Axes.X;
});
}
}

View File

@ -12,8 +12,8 @@ using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Overlays;
using osu.Game.Users;
using osu.Game.Users.Drawables;
using osuTK;
@ -195,12 +195,12 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
foreach (var added in e.NewItems.OfType<User>())
foreach (var added in e.NewItems.OfType<APIUser>())
addUser(added);
break;
case NotifyCollectionChangedAction.Remove:
foreach (var removed in e.OldItems.OfType<User>())
foreach (var removed in e.OldItems.OfType<APIUser>())
removeUser(removed);
break;
@ -222,13 +222,13 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
private int displayedCircles => avatarFlow.Count + (hiddenUsers.Count > 0 ? 1 : 0);
private void addUser(User user)
private void addUser(APIUser user)
{
if (displayedCircles < NumberOfCircles)
avatarFlow.Add(new CircularAvatar { User = user });
}
private void removeUser(User user)
private void removeUser(APIUser user)
{
avatarFlow.RemoveAll(a => a.User == user);
}
@ -256,7 +256,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
}
}
private void onHostChanged(ValueChangedEvent<User> host)
private void onHostChanged(ValueChangedEvent<APIUser> host)
{
hostAvatar.User = host.NewValue;
hostText.Clear();
@ -270,7 +270,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
private class CircularAvatar : CompositeDrawable
{
public User User
public APIUser User
{
get => avatar.User;
set => avatar.User = value;

View File

@ -8,10 +8,10 @@ using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Game.Beatmaps.Drawables;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.Rooms;
using osu.Game.Screens.OnlinePlay.Lounge.Components;
using osu.Game.Screens.OnlinePlay.Match.Components;
using osu.Game.Users;
using osuTK;
namespace osu.Game.Screens.OnlinePlay.Match
@ -24,7 +24,7 @@ namespace osu.Game.Screens.OnlinePlay.Match
[Resolved]
private IAPIProvider api { get; set; }
private readonly IBindable<User> host = new Bindable<User>();
private readonly IBindable<APIUser> host = new Bindable<APIUser>();
private readonly bool allowEdit;
[CanBeNull]

View File

@ -62,8 +62,6 @@ namespace osu.Game.Screens.OnlinePlay.Match
[Resolved(canBeNull: true)]
protected OnlinePlayScreen ParentScreen { get; private set; }
private IBindable<WeakReference<BeatmapSetInfo>> managerUpdated;
[Cached]
private OnlinePlayBeatmapAvailabilityTracker beatmapAvailabilityTracker { get; set; }
@ -246,8 +244,7 @@ namespace osu.Game.Screens.OnlinePlay.Match
SelectedItem.BindValueChanged(_ => Scheduler.AddOnce(selectedItemChanged));
managerUpdated = beatmapManager.ItemUpdated.GetBoundCopy();
managerUpdated.BindValueChanged(beatmapUpdated);
beatmapManager.ItemUpdated += beatmapUpdated;
UserMods.BindValueChanged(_ => Scheduler.AddOnce(UpdateMods));
}
@ -362,14 +359,14 @@ namespace osu.Game.Screens.OnlinePlay.Match
}
}
private void beatmapUpdated(ValueChangedEvent<WeakReference<BeatmapSetInfo>> weakSet) => Schedule(updateWorkingBeatmap);
private void beatmapUpdated(BeatmapSetInfo set) => Schedule(updateWorkingBeatmap);
private void updateWorkingBeatmap()
{
var beatmap = SelectedItem.Value?.Beatmap.Value;
// Retrieve the corresponding local beatmap, since we can't directly use the playlist's beatmap info
var localBeatmap = beatmap == null ? null : beatmapManager.QueryBeatmap(b => b.OnlineBeatmapID == beatmap.OnlineBeatmapID);
var localBeatmap = beatmap == null ? null : beatmapManager.QueryBeatmap(b => b.OnlineBeatmapID == beatmap.OnlineID);
Beatmap.Value = beatmapManager.GetWorkingBeatmap(localBeatmap);
}
@ -431,6 +428,14 @@ namespace osu.Game.Screens.OnlinePlay.Match
/// <param name="room">The room to change the settings of.</param>
protected abstract RoomSettingsOverlay CreateRoomSettingsOverlay(Room room);
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
if (beatmapManager != null)
beatmapManager.ItemUpdated -= beatmapUpdated;
}
public class UserModSelectButton : PurpleTriangleButton
{
}

View File

@ -6,9 +6,9 @@ using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics.Containers;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.Rooms;
using osu.Game.Screens.OnlinePlay.Match;
using osu.Game.Users;
namespace osu.Game.Screens.OnlinePlay
{
@ -24,7 +24,7 @@ namespace osu.Game.Screens.OnlinePlay
protected Bindable<string> RoomName { get; private set; }
[Resolved(typeof(Room))]
protected Bindable<User> Host { get; private set; }
protected Bindable<APIUser> Host { get; private set; }
[Resolved(typeof(Room))]
protected Bindable<RoomStatus> Status { get; private set; }
@ -39,7 +39,7 @@ namespace osu.Game.Screens.OnlinePlay
protected Bindable<RoomCategory> Category { get; private set; }
[Resolved(typeof(Room))]
protected BindableList<User> RecentParticipants { get; private set; }
protected BindableList<APIUser> RecentParticipants { get; private set; }
[Resolved(typeof(Room))]
protected Bindable<int> ParticipantCount { get; private set; }

View File

@ -32,7 +32,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
private void load(IBindable<RulesetInfo> ruleset)
{
// Sanity checks to ensure that PlaylistsPlayer matches the settings for the current PlaylistItem
if (Beatmap.Value.BeatmapInfo.OnlineBeatmapID != PlaylistItem.Beatmap.Value.OnlineBeatmapID)
if (Beatmap.Value.BeatmapInfo.OnlineBeatmapID != PlaylistItem.Beatmap.Value.OnlineID)
throw new InvalidOperationException("Current Beatmap does not match PlaylistItem's Beatmap");
if (ruleset.Value.ID != PlaylistItem.Ruleset.Value.ID)

View File

@ -169,7 +169,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
/// <param name="pivot">An optional pivot around which the scores were retrieved.</param>
private void performSuccessCallback([NotNull] Action<IEnumerable<ScoreInfo>> callback, [NotNull] List<MultiplayerScore> scores, [CanBeNull] MultiplayerScores pivot = null)
{
var scoreInfos = scores.Select(s => s.CreateScoreInfo(playlistItem)).ToArray();
var scoreInfos = scores.Select(s => s.CreateScoreInfo(playlistItem, Beatmap.Value.BeatmapInfo)).ToArray();
// Score panels calculate total score before displaying, which can take some time. In order to count that calculation as part of the loading spinner display duration,
// calculate the total scores locally before invoking the success callback.

View File

@ -164,7 +164,7 @@ namespace osu.Game.Screens.Play
new Drawable[]
{
new MetadataLineLabel("Mapper"),
new MetadataLineInfo(metadata.AuthorString)
new MetadataLineInfo(metadata.Author.Username)
}
}
},

View File

@ -32,9 +32,9 @@ namespace osu.Game.Screens.Play.Break
}
public BlurredIcon()
: base(cachedFrameBuffer: true)
{
RelativePositionAxes = Axes.X;
CacheDrawnFrameBuffer = true;
Child = icon = new SpriteIcon
{
Origin = Anchor.Centre,

View File

@ -11,7 +11,7 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers;
using osu.Game.Graphics.Containers;
using osu.Game.Users;
using osu.Game.Online.API.Requests.Responses;
using osuTK;
using osuTK.Graphics;
@ -75,7 +75,7 @@ namespace osu.Game.Screens.Play.HUD
/// Whether the player should be tracked on the leaderboard.
/// Set to <c>true</c> for the local player or a player whose replay is currently being played.
/// </param>
public ILeaderboardScore Add([CanBeNull] User user, bool isTracked)
public ILeaderboardScore Add([CanBeNull] APIUser user, bool isTracked)
{
var drawable = CreateLeaderboardScoreDrawable(user, isTracked);
@ -106,7 +106,7 @@ namespace osu.Game.Screens.Play.HUD
scroll.ScrollToStart(false);
}
protected virtual GameplayLeaderboardScore CreateLeaderboardScoreDrawable(User user, bool isTracked) =>
protected virtual GameplayLeaderboardScore CreateLeaderboardScoreDrawable(APIUser user, bool isTracked) =>
new GameplayLeaderboardScore(user, isTracked);
protected override void Update()

View File

@ -10,7 +10,7 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Users;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Users.Drawables;
using osu.Game.Utils;
using osuTK;
@ -79,7 +79,7 @@ namespace osu.Game.Screens.Play.HUD
}
[CanBeNull]
public User User { get; }
public APIUser User { get; }
/// <summary>
/// Whether this score is the local user or a replay player (and should be focused / always visible).
@ -101,7 +101,7 @@ namespace osu.Game.Screens.Play.HUD
/// </summary>
/// <param name="user">The score's player.</param>
/// <param name="tracked">Whether the player is the local user or a replay player.</param>
public GameplayLeaderboardScore([CanBeNull] User user, bool tracked)
public GameplayLeaderboardScore([CanBeNull] APIUser user, bool tracked)
{
User = user;
Tracked = tracked;

View File

@ -12,11 +12,11 @@ using osu.Game.Configuration;
using osu.Game.Database;
using osu.Game.Graphics;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.Multiplayer;
using osu.Game.Online.Multiplayer.MatchTypes.TeamVersus;
using osu.Game.Online.Spectator;
using osu.Game.Rulesets.Scoring;
using osu.Game.Users;
using osuTK.Graphics;
namespace osu.Game.Screens.Play.HUD
@ -118,7 +118,7 @@ namespace osu.Game.Screens.Play.HUD
protected virtual TrackedUserData CreateUserData(MultiplayerRoomUser user, ScoreProcessor scoreProcessor) => new TrackedUserData(user, scoreProcessor);
protected override GameplayLeaderboardScore CreateLeaderboardScoreDrawable(User user, bool isTracked)
protected override GameplayLeaderboardScore CreateLeaderboardScoreDrawable(APIUser user, bool isTracked)
{
var leaderboardScore = base.CreateLeaderboardScoreDrawable(user, isTracked);

View File

@ -18,6 +18,7 @@ using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.Spectator;
using osu.Game.Overlays.BeatmapListing.Panels;
using osu.Game.Overlays.Settings;
@ -26,6 +27,7 @@ using osu.Game.Screens.OnlinePlay.Match.Components;
using osu.Game.Screens.Spectate;
using osu.Game.Users;
using osuTK;
using APIUser = osu.Game.Online.API.Requests.Responses.APIUser;
namespace osu.Game.Screens.Play
{
@ -33,7 +35,7 @@ namespace osu.Game.Screens.Play
public class SoloSpectator : SpectatorScreen, IPreviewTrackOwner
{
[NotNull]
private readonly User targetUser;
private readonly APIUser targetUser;
[Resolved]
private IAPIProvider api { get; set; }
@ -50,7 +52,6 @@ namespace osu.Game.Screens.Play
private Container beatmapPanelContainer;
private TriangleButton watchButton;
private SettingsCheckbox automaticDownload;
private BeatmapSetInfo onlineBeatmap;
/// <summary>
/// The player's immediate online gameplay state.
@ -60,7 +61,9 @@ namespace osu.Game.Screens.Play
private GetBeatmapSetRequest onlineBeatmapRequest;
public SoloSpectator([NotNull] User targetUser)
private APIBeatmapSet beatmapSet;
public SoloSpectator([NotNull] APIUser targetUser)
: base(targetUser.Id)
{
this.targetUser = targetUser;
@ -220,10 +223,10 @@ namespace osu.Game.Screens.Play
Debug.Assert(state.BeatmapID != null);
onlineBeatmapRequest = new GetBeatmapSetRequest(state.BeatmapID.Value, BeatmapSetLookupType.BeatmapId);
onlineBeatmapRequest.Success += res => Schedule(() =>
onlineBeatmapRequest.Success += beatmapSet => Schedule(() =>
{
onlineBeatmap = res.ToBeatmapSet(rulesets);
beatmapPanelContainer.Child = new GridBeatmapPanel(res);
this.beatmapSet = beatmapSet;
beatmapPanelContainer.Child = new GridBeatmapPanel(this.beatmapSet);
checkForAutomaticDownload();
});
@ -232,16 +235,16 @@ namespace osu.Game.Screens.Play
private void checkForAutomaticDownload()
{
if (onlineBeatmap == null)
if (beatmapSet == null)
return;
if (!automaticDownload.Current.Value)
return;
if (beatmaps.IsAvailableLocally(onlineBeatmap))
if (beatmaps.IsAvailableLocally(new BeatmapSetInfo { OnlineBeatmapSetID = beatmapSet.OnlineID }))
return;
beatmaps.Download(onlineBeatmap);
beatmaps.Download(beatmapSet);
}
public override bool OnExiting(IScreen next)

View File

@ -98,9 +98,8 @@ namespace osu.Game.Screens.Play
/// </summary>
protected virtual void RecreateGraph()
{
var newColumns = new BufferedContainer<Column>
var newColumns = new BufferedContainer<Column>(cachedFrameBuffer: true)
{
CacheDrawnFrameBuffer = true,
RedrawOnScale = false,
RelativeSizeAxes = Axes.Both,
};

View File

@ -51,13 +51,12 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy
Font = OsuFont.Numeric.With(size: 76),
UseFullGlyphHeight = false
},
superFlash = new BufferedContainer
superFlash = new BufferedContainer(cachedFrameBuffer: true)
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
BlurSigma = new Vector2(85),
Size = new Vector2(600),
CacheDrawnFrameBuffer = true,
Blending = BlendingParameters.Additive,
Alpha = 0,
Children = new[]
@ -71,14 +70,13 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy
},
},
},
flash = new BufferedContainer
flash = new BufferedContainer(cachedFrameBuffer: true)
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
BlurSigma = new Vector2(35),
BypassAutoSizeAxes = Axes.Both,
Size = new Vector2(200),
CacheDrawnFrameBuffer = true,
Blending = BlendingParameters.Additive,
Alpha = 0,
Scale = new Vector2(1.8f),

View File

@ -62,7 +62,7 @@ namespace osu.Game.Screens.Ranking.Expanded
{
var beatmap = score.BeatmapInfo;
var metadata = beatmap.BeatmapSet?.Metadata ?? beatmap.Metadata;
string creator = metadata.Author?.Username;
string creator = metadata.Author.Username;
var topStatistics = new List<StatisticDisplay>
{

View File

@ -6,7 +6,7 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Users;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Users.Drawables;
using osuTK;
@ -17,13 +17,13 @@ namespace osu.Game.Screens.Ranking.Expanded
/// </summary>
public class ExpandedPanelTopContent : CompositeDrawable
{
private readonly User user;
private readonly APIUser user;
/// <summary>
/// Creates a new <see cref="ExpandedPanelTopContent"/>.
/// </summary>
/// <param name="user">The <see cref="User"/> to display.</param>
public ExpandedPanelTopContent(User user)
/// <param name="user">The <see cref="APIUser"/> to display.</param>
public ExpandedPanelTopContent(APIUser user)
{
this.user = user;
Anchor = Anchor.TopCentre;

View File

@ -69,6 +69,8 @@ namespace osu.Game.Screens.Ranking.Statistics
foreach (var child in content)
child.FadeOut(150).Expire();
spinner.Hide();
var newScore = score.NewValue;
if (newScore == null)

View File

@ -143,11 +143,6 @@ namespace osu.Game.Screens.Select
private CarouselRoot root;
private IBindable<WeakReference<BeatmapSetInfo>> itemUpdated;
private IBindable<WeakReference<BeatmapSetInfo>> itemRemoved;
private IBindable<WeakReference<BeatmapInfo>> itemHidden;
private IBindable<WeakReference<BeatmapInfo>> itemRestored;
private readonly DrawablePool<DrawableCarouselBeatmapSet> setPool = new DrawablePool<DrawableCarouselBeatmapSet>(100);
public BeatmapCarousel()
@ -179,14 +174,10 @@ namespace osu.Game.Screens.Select
RightClickScrollingEnabled.ValueChanged += enabled => Scroll.RightMouseScrollbar = enabled.NewValue;
RightClickScrollingEnabled.TriggerChange();
itemUpdated = beatmaps.ItemUpdated.GetBoundCopy();
itemUpdated.BindValueChanged(beatmapUpdated);
itemRemoved = beatmaps.ItemRemoved.GetBoundCopy();
itemRemoved.BindValueChanged(beatmapRemoved);
itemHidden = beatmaps.BeatmapHidden.GetBoundCopy();
itemHidden.BindValueChanged(beatmapHidden);
itemRestored = beatmaps.BeatmapRestored.GetBoundCopy();
itemRestored.BindValueChanged(beatmapRestored);
beatmaps.ItemUpdated += beatmapUpdated;
beatmaps.ItemRemoved += beatmapRemoved;
beatmaps.BeatmapHidden += beatmapHidden;
beatmaps.BeatmapRestored += beatmapRestored;
if (!beatmapSets.Any())
loadBeatmapSets(GetLoadableBeatmaps());
@ -675,29 +666,10 @@ namespace osu.Game.Screens.Select
return (firstIndex, lastIndex);
}
private void beatmapRemoved(ValueChangedEvent<WeakReference<BeatmapSetInfo>> weakItem)
{
if (weakItem.NewValue.TryGetTarget(out var item))
RemoveBeatmapSet(item);
}
private void beatmapUpdated(ValueChangedEvent<WeakReference<BeatmapSetInfo>> weakItem)
{
if (weakItem.NewValue.TryGetTarget(out var item))
UpdateBeatmapSet(item);
}
private void beatmapRestored(ValueChangedEvent<WeakReference<BeatmapInfo>> weakItem)
{
if (weakItem.NewValue.TryGetTarget(out var b))
UpdateBeatmapSet(beatmaps.QueryBeatmapSet(s => s.ID == b.BeatmapSetInfoID));
}
private void beatmapHidden(ValueChangedEvent<WeakReference<BeatmapInfo>> weakItem)
{
if (weakItem.NewValue.TryGetTarget(out var b))
UpdateBeatmapSet(beatmaps.QueryBeatmapSet(s => s.ID == b.BeatmapSetInfoID));
}
private void beatmapRemoved(BeatmapSetInfo item) => RemoveBeatmapSet(item);
private void beatmapUpdated(BeatmapSetInfo item) => UpdateBeatmapSet(item);
private void beatmapRestored(BeatmapInfo b) => UpdateBeatmapSet(beatmaps.QueryBeatmapSet(s => s.ID == b.BeatmapSetInfoID));
private void beatmapHidden(BeatmapInfo b) => UpdateBeatmapSet(beatmaps.QueryBeatmapSet(s => s.ID == b.BeatmapSetInfoID));
private CarouselBeatmapSet createCarouselSet(BeatmapSetInfo beatmapSet)
{
@ -956,5 +928,18 @@ namespace osu.Game.Screens.Select
return base.OnDragStart(e);
}
}
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
if (beatmaps != null)
{
beatmaps.ItemUpdated -= beatmapUpdated;
beatmaps.ItemRemoved -= beatmapRemoved;
beatmaps.BeatmapHidden -= beatmapHidden;
beatmaps.BeatmapRestored -= beatmapRestored;
}
}
}
}

View File

@ -29,7 +29,7 @@ namespace osu.Game.Screens.Select
new PopupDialogOkButton
{
Text = @"Yes. Totally. Delete it.",
Action = () => manager.Delete(beatmap),
Action = () => manager?.Delete(beatmap),
},
new PopupDialogCancelButton
{

View File

@ -41,13 +41,13 @@ namespace osu.Game.Screens.Select
[Resolved]
private RulesetStore rulesets { get; set; }
private BeatmapInfo beatmapInfo;
private IBeatmapInfo beatmapInfo;
private APIFailTimes failTimes;
private int[] ratings;
public BeatmapInfo BeatmapInfo
public IBeatmapInfo BeatmapInfo
{
get => beatmapInfo;
set
@ -56,8 +56,11 @@ namespace osu.Game.Screens.Select
beatmapInfo = value;
failTimes = beatmapInfo?.OnlineInfo?.FailTimes;
ratings = beatmapInfo?.BeatmapSet?.OnlineInfo?.Ratings;
var onlineInfo = beatmapInfo as IBeatmapOnlineInfo;
var onlineSetInfo = beatmapInfo.BeatmapSet as IBeatmapSetOnlineInfo;
failTimes = onlineInfo?.FailTimes;
ratings = onlineSetInfo?.Ratings;
Scheduler.AddOnce(updateStatistics);
}
@ -178,9 +181,9 @@ namespace osu.Game.Screens.Select
private void updateStatistics()
{
advanced.BeatmapInfo = BeatmapInfo;
description.Text = BeatmapInfo?.Version;
source.Text = BeatmapInfo?.Metadata?.Source;
tags.Text = BeatmapInfo?.Metadata?.Tags;
description.Text = BeatmapInfo?.DifficultyName;
source.Text = BeatmapInfo?.Metadata.Source;
tags.Text = BeatmapInfo?.Metadata.Tags;
// failTimes may have been previously fetched
if (ratings != null && failTimes != null)
@ -190,7 +193,7 @@ namespace osu.Game.Screens.Select
}
// for now, let's early abort if an OnlineBeatmapID is not present (should have been populated at import time).
if (BeatmapInfo?.OnlineBeatmapID == null || api.State.Value == APIState.Offline)
if (BeatmapInfo == null || BeatmapInfo.OnlineID <= 0 || api.State.Value == APIState.Offline)
{
updateMetrics();
return;

View File

@ -428,7 +428,7 @@ namespace osu.Game.Screens.Select
private Drawable getMapper(BeatmapMetadata metadata)
{
if (metadata.Author == null)
if (string.IsNullOrEmpty(metadata.Author.Username))
return Empty();
return new LinkFlowContainer(s =>

View File

@ -27,9 +27,8 @@ namespace osu.Game.Screens.Select
{
RelativeSizeAxes = Axes.Both;
InternalChild = new BufferedContainer
InternalChild = new BufferedContainer(cachedFrameBuffer: true)
{
CacheDrawnFrameBuffer = true,
RelativeSizeAxes = Axes.Both,
Children = new Drawable[]
{

View File

@ -49,7 +49,7 @@ namespace osu.Game.Screens.Select.Carousel
match &= !criteria.BeatDivisor.HasFilter || criteria.BeatDivisor.IsInRange(BeatmapInfo.BeatDivisor);
match &= !criteria.OnlineStatus.HasFilter || criteria.OnlineStatus.IsInRange(BeatmapInfo.Status);
match &= !criteria.Creator.HasFilter || criteria.Creator.Matches(BeatmapInfo.Metadata.AuthorString);
match &= !criteria.Creator.HasFilter || criteria.Creator.Matches(BeatmapInfo.Metadata.Author.Username);
match &= !criteria.Artist.HasFilter || criteria.Artist.Matches(BeatmapInfo.Metadata.Artist) ||
criteria.Artist.Matches(BeatmapInfo.Metadata.ArtistUnicode);

View File

@ -15,8 +15,8 @@ namespace osu.Game.Screens.Select.Carousel
public class SetPanelBackground : BufferedContainer
{
public SetPanelBackground(WorkingBeatmap working)
: base(cachedFrameBuffer: true)
{
CacheDrawnFrameBuffer = true;
RedrawOnScale = false;
Children = new Drawable[]

View File

@ -1,7 +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 System;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
@ -28,9 +27,6 @@ namespace osu.Game.Screens.Select.Carousel
[Resolved]
private IAPIProvider api { get; set; }
private IBindable<WeakReference<ScoreInfo>> itemUpdated;
private IBindable<WeakReference<ScoreInfo>> itemRemoved;
public TopLocalRank(BeatmapInfo beatmapInfo)
: base(null)
{
@ -40,24 +36,18 @@ namespace osu.Game.Screens.Select.Carousel
[BackgroundDependencyLoader]
private void load()
{
itemUpdated = scores.ItemUpdated.GetBoundCopy();
itemUpdated.BindValueChanged(scoreChanged);
itemRemoved = scores.ItemRemoved.GetBoundCopy();
itemRemoved.BindValueChanged(scoreChanged);
scores.ItemUpdated += scoreChanged;
scores.ItemRemoved += scoreChanged;
ruleset.ValueChanged += _ => fetchAndLoadTopScore();
fetchAndLoadTopScore();
}
private void scoreChanged(ValueChangedEvent<WeakReference<ScoreInfo>> weakScore)
private void scoreChanged(ScoreInfo score)
{
if (weakScore.NewValue.TryGetTarget(out var score))
{
if (score.BeatmapInfoID == beatmapInfo.ID)
fetchAndLoadTopScore();
}
if (score.BeatmapInfoID == beatmapInfo.ID)
fetchAndLoadTopScore();
}
private ScheduledDelegate scheduledRankUpdate;
@ -86,5 +76,16 @@ namespace osu.Game.Screens.Select.Carousel
.OrderByDescending(s => s.TotalScore)
.FirstOrDefault();
}
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
if (scores != null)
{
scores.ItemUpdated -= scoreChanged;
scores.ItemRemoved -= scoreChanged;
}
}
}
}

View File

@ -44,10 +44,6 @@ namespace osu.Game.Screens.Select.Leaderboards
private bool filterMods;
private IBindable<WeakReference<ScoreInfo>> itemRemoved;
private IBindable<WeakReference<ScoreInfo>> itemAdded;
/// <summary>
/// Whether to apply the game's currently selected mods as a filter when retrieving scores.
/// </summary>
@ -90,11 +86,8 @@ namespace osu.Game.Screens.Select.Leaderboards
UpdateScores();
};
itemRemoved = scoreManager.ItemRemoved.GetBoundCopy();
itemRemoved.BindValueChanged(onScoreRemoved);
itemAdded = scoreManager.ItemUpdated.GetBoundCopy();
itemAdded.BindValueChanged(onScoreAdded);
scoreManager.ItemRemoved += scoreStoreChanged;
scoreManager.ItemUpdated += scoreStoreChanged;
}
protected override void Reset()
@ -103,22 +96,13 @@ namespace osu.Game.Screens.Select.Leaderboards
TopScore = null;
}
private void onScoreRemoved(ValueChangedEvent<WeakReference<ScoreInfo>> score) =>
scoreStoreChanged(score);
private void onScoreAdded(ValueChangedEvent<WeakReference<ScoreInfo>> score) =>
scoreStoreChanged(score);
private void scoreStoreChanged(ValueChangedEvent<WeakReference<ScoreInfo>> score)
private void scoreStoreChanged(ScoreInfo score)
{
if (Scope != BeatmapLeaderboardScope.Local)
return;
if (score.NewValue.TryGetTarget(out var scoreInfo))
{
if (BeatmapInfo?.ID != scoreInfo.BeatmapInfoID)
return;
}
if (BeatmapInfo?.ID != score.BeatmapInfoID)
return;
RefreshScores();
}
@ -215,5 +199,16 @@ namespace osu.Game.Screens.Select.Leaderboards
{
Action = () => ScoreSelected?.Invoke(model)
};
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
if (scoreManager != null)
{
scoreManager.ItemRemoved -= scoreStoreChanged;
scoreManager.ItemUpdated -= scoreStoreChanged;
}
}
}
}

View File

@ -1,7 +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 System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
@ -11,11 +10,11 @@ using osu.Framework.Bindables;
using osu.Framework.Extensions.ObjectExtensions;
using osu.Game.Beatmaps;
using osu.Game.Database;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.Spectator;
using osu.Game.Replays;
using osu.Game.Rulesets;
using osu.Game.Scoring;
using osu.Game.Users;
namespace osu.Game.Screens.Spectate
{
@ -42,11 +41,9 @@ namespace osu.Game.Screens.Spectate
private readonly IBindableDictionary<int, SpectatorState> playingUserStates = new BindableDictionary<int, SpectatorState>();
private readonly Dictionary<int, User> userMap = new Dictionary<int, User>();
private readonly Dictionary<int, APIUser> userMap = new Dictionary<int, APIUser>();
private readonly Dictionary<int, SpectatorGameplayState> gameplayStates = new Dictionary<int, SpectatorGameplayState>();
private IBindable<WeakReference<BeatmapSetInfo>> managerUpdated;
/// <summary>
/// Creates a new <see cref="SpectatorScreen"/>.
/// </summary>
@ -73,20 +70,16 @@ namespace osu.Game.Screens.Spectate
playingUserStates.BindTo(spectatorClient.PlayingUserStates);
playingUserStates.BindCollectionChanged(onPlayingUserStatesChanged, true);
managerUpdated = beatmaps.ItemUpdated.GetBoundCopy();
managerUpdated.BindValueChanged(beatmapUpdated);
beatmaps.ItemUpdated += beatmapUpdated;
foreach ((int id, var _) in userMap)
spectatorClient.WatchUser(id);
}));
}
private void beatmapUpdated(ValueChangedEvent<WeakReference<BeatmapSetInfo>> e)
private void beatmapUpdated(BeatmapSetInfo beatmapSet)
{
if (!e.NewValue.TryGetTarget(out var beatmapSet))
return;
foreach ((int userId, var _) in userMap)
foreach ((int userId, _) in userMap)
{
if (!playingUserStates.TryGetValue(userId, out var userState))
continue;
@ -223,7 +216,8 @@ namespace osu.Game.Screens.Spectate
spectatorClient.StopWatchingUser(userId);
}
managerUpdated?.UnbindAll();
if (beatmaps != null)
beatmaps.ItemUpdated -= beatmapUpdated;
}
}
}