// Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Screens; using osu.Game.Beatmaps; using osu.Game.Graphics.Containers; using osu.Game.Online.Multiplayer; using osu.Game.Online.Multiplayer.GameTypes; using osu.Game.Rulesets; using osu.Game.Screens.Multi.Match.Components; using osu.Game.Screens.Multi.Play; using osu.Game.Screens.Play; using osu.Game.Screens.Select; namespace osu.Game.Screens.Multi.Match { public class MatchSubScreen : CompositeDrawable, IMultiplayerSubScreen { public bool AllowBeatmapRulesetChange => false; public bool AllowExternalScreenChange => true; public bool CursorVisible => true; public string Title => room.RoomID.Value == null ? "New room" : room.Name.Value; public string ShortTitle => "room"; public bool ValidForResume { get; set; } = true; public bool ValidForPush { get; set; } = true; public override bool RemoveWhenNotAlive => false; private readonly RoomBindings bindings = new RoomBindings(); private readonly MatchLeaderboard leaderboard; private readonly Action pushGameplayScreen; [Cached] private readonly Room room; [Resolved] private IBindableBeatmap beatmap { get; set; } [Resolved] private BeatmapManager beatmapManager { get; set; } [Resolved(CanBeNull = true)] private OsuGame game { get; set; } [Resolved(CanBeNull = true)] private IRoomManager manager { get; set; } public MatchSubScreen(Room room, Action pushGameplayScreen) { this.room = room; this.pushGameplayScreen = pushGameplayScreen; RelativeSizeAxes = Axes.Both; bindings.Room = room; MatchChatDisplay chat; Components.Header header; Info info; GridContainer bottomRow; MatchSettingsOverlay settings; InternalChildren = new Drawable[] { new GridContainer { RelativeSizeAxes = Axes.Both, Content = new[] { new Drawable[] { header = new Components.Header(room) { Depth = -1 } }, new Drawable[] { info = new Info(room) { OnStart = onStart } }, new Drawable[] { bottomRow = new GridContainer { RelativeSizeAxes = Axes.Both, Content = new[] { new Drawable[] { leaderboard = new MatchLeaderboard { Padding = new MarginPadding(10), RelativeSizeAxes = Axes.Both, Room = room }, new Container { Padding = new MarginPadding(10), RelativeSizeAxes = Axes.Both, Child = chat = new MatchChatDisplay(room) { RelativeSizeAxes = Axes.Both } }, }, }, } }, }, RowDimensions = new[] { new Dimension(GridSizeMode.AutoSize), new Dimension(GridSizeMode.AutoSize), new Dimension(GridSizeMode.Distributed), } }, new Container { RelativeSizeAxes = Axes.Both, Padding = new MarginPadding { Top = Components.Header.HEIGHT }, Child = settings = new MatchSettingsOverlay(room) { RelativeSizeAxes = Axes.Both }, }, }; header.OnRequestSelectBeatmap = () => this.Push(new MatchSongSelect { Selected = addPlaylistItem }); header.Tabs.Current.ValueChanged += t => { const float fade_duration = 500; if (t is SettingsMatchPage) { settings.Show(); info.FadeOut(fade_duration, Easing.OutQuint); bottomRow.FadeOut(fade_duration, Easing.OutQuint); } else { settings.Hide(); info.FadeIn(fade_duration, Easing.OutQuint); bottomRow.FadeIn(fade_duration, Easing.OutQuint); } }; chat.Exit += this.Exit; } [BackgroundDependencyLoader] private void load() { beatmapManager.ItemAdded += beatmapAdded; } public void OnEntering(IScreen last) { this.FadeInFromZero(WaveContainer.APPEAR_DURATION, Easing.OutQuint); this.FadeInFromZero(WaveContainer.APPEAR_DURATION, Easing.OutQuint); this.MoveToX(200).MoveToX(0, WaveContainer.APPEAR_DURATION, Easing.OutQuint); } public bool OnExiting(IScreen next) { manager?.PartRoom(); this.FadeOut(WaveContainer.DISAPPEAR_DURATION, Easing.OutQuint); this.MoveToX(200, WaveContainer.DISAPPEAR_DURATION, Easing.OutQuint); return false; } public void OnResuming(IScreen last) { this.FadeIn(WaveContainer.APPEAR_DURATION, Easing.OutQuint); this.MoveToX(0, WaveContainer.APPEAR_DURATION, Easing.OutQuint); } public void OnSuspending(IScreen next) { this.FadeOut(WaveContainer.DISAPPEAR_DURATION, Easing.OutQuint); this.MoveToX(-200, WaveContainer.DISAPPEAR_DURATION, Easing.OutQuint); } protected override void LoadComplete() { base.LoadComplete(); bindings.CurrentBeatmap.BindValueChanged(setBeatmap, true); bindings.CurrentRuleset.BindValueChanged(setRuleset, true); } private void setBeatmap(BeatmapInfo beatmap) { // 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); game?.ForcefullySetBeatmap(beatmapManager.GetWorkingBeatmap(localBeatmap)); } private void setRuleset(RulesetInfo ruleset) { if (ruleset == null) return; game?.ForcefullySetRuleset(ruleset); } private void beatmapAdded(BeatmapSetInfo model, bool existing, bool silent) => Schedule(() => { if (beatmap.Value != beatmapManager.DefaultBeatmap) return; if (bindings.CurrentBeatmap.Value == null) return; // Try to retrieve the corresponding local beatmap var localBeatmap = beatmapManager.QueryBeatmap(b => b.OnlineBeatmapID == bindings.CurrentBeatmap.Value.OnlineBeatmapID); if (localBeatmap != null) game?.ForcefullySetBeatmap(beatmapManager.GetWorkingBeatmap(localBeatmap)); }); private void addPlaylistItem(PlaylistItem item) { bindings.Playlist.Clear(); bindings.Playlist.Add(item); } private void onStart() { beatmap.Value.Mods.Value = bindings.CurrentMods.Value.ToArray(); switch (bindings.Type.Value) { default: case GameTypeTimeshift _: pushGameplayScreen?.Invoke(new PlayerLoader(() => new TimeshiftPlayer(room, room.Playlist.First().ID) { Exited = () => leaderboard.RefreshScores() })); break; } } public override string ToString() => Title; protected override void Dispose(bool isDisposing) { base.Dispose(isDisposing); if (beatmapManager != null) beatmapManager.ItemAdded -= beatmapAdded; } } }