osu/osu.Game/Screens/Play/SoloSpectator.cs

254 lines
9.0 KiB
C#
Raw Normal View History

2020-10-26 10:47:39 +00:00
// 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.Diagnostics;
2020-10-26 10:47:39 +00:00
using JetBrains.Annotations;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
2020-10-28 09:35:20 +00:00
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Screens;
2021-04-02 12:27:20 +00:00
using osu.Framework.Threading;
using osu.Game.Audio;
using osu.Game.Beatmaps;
using osu.Game.Configuration;
using osu.Game.Graphics;
2020-10-26 10:47:39 +00:00
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.Spectator;
using osu.Game.Overlays.BeatmapListing.Panels;
using osu.Game.Overlays.Settings;
using osu.Game.Rulesets;
using osu.Game.Screens.OnlinePlay.Match.Components;
using osu.Game.Screens.Spectate;
2020-10-26 10:47:39 +00:00
using osu.Game.Users;
using osuTK;
2020-10-26 10:47:39 +00:00
namespace osu.Game.Screens.Play
{
[Cached(typeof(IPreviewTrackOwner))]
public class SoloSpectator : SpectatorScreen, IPreviewTrackOwner
2020-10-26 10:47:39 +00:00
{
[NotNull]
2020-10-26 10:47:39 +00:00
private readonly User targetUser;
[Resolved]
private IAPIProvider api { get; set; }
[Resolved]
private PreviewTrackManager previewTrackManager { get; set; }
[Resolved]
private RulesetStore rulesets { get; set; }
[Resolved]
private BeatmapManager beatmaps { get; set; }
private Container beatmapPanelContainer;
private TriangleButton watchButton;
private SettingsCheckbox automaticDownload;
private BeatmapSetInfo onlineBeatmap;
/// <summary>
/// The player's immediate online gameplay state.
2021-04-02 12:27:20 +00:00
/// This doesn't always reflect the gameplay state being watched.
/// </summary>
private GameplayState immediateGameplayState;
private GetBeatmapSetRequest onlineBeatmapRequest;
2021-04-01 13:08:52 +00:00
public SoloSpectator([NotNull] User targetUser)
: base(targetUser.Id)
2020-10-26 10:47:39 +00:00
{
this.targetUser = targetUser;
2020-10-26 10:47:39 +00:00
}
[BackgroundDependencyLoader]
private void load(OsuColour colours, OsuConfigManager config)
2020-10-26 10:47:39 +00:00
{
2020-10-28 09:35:20 +00:00
InternalChild = new Container
2020-10-26 10:47:39 +00:00
{
2020-10-28 09:35:20 +00:00
Masking = true,
CornerRadius = 20,
AutoSizeAxes = Axes.Both,
AutoSizeDuration = 500,
AutoSizeEasing = Easing.OutQuint,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Children = new Drawable[]
2020-10-26 10:47:39 +00:00
{
2020-10-28 09:35:20 +00:00
new Box
{
2020-10-28 09:35:20 +00:00
Colour = colours.GreySeafoamDark,
RelativeSizeAxes = Axes.Both,
},
new FillFlowContainer
{
Margin = new MarginPadding(20),
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Vertical,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Spacing = new Vector2(15),
Children = new Drawable[]
{
2020-10-28 09:35:20 +00:00
new OsuSpriteText
{
Text = "Spectator Mode",
Font = OsuFont.Default.With(size: 30),
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
},
new FillFlowContainer
{
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Horizontal,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Spacing = new Vector2(15),
Children = new Drawable[]
{
new UserGridPanel(targetUser)
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
Height = 145,
Width = 290,
},
new SpriteIcon
{
Size = new Vector2(40),
Icon = FontAwesome.Solid.ArrowRight,
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
},
beatmapPanelContainer = new Container
{
AutoSizeAxes = Axes.Both,
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
},
}
},
automaticDownload = new SettingsCheckbox
{
LabelText = "Automatically download beatmaps",
Current = config.GetBindable<bool>(OsuSetting.AutomaticallyDownloadWhenSpectating),
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
},
2020-10-28 09:35:20 +00:00
watchButton = new PurpleTriangleButton
{
Text = "Start Watching",
Width = 250,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
2021-04-02 12:27:20 +00:00
Action = () => scheduleStart(immediateGameplayState),
Enabled = { Value = false }
2020-10-28 09:35:20 +00:00
}
}
}
2020-10-28 09:35:20 +00:00
}
2020-10-26 10:47:39 +00:00
};
}
protected override void LoadComplete()
{
base.LoadComplete();
automaticDownload.Current.BindValueChanged(_ => checkForAutomaticDownload());
}
2021-04-02 12:27:20 +00:00
protected override void OnUserStateChanged(int userId, SpectatorState spectatorState)
{
clearDisplay();
showBeatmapPanel(spectatorState);
2021-04-02 12:27:20 +00:00
}
2021-04-02 12:27:20 +00:00
protected override void StartGameplay(int userId, GameplayState gameplayState)
{
immediateGameplayState = gameplayState;
watchButton.Enabled.Value = true;
2021-04-02 12:27:20 +00:00
scheduleStart(gameplayState);
}
protected override void EndGameplay(int userId)
{
2021-04-02 12:27:20 +00:00
scheduledStart?.Cancel();
immediateGameplayState = null;
watchButton.Enabled.Value = false;
2021-04-02 12:27:20 +00:00
clearDisplay();
}
2020-10-28 09:35:20 +00:00
private void clearDisplay()
{
watchButton.Enabled.Value = false;
onlineBeatmapRequest?.Cancel();
2020-10-28 09:35:20 +00:00
beatmapPanelContainer.Clear();
previewTrackManager.StopAnyPlaying(this);
2020-10-28 09:35:20 +00:00
}
2021-04-02 12:27:20 +00:00
private ScheduledDelegate scheduledStart;
private void scheduleStart(GameplayState gameplayState)
2020-10-28 09:35:20 +00:00
{
2021-04-02 12:27:20 +00:00
// This function may be called multiple times in quick succession once the screen becomes current again.
scheduledStart?.Cancel();
scheduledStart = Schedule(() =>
{
if (this.IsCurrentScreen())
start();
else
scheduleStart(gameplayState);
});
2021-04-02 12:27:20 +00:00
void start()
{
Beatmap.Value = gameplayState.Beatmap;
Ruleset.Value = gameplayState.Ruleset.RulesetInfo;
2021-04-02 12:27:20 +00:00
this.Push(new SpectatorPlayerLoader(gameplayState.Score));
}
}
private void showBeatmapPanel(SpectatorState state)
{
Debug.Assert(state.BeatmapID != null);
onlineBeatmapRequest = new GetBeatmapSetRequest(state.BeatmapID.Value, BeatmapSetLookupType.BeatmapId);
onlineBeatmapRequest.Success += res => Schedule(() =>
{
onlineBeatmap = res.ToBeatmapSet(rulesets);
beatmapPanelContainer.Child = new GridBeatmapPanel(onlineBeatmap);
checkForAutomaticDownload();
});
api.Queue(onlineBeatmapRequest);
}
private void checkForAutomaticDownload()
{
if (onlineBeatmap == null)
return;
if (!automaticDownload.Current.Value)
return;
if (beatmaps.IsAvailableLocally(onlineBeatmap))
return;
beatmaps.Download(onlineBeatmap);
}
public override bool OnExiting(IScreen next)
{
previewTrackManager.StopAnyPlaying(this);
return base.OnExiting(next);
}
2020-10-26 10:47:39 +00:00
}
}