1
0
mirror of https://github.com/ppy/osu.git synced 2024-12-14 13:22:55 +08:00

Implement RoomManager and RoomsContainer

Reduces logic from LoungeScreen
This commit is contained in:
smoogipoo 2018-12-11 19:07:40 +09:00
parent 1ac615b490
commit 497f431366
10 changed files with 229 additions and 189 deletions

View File

@ -1,8 +1,6 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Game.Beatmaps;
@ -10,6 +8,7 @@ using osu.Game.Online.Multiplayer;
using osu.Game.Rulesets;
using osu.Game.Screens;
using osu.Game.Screens.Backgrounds;
using osu.Game.Screens.Multi;
using osu.Game.Screens.Multi.Lounge;
using osu.Game.Screens.Multi.Lounge.Components;
using osu.Game.Users;
@ -160,11 +159,8 @@ namespace osu.Game.Tests.Visual
};
AddStep(@"show", () => Add(loungeScreen));
AddStep(@"set rooms", () => loungeScreen.Rooms = rooms);
selectAssert(0);
AddStep(@"clear rooms", () => loungeScreen.Rooms = new Room[] {});
AddAssert(@"no room selected", () => loungeScreen.SelectedRoom == null);
AddStep(@"set rooms", () => loungeScreen.Rooms = rooms);
selectAssert(1);
AddStep(@"open room 1", () => clickRoom(1));
AddUntilStep(() => loungeScreen.ChildScreen?.IsCurrentScreen == true, "wait until room current");
@ -174,37 +170,33 @@ namespace osu.Game.Tests.Visual
filterAssert(string.Empty, LoungeTab.Private, 1);
filterAssert(string.Empty, LoungeTab.Public, 2);
filterAssert(@"no matches", LoungeTab.Public, 0);
AddStep(@"clear rooms", () => loungeScreen.Rooms = new Room[] {});
AddStep(@"set rooms", () => loungeScreen.Rooms = rooms);
AddAssert(@"no matches after clear", () => !loungeScreen.ChildRooms.Any());
filterAssert(string.Empty, LoungeTab.Public, 2);
AddStep(@"exit", loungeScreen.Exit);
}
private void clickRoom(int n)
{
InputManager.MoveMouseTo(loungeScreen.ChildRooms.ElementAt(n));
InputManager.Click(MouseButton.Left);
}
private void selectAssert(int n)
{
AddStep($@"select room {n}", () => clickRoom(n));
AddAssert($@"room {n} selected", () => loungeScreen.SelectedRoom == loungeScreen.ChildRooms.ElementAt(n).Room);
}
private void filterAssert(string filter, LoungeTab tab, int endCount)
{
AddStep($@"filter '{filter}', {tab}", () => loungeScreen.SetFilter(filter, tab));
AddAssert(@"filtered correctly", () => loungeScreen.ChildRooms.Count() == endCount);
}
private class TestLoungeScreen : LoungeScreen
{
protected override BackgroundScreen CreateBackground() => new BackgroundScreenDefault();
public IEnumerable<DrawableRoom> ChildRooms => RoomsContainer.Children.Where(r => r.MatchingFilter);
public Room SelectedRoom => Inspector.Room;
[Resolved]
private RoomManager manager { get; set; }
public Room SelectedRoom => manager.Current.Value;
public void SetFilter(string filter, LoungeTab tab)
{

View File

@ -66,8 +66,7 @@ namespace osu.Game.Tests.Visual
}
};
RoomInspector inspector;
Add(inspector = new RoomInspector
Add(new RoomInspector
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
@ -75,9 +74,6 @@ namespace osu.Game.Tests.Visual
Width = 0.5f,
});
AddStep(@"set room", () => inspector.Room = room);
AddStep(@"null room", () => inspector.Room = null);
AddStep(@"set room", () => inspector.Room = room);
AddStep(@"change title", () => room.Name.Value = @"A Better Room Than The Above");
AddStep(@"change host", () => room.Host.Value = new User { Username = @"DrabWeb", Id = 6946022, Country = new Country { FlagName = @"CA" } });
AddStep(@"change status", () => room.Status.Value = new RoomStatusPlaying());
@ -133,8 +129,6 @@ namespace osu.Game.Tests.Visual
}
}
};
inspector.Room = newRoom;
});
}

View File

@ -18,7 +18,9 @@ namespace osu.Game.Screens.Multi.Lounge.Components
DisplayStyleControl.Hide();
}
public RoomAvailability Availability
public FilterCriteria CreateCriteria() => new FilterCriteria { Availability = availability };
private RoomAvailability availability
{
get
{

View File

@ -0,0 +1,12 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Online.Multiplayer;
namespace osu.Game.Screens.Multi.Lounge.Components
{
public class FilterCriteria
{
public RoomAvailability Availability;
}
}

View File

@ -28,6 +28,8 @@ namespace osu.Game.Screens.Multi.Lounge.Components
{
private const float transition_duration = 100;
public readonly Bindable<Room> Room = new Bindable<Room>();
private readonly MarginPadding contentPadding = new MarginPadding { Horizontal = 20, Vertical = 10 };
private readonly Bindable<string> nameBind = new Bindable<string>();
private readonly Bindable<BeatmapInfo> beatmapBind = new Bindable<BeatmapInfo>();
@ -52,43 +54,6 @@ namespace osu.Game.Screens.Multi.Lounge.Components
[Resolved]
private BeatmapManager beatmaps { get; set; }
private Room room;
public Room Room
{
get => room;
set
{
if (value == room)
return;
if (room != null)
{
nameBind.UnbindFrom(room.Name);
hostBind.UnbindFrom(room.Host);
statusBind.UnbindFrom(room.Status);
typeBind.UnbindFrom(room.Type);
beatmapBind.UnbindFrom(room.Beatmap);
maxParticipantsBind.UnbindFrom(room.MaxParticipants);
participantsBind.UnbindFrom(room.Participants);
}
room = value;
if (room != null)
{
nameBind.BindTo(room.Name);
hostBind.BindTo(room.Host);
statusBind.BindTo(room.Status);
typeBind.BindTo(room.Type);
beatmapBind.BindTo(room.Beatmap);
maxParticipantsBind.BindTo(room.MaxParticipants);
participantsBind.BindTo(room.Participants);
}
updateState();
}
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
@ -226,7 +191,52 @@ namespace osu.Game.Screens.Multi.Lounge.Components
beatmapTypeInfo.Type.BindTo(typeBind);
beatmapTypeInfo.Beatmap.BindTo(beatmapBind);
updateState();
Room.BindValueChanged(updateRoom, true);
}
private Room lastRoom;
private void updateRoom(Room newRoom)
{
if (lastRoom != null)
{
nameBind.UnbindFrom(lastRoom.Name);
hostBind.UnbindFrom(lastRoom.Host);
statusBind.UnbindFrom(lastRoom.Status);
typeBind.UnbindFrom(lastRoom.Type);
beatmapBind.UnbindFrom(lastRoom.Beatmap);
maxParticipantsBind.UnbindFrom(lastRoom.MaxParticipants);
participantsBind.UnbindFrom(lastRoom.Participants);
}
if (newRoom != null)
{
nameBind.BindTo(newRoom.Name);
hostBind.BindTo(newRoom.Host);
statusBind.BindTo(newRoom.Status);
typeBind.BindTo(newRoom.Type);
beatmapBind.BindTo(newRoom.Beatmap);
maxParticipantsBind.BindTo(newRoom.MaxParticipants);
participantsBind.BindTo(newRoom.Participants);
participantsFlow.FadeIn(transition_duration);
participantCount.FadeIn(transition_duration);
beatmapTypeInfo.FadeIn(transition_duration);
name.FadeIn(transition_duration);
participantInfo.FadeIn(transition_duration);
}
else
{
participantsFlow.FadeOut(transition_duration);
participantCount.FadeOut(transition_duration);
beatmapTypeInfo.FadeOut(transition_duration);
name.FadeOut(transition_duration);
participantInfo.FadeOut(transition_duration);
displayStatus(new RoomStatusNoneSelected());
}
lastRoom = newRoom;
}
protected override void UpdateAfterChildren()
@ -245,32 +255,6 @@ namespace osu.Game.Screens.Multi.Lounge.Components
status.FadeColour(c, transition_duration);
}
private void updateState()
{
if (Room == null)
{
beatmap.Value = null;
participantsFlow.FadeOut(transition_duration);
participantCount.FadeOut(transition_duration);
beatmapTypeInfo.FadeOut(transition_duration);
name.FadeOut(transition_duration);
participantInfo.FadeOut(transition_duration);
displayStatus(new RoomStatusNoneSelected());
}
else
{
participantsFlow.FadeIn(transition_duration);
participantCount.FadeIn(transition_duration);
beatmapTypeInfo.FadeIn(transition_duration);
name.FadeIn(transition_duration);
participantInfo.FadeIn(transition_duration);
statusBind.TriggerChange();
beatmapBind.TriggerChange();
}
}
private class UserTile : Container, IHasTooltip
{
private readonly User user;

View File

@ -0,0 +1,104 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Configuration;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Graphics.UserInterface;
using osu.Game.Online.Multiplayer;
using osuTK;
namespace osu.Game.Screens.Multi.Lounge.Components
{
public class RoomsContainer : CompositeDrawable, IHasFilterableChildren
{
public Action<Room> OpenRequested;
private readonly IBindableCollection<Room> rooms = new BindableCollection<Room>();
private readonly Bindable<Room> currentRoom = new Bindable<Room>();
private readonly FillFlowContainer<DrawableRoom> roomFlow;
[Resolved]
private RoomManager manager { get; set; }
public RoomsContainer()
{
RelativeSizeAxes = Axes.X;
AutoSizeAxes = Axes.Y;
InternalChild = roomFlow = new FillFlowContainer<DrawableRoom>
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Direction = FillDirection.Vertical,
Spacing = new Vector2(2),
};
}
[BackgroundDependencyLoader]
private void load()
{
currentRoom.BindTo(manager.Current);
rooms.BindTo(manager.Rooms);
rooms.ItemsAdded += addRooms;
rooms.ItemsRemoved += removeRooms;
addRooms(rooms);
currentRoom.BindValueChanged(selectRoom, true);
}
private FilterCriteria currentFilter;
public void Filter(FilterCriteria criteria)
{
roomFlow.Children.ForEach(r => r.MatchingFilter = criteria == null || r.Room.Availability == criteria.Availability);
currentFilter = criteria;
}
private void addRooms(IEnumerable<Room> rooms)
{
foreach (var r in rooms)
roomFlow.Add(new DrawableRoom(r) { Action = () => selectRoom(r) });
Filter(currentFilter);
}
private void removeRooms(IEnumerable<Room> rooms)
{
foreach (var r in rooms)
{
var toRemove = roomFlow.Single(d => d.Room == r);
toRemove.Action = null;
roomFlow.Remove(toRemove);
}
}
private void selectRoom(Room room)
{
var drawable = roomFlow.FirstOrDefault(r => r.Room == room);
if (drawable != null && drawable.State == SelectionState.Selected)
OpenRequested?.Invoke(room);
else
{
currentRoom.Value = room;
roomFlow.Children.ForEach(r => r.State = r.Room == room ? SelectionState.Selected : SelectionState.NotSelected);
}
}
public IEnumerable<string> FilterTerms => Enumerable.Empty<string>();
public IEnumerable<IFilterable> FilterableChildren => InternalChildren.OfType<IFilterable>();
public bool MatchingFilter { set { } }
}
}

View File

@ -1,40 +1,37 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Collections.Generic;
using osu.Framework.Configuration;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Input.Events;
using osu.Framework.Screens;
using osu.Game.Graphics.UserInterface;
using osu.Game.Online.Multiplayer;
using osu.Game.Overlays.SearchableList;
using osu.Game.Screens.Multi.Lounge.Components;
using osu.Game.Screens.Multi.Match;
using osuTK;
namespace osu.Game.Screens.Multi.Lounge
{
public class LoungeScreen : MultiplayerScreen
{
protected readonly FilterControl Filter;
private readonly Container content;
private readonly SearchContainer search;
private readonly RoomsContainer rooms;
protected readonly FilterControl Filter;
protected readonly FillFlowContainer<DrawableRoom> RoomsContainer;
protected readonly RoomInspector Inspector;
[Cached]
private readonly RoomManager manager;
public override string Title => "Lounge";
private Room roomBeingCreated;
private readonly IBindable<bool> roomCreated = new Bindable<bool>();
protected override Drawable TransitionContent => content;
public LoungeScreen()
{
RoomInspector inspector;
Children = new Drawable[]
{
Filter = new FilterControl { Depth = -1 },
@ -56,16 +53,10 @@ namespace osu.Game.Screens.Multi.Lounge
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Child = RoomsContainer = new RoomsFilterContainer
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Direction = FillDirection.Vertical,
Spacing = new Vector2(10 - DrawableRoom.SELECTION_BORDER_WIDTH * 2),
},
Child = rooms = new RoomsContainer { OpenRequested = openRoom }
},
},
Inspector = new RoomInspector
inspector = new RoomInspector
{
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
@ -73,18 +64,15 @@ namespace osu.Game.Screens.Multi.Lounge
Width = 0.45f,
},
},
}
},
manager = new RoomManager()
};
inspector.Room.BindTo(manager.Current);
Filter.Search.Current.ValueChanged += s => filterRooms();
Filter.Tabs.Current.ValueChanged += t => filterRooms();
Filter.Search.Exit += Exit;
roomCreated.BindValueChanged(v =>
{
if (v)
addRoom(roomBeingCreated);
});
}
protected override void UpdateAfterChildren()
@ -99,31 +87,6 @@ namespace osu.Game.Screens.Multi.Lounge
};
}
public IEnumerable<Room> Rooms
{
set
{
RoomsContainer.ForEach(r => r.Action = null);
RoomsContainer.Clear();
foreach (var room in value)
addRoom(room);
}
}
private DrawableRoom addRoom(Room room)
{
var drawableRoom = new DrawableRoom(room);
drawableRoom.Action = () => selectionRequested(drawableRoom);
RoomsContainer.Add(drawableRoom);
filterRooms();
return drawableRoom;
}
protected override void OnFocus(FocusEvent e)
{
GetContainingInputManager().ChangeFocus(Filter.Search);
@ -158,65 +121,22 @@ namespace osu.Game.Screens.Multi.Lounge
{
if (Filter.Tabs.Current.Value == LoungeTab.Create)
{
roomBeingCreated = new Room();
roomCreated.UnbindBindings();
roomCreated.BindTo(roomBeingCreated.Created);
Filter.Tabs.Current.Value = LoungeTab.Public;
Push(new MatchScreen(roomBeingCreated));
Push(new MatchScreen(new Room()));
}
search.SearchTerm = Filter.Search.Current.Value ?? string.Empty;
foreach (DrawableRoom r in RoomsContainer.Children)
{
r.MatchingFilter = r.MatchingFilter && r.Room.Availability.Value == Filter.Availability;
}
rooms.Filter(Filter.CreateCriteria());
}
private void selectionRequested(DrawableRoom room)
{
if (room.State == SelectionState.Selected)
openRoom(room);
else
{
RoomsContainer.ForEach(c => c.State = c == room ? SelectionState.Selected : SelectionState.NotSelected);
Inspector.Room = room.Room;
}
}
private void openRoom(DrawableRoom room)
private void openRoom(Room room)
{
// Handles the case where a room is clicked 3 times in quick succession
if (!IsCurrentScreen)
return;
RoomsContainer.ForEach(c => c.State = c == room ? SelectionState.Selected : SelectionState.NotSelected);
Inspector.Room = room.Room;
Push(new MatchScreen(room.Room));
}
private class RoomsFilterContainer : FillFlowContainer<DrawableRoom>, IHasFilterableChildren
{
public IEnumerable<string> FilterTerms => new string[] { };
public IEnumerable<IFilterable> FilterableChildren => Children;
public bool MatchingFilter
{
set
{
if (value)
InvalidateLayout();
}
}
public RoomsFilterContainer()
{
LayoutDuration = 200;
LayoutEasing = Easing.OutQuint;
}
Push(new MatchScreen(room));
}
}
}

View File

@ -27,7 +27,6 @@ namespace osu.Game.Screens.Multi.Match.Components
private readonly Bindable<RoomAvailability> availabilityBind = new Bindable<RoomAvailability>();
private readonly Bindable<GameType> typeBind = new Bindable<GameType>();
private readonly Bindable<int?> maxParticipantsBind = new Bindable<int?>();
private readonly Bindable<bool> createdBind = new Bindable<bool>();
private readonly Container content;
@ -39,6 +38,9 @@ namespace osu.Game.Screens.Multi.Match.Components
protected readonly TriangleButton ApplyButton;
protected readonly OsuPasswordTextBox PasswordField;
[Resolved]
private RoomManager manager { get; set; }
[Resolved]
private Room room { get; set; }
@ -162,7 +164,6 @@ namespace osu.Game.Screens.Multi.Match.Components
availabilityBind.BindTo(room.Availability);
typeBind.BindTo(room.Type);
maxParticipantsBind.BindTo(room.MaxParticipants);
createdBind.BindTo(room.Created);
MaxParticipantsField.ReadOnly = true;
PasswordField.ReadOnly = true;
@ -210,8 +211,7 @@ namespace osu.Game.Screens.Multi.Match.Components
else
maxParticipantsBind.Value = null;
// Todo: This should only be set after the room has been created server-side
createdBind.Value = true;
manager.CreateRoom(room);
}
private class SettingsTextBox : OsuTextBox

View File

@ -55,7 +55,7 @@ namespace osu.Game.Screens.Multi
Padding = new MarginPadding { Top = Header.HEIGHT },
Child = loungeScreen = new LoungeScreen(),
},
new Header(loungeScreen),
new Header(loungeScreen)
};
loungeScreen.Exited += s => Exit();

View File

@ -0,0 +1,32 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Allocation;
using osu.Framework.Configuration;
using osu.Framework.Graphics;
using osu.Game.Online.API;
using osu.Game.Online.Multiplayer;
namespace osu.Game.Screens.Multi
{
public class RoomManager : Component
{
public IBindableCollection<Room> Rooms => rooms;
private readonly BindableCollection<Room> rooms = new BindableCollection<Room>();
public readonly Bindable<Room> Current = new Bindable<Room>();
[Resolved]
private APIAccess api { get; set; }
public void CreateRoom(Room room)
{
room.Host.Value = api.LocalUser;
// Todo: Perform API request
room.Created.Value = true;
rooms.Add(room);
}
}
}