1
0
mirror of https://github.com/ppy/osu.git synced 2025-03-15 15:27:20 +08:00

Merge branch 'timeshift'

# Conflicts:
#	osu.Game/osu.Game.csproj
This commit is contained in:
smoogipoo 2018-12-13 17:06:20 +09:00
commit 208273f16a
46 changed files with 976 additions and 735 deletions

View File

@ -9,7 +9,7 @@ using osu.Game.Beatmaps;
using osu.Game.Graphics.UserInterface;
using osu.Game.Online.Multiplayer;
using osu.Game.Rulesets;
using osu.Game.Screens.Multi.Components;
using osu.Game.Screens.Multi.Lounge.Components;
using osu.Game.Users;
namespace osu.Game.Tests.Visual

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,8 +8,9 @@ using osu.Game.Online.Multiplayer;
using osu.Game.Rulesets;
using osu.Game.Screens;
using osu.Game.Screens.Backgrounds;
using osu.Game.Screens.Multi.Components;
using osu.Game.Screens.Multi.Screens.Lounge;
using osu.Game.Screens.Multi;
using osu.Game.Screens.Multi.Lounge;
using osu.Game.Screens.Multi.Lounge.Components;
using osu.Game.Users;
using osuTK.Input;
@ -20,12 +19,12 @@ namespace osu.Game.Tests.Visual
[TestFixture]
public class TestCaseLounge : ManualInputManagerTestCase
{
private TestLounge lounge;
private TestLoungeScreen loungeScreen;
[BackgroundDependencyLoader]
private void load(RulesetStore rulesets)
{
lounge = new TestLounge();
loungeScreen = new TestLoungeScreen();
Room[] rooms =
{
@ -159,52 +158,45 @@ namespace osu.Game.Tests.Visual
},
};
AddStep(@"show", () => Add(lounge));
AddStep(@"set rooms", () => lounge.Rooms = rooms);
AddStep(@"show", () => Add(loungeScreen));
selectAssert(0);
AddStep(@"clear rooms", () => lounge.Rooms = new Room[] {});
AddAssert(@"no room selected", () => lounge.SelectedRoom == null);
AddStep(@"set rooms", () => lounge.Rooms = rooms);
AddAssert(@"no room selected", () => loungeScreen.SelectedRoom == null);
selectAssert(1);
AddStep(@"open room 1", () => clickRoom(1));
AddUntilStep(() => lounge.ChildScreen?.IsCurrentScreen == true, "wait until room current");
AddStep(@"make lounge current", lounge.MakeCurrent);
AddUntilStep(() => loungeScreen.ChildScreen?.IsCurrentScreen == true, "wait until room current");
AddStep(@"make lounge current", loungeScreen.MakeCurrent);
filterAssert(@"THE FINAL", LoungeTab.Public, 1);
filterAssert(string.Empty, LoungeTab.Public, 2);
filterAssert(string.Empty, LoungeTab.Private, 1);
filterAssert(string.Empty, LoungeTab.Public, 2);
filterAssert(@"no matches", LoungeTab.Public, 0);
AddStep(@"clear rooms", () => lounge.Rooms = new Room[] {});
AddStep(@"set rooms", () => lounge.Rooms = rooms);
AddAssert(@"no matches after clear", () => !lounge.ChildRooms.Any());
filterAssert(string.Empty, LoungeTab.Public, 2);
AddStep(@"exit", lounge.Exit);
AddStep(@"exit", loungeScreen.Exit);
}
private void clickRoom(int n)
{
InputManager.MoveMouseTo(lounge.ChildRooms.ElementAt(n));
InputManager.Click(MouseButton.Left);
}
private void selectAssert(int n)
{
AddStep($@"select room {n}", () => clickRoom(n));
AddAssert($@"room {n} selected", () => lounge.SelectedRoom == lounge.ChildRooms.ElementAt(n).Room);
}
private void filterAssert(string filter, LoungeTab tab, int endCount)
{
AddStep($@"filter '{filter}', {tab}", () => lounge.SetFilter(filter, tab));
AddAssert(@"filtered correctly", () => lounge.ChildRooms.Count() == endCount);
AddStep($@"filter '{filter}', {tab}", () => loungeScreen.SetFilter(filter, tab));
}
private class TestLounge : Lounge
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

@ -1,12 +1,15 @@
// 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 NUnit.Framework;
using osu.Framework.Allocation;
using osu.Game.Beatmaps;
using osu.Game.Online.Multiplayer;
using osu.Game.Rulesets;
using osu.Game.Screens.Multi.Screens.Match;
using osu.Game.Screens.Multi.Match;
using osu.Game.Screens.Multi.Match.Components;
using osu.Game.Users;
namespace osu.Game.Tests.Visual
@ -14,6 +17,13 @@ namespace osu.Game.Tests.Visual
[TestFixture]
public class TestCaseMatch : OsuTestCase
{
public override IReadOnlyList<Type> RequiredTypes => new[]
{
typeof(TestCaseMatch),
typeof(GameTypePicker),
typeof(RoomSettingsOverlay)
};
[BackgroundDependencyLoader]
private void load(RulesetStore rulesets)
{
@ -86,9 +96,9 @@ namespace osu.Game.Tests.Visual
},
};
Match match = new Match(room);
MatchScreen matchScreen = new MatchScreen(room);
AddStep(@"show", () => Add(match));
AddStep(@"show", () => Add(matchScreen));
AddStep(@"null beatmap", () => room.Beatmap.Value = null);
AddStep(@"change name", () => room.Name.Value = @"Two Awesome Rooms");
AddStep(@"change status", () => room.Status.Value = new RoomStatusPlaying());
@ -136,7 +146,7 @@ namespace osu.Game.Tests.Visual
},
});
AddStep(@"exit", match.Exit);
AddStep(@"exit", matchScreen.Exit);
}
}
}

View File

@ -1,43 +0,0 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using NUnit.Framework;
using osu.Game.Beatmaps;
using osu.Game.Screens.Multi.Screens.Match;
namespace osu.Game.Tests.Visual
{
[TestFixture]
public class TestCaseMatchHeader : OsuTestCase
{
public TestCaseMatchHeader()
{
Header header = new Header();
Add(header);
AddStep(@"set beatmap set", () => header.BeatmapSet = new BeatmapSetInfo
{
OnlineInfo = new BeatmapSetOnlineInfo
{
Covers = new BeatmapSetOnlineCovers
{
Cover = @"https://assets.ppy.sh/beatmaps/760757/covers/cover.jpg?1526944540",
},
},
});
AddStep(@"change beatmap set", () => header.BeatmapSet = new BeatmapSetInfo
{
OnlineInfo = new BeatmapSetOnlineInfo
{
Covers = new BeatmapSetOnlineCovers
{
Cover = @"https://assets.ppy.sh/beatmaps/761883/covers/cover.jpg?1525557400",
},
},
});
AddStep(@"null beatmap set", () => header.BeatmapSet = null);
}
}
}

View File

@ -6,7 +6,7 @@ using osu.Framework.Allocation;
using osu.Game.Beatmaps;
using osu.Game.Online.Multiplayer;
using osu.Game.Rulesets;
using osu.Game.Screens.Multi.Screens.Match;
using osu.Game.Screens.Multi.Match.Components;
namespace osu.Game.Tests.Visual
{
@ -19,10 +19,10 @@ namespace osu.Game.Tests.Visual
Info info = new Info();
Add(info);
AddStep(@"set name", () => info.Name = @"Room Name?");
AddStep(@"set availability", () => info.Availability = RoomAvailability.FriendsOnly);
AddStep(@"set status", () => info.Status = new RoomStatusPlaying());
AddStep(@"set beatmap", () => info.Beatmap = new BeatmapInfo
AddStep(@"set name", () => info.Name.Value = @"Room Name?");
AddStep(@"set availability", () => info.Availability.Value = RoomAvailability.FriendsOnly);
AddStep(@"set status", () => info.Status.Value = new RoomStatusPlaying());
AddStep(@"set beatmap", () => info.Beatmap.Value = new BeatmapInfo
{
StarDifficulty = 2.4,
Ruleset = rulesets.GetRuleset(0),
@ -34,14 +34,14 @@ namespace osu.Game.Tests.Visual
},
});
AddStep(@"set type", () => info.Type = new GameTypeTagTeam());
AddStep(@"set type", () => info.Type.Value = new GameTypeTagTeam());
AddStep(@"change name", () => info.Name = @"Room Name!");
AddStep(@"change availability", () => info.Availability = RoomAvailability.InviteOnly);
AddStep(@"change status", () => info.Status = new RoomStatusOpen());
AddStep(@"null beatmap", () => info.Beatmap = null);
AddStep(@"change type", () => info.Type = new GameTypeTeamVersus());
AddStep(@"change beatmap", () => info.Beatmap = new BeatmapInfo
AddStep(@"change name", () => info.Name.Value = @"Room Name!");
AddStep(@"change availability", () => info.Availability.Value = RoomAvailability.InviteOnly);
AddStep(@"change status", () => info.Status.Value = new RoomStatusOpen());
AddStep(@"null beatmap", () => info.Beatmap.Value = null);
AddStep(@"change type", () => info.Type.Value = new GameTypeTeamVersus());
AddStep(@"change beatmap", () => info.Beatmap.Value = new BeatmapInfo
{
StarDifficulty = 4.2,
Ruleset = rulesets.GetRuleset(3),

View File

@ -3,7 +3,7 @@
using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Game.Screens.Multi.Screens.Match;
using osu.Game.Screens.Multi.Match.Components;
using osu.Game.Users;
namespace osu.Game.Tests.Visual
@ -19,8 +19,8 @@ namespace osu.Game.Tests.Visual
RelativeSizeAxes = Axes.Both,
});
AddStep(@"set max to null", () => participants.Max = null);
AddStep(@"set users", () => participants.Users = new[]
AddStep(@"set max to null", () => participants.MaxParticipants.Value = null);
AddStep(@"set users", () => participants.Users.Value = new[]
{
new User
{
@ -48,9 +48,9 @@ namespace osu.Game.Tests.Visual
},
});
AddStep(@"set max", () => participants.Max = 10);
AddStep(@"clear users", () => participants.Users = new User[] { });
AddStep(@"set max to null", () => participants.Max = null);
AddStep(@"set max", () => participants.MaxParticipants.Value = 10);
AddStep(@"clear users", () => participants.Users.Value = new User[] { });
AddStep(@"set max to null", () => participants.MaxParticipants.Value = null);
}
}
}

View File

@ -4,7 +4,7 @@
using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Game.Screens.Multi;
using osu.Game.Screens.Multi.Screens.Lounge;
using osu.Game.Screens.Multi.Lounge;
namespace osu.Game.Tests.Visual
{
@ -13,14 +13,14 @@ namespace osu.Game.Tests.Visual
{
public TestCaseMultiHeader()
{
Lounge lounge;
LoungeScreen loungeScreen;
Children = new Drawable[]
{
lounge = new Lounge
loungeScreen = new LoungeScreen
{
Padding = new MarginPadding { Top = Header.HEIGHT },
},
new Header(lounge),
new Header(loungeScreen),
};
}
}

View File

@ -1,14 +1,25 @@
// 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 NUnit.Framework;
using osu.Game.Screens.Multi;
using osu.Game.Screens.Multi.Lounge;
using osu.Game.Screens.Multi.Lounge.Components;
namespace osu.Game.Tests.Visual
{
[TestFixture]
public class TestCaseMultiScreen : OsuTestCase
{
public override IReadOnlyList<Type> RequiredTypes => new[]
{
typeof(Multiplayer),
typeof(LoungeScreen),
typeof(FilterControl)
};
public TestCaseMultiScreen()
{
Multiplayer multi = new Multiplayer();

View File

@ -7,7 +7,7 @@ using osu.Framework.Graphics;
using osu.Game.Beatmaps;
using osu.Game.Online.Multiplayer;
using osu.Game.Rulesets;
using osu.Game.Screens.Multi.Components;
using osu.Game.Screens.Multi.Lounge.Components;
using osu.Game.Users;
namespace osu.Game.Tests.Visual
@ -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

@ -1,11 +1,14 @@
// 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 NUnit.Framework;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Testing.Input;
using osu.Game.Online.Multiplayer;
using osu.Game.Screens.Multi.Screens.Match.Settings;
using osu.Game.Screens.Multi.Match.Components;
using osuTK.Input;
namespace osu.Game.Tests.Visual
@ -13,6 +16,12 @@ namespace osu.Game.Tests.Visual
[TestFixture]
public class TestCaseRoomSettings : ManualInputManagerTestCase
{
public override IReadOnlyList<Type> RequiredTypes => new[]
{
typeof(RoomSettingsOverlay),
typeof(GameTypePicker)
};
private readonly Room room;
private readonly TestRoomSettingsOverlay overlay;
@ -26,13 +35,13 @@ namespace osu.Game.Tests.Visual
MaxParticipants = { Value = 10 },
};
Add(overlay = new TestRoomSettingsOverlay(room)
Add(overlay = new TestRoomSettingsOverlay
{
RelativeSizeAxes = Axes.Both,
Height = 0.75f,
State = Visibility.Visible
});
AddStep(@"show", overlay.Show);
assertAll();
AddStep(@"set name", () => overlay.CurrentName = @"Two Testing Room");
AddStep(@"set max", () => overlay.CurrentMaxParticipants = null);
@ -105,10 +114,6 @@ namespace osu.Game.Tests.Visual
set => TypePicker.Current.Value = value;
}
public TestRoomSettingsOverlay(Room room) : base(room)
{
}
public void ClickApplyButton(ManualInputManager inputManager)
{
inputManager.MoveMouseTo(ApplyButton);

View File

@ -0,0 +1,50 @@
// 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.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
namespace osu.Game.Beatmaps.Drawables
{
public class UpdateableBeatmapBackgroundSprite : ModelBackedDrawable<WorkingBeatmap>
{
public readonly IBindable<WorkingBeatmap> Beatmap = new Bindable<WorkingBeatmap>();
[Resolved]
private OsuGameBase game { get; set; }
public UpdateableBeatmapBackgroundSprite()
{
Beatmap.BindValueChanged(b => Schedule(() => Model = b));
}
protected override Drawable CreateDrawable(WorkingBeatmap model)
{
Drawable drawable = model == null ? (Drawable)new DefaultSprite() : new BeatmapBackgroundSprite(model);
drawable.RelativeSizeAxes = Axes.Both;
drawable.Anchor = Anchor.Centre;
drawable.Origin = Anchor.Centre;
drawable.FillMode = FillMode.Fill;
return drawable;
}
protected override double FadeDuration => 400;
private class DefaultSprite : Sprite
{
[Resolved]
private IBindableBeatmap gameBeatmap { get; set; }
[BackgroundDependencyLoader]
private void load()
{
Texture = gameBeatmap.Default.Background;
}
}
}
}

View File

@ -62,7 +62,7 @@ namespace osu.Game.Graphics.Containers
public void AddLink(string text, string url, LinkAction linkType = LinkAction.External, string linkArgument = null, string tooltipText = null, Action<SpriteText> creationParameters = null)
{
AddInternal(new DrawableLinkCompiler(AddText(text, creationParameters).ToList())
AddInternal(new DrawableLinkCompiler(AddText(text, creationParameters).OfType<SpriteText>().ToList())
{
TooltipText = tooltipText ?? (url != text ? url : string.Empty),
Action = () =>

View File

@ -13,6 +13,7 @@ namespace osu.Game.Online.Multiplayer
public abstract class GameType
{
public abstract string Name { get; }
public abstract Drawable GetIcon(OsuColour colours, float size);
public override int GetHashCode() => GetType().GetHashCode();
@ -22,6 +23,7 @@ namespace osu.Game.Online.Multiplayer
public class GameTypeTag : GameType
{
public override string Name => "Tag";
public override Drawable GetIcon(OsuColour colours, float size)
{
return new SpriteIcon
@ -39,6 +41,7 @@ namespace osu.Game.Online.Multiplayer
public class GameTypeVersus : GameType
{
public override string Name => "Versus";
public override Drawable GetIcon(OsuColour colours, float size)
{
return new VersusRow(colours.Blue, colours.Blue, size * 0.6f)
@ -52,6 +55,7 @@ namespace osu.Game.Online.Multiplayer
public class GameTypeTagTeam : GameType
{
public override string Name => "Tag Team";
public override Drawable GetIcon(OsuColour colours, float size)
{
return new FillFlowContainer
@ -85,6 +89,7 @@ namespace osu.Game.Online.Multiplayer
public class GameTypeTeamVersus : GameType
{
public override string Name => "Team Versus";
public override Drawable GetIcon(OsuColour colours, float size)
{
return new FillFlowContainer
@ -146,4 +151,20 @@ namespace osu.Game.Online.Multiplayer
};
}
}
public class GameTypeTimeshift : GameType
{
public override string Name => "Timeshift";
public override Drawable GetIcon(OsuColour colours, float size) => new SpriteIcon
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Icon = FontAwesome.fa_osu_charts,
X = -2, // The icon is off-centre
Size = new Vector2(size),
Colour = colours.Blue,
Shadow = false
};
}
}

View File

@ -2,6 +2,7 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Configuration;
using osu.Game.Beatmaps;
using osu.Game.Users;
@ -10,13 +11,15 @@ namespace osu.Game.Online.Multiplayer
{
public class Room
{
public Bindable<string> Name = new Bindable<string>();
public Bindable<string> Name = new Bindable<string>("My awesome room!");
public Bindable<User> Host = new Bindable<User>();
public Bindable<RoomStatus> Status = new Bindable<RoomStatus>();
public Bindable<RoomStatus> Status = new Bindable<RoomStatus>(new RoomStatusOpen());
public Bindable<RoomAvailability> Availability = new Bindable<RoomAvailability>();
public Bindable<GameType> Type = new Bindable<GameType>();
public Bindable<GameType> Type = new Bindable<GameType>(new GameTypeTimeshift());
public Bindable<BeatmapInfo> Beatmap = new Bindable<BeatmapInfo>();
public Bindable<int?> MaxParticipants = new Bindable<int?>();
public Bindable<IEnumerable<User>> Participants = new Bindable<IEnumerable<User>>();
public Bindable<IEnumerable<User>> Participants = new Bindable<IEnumerable<User>>(Enumerable.Empty<User>());
public Bindable<bool> Created = new Bindable<bool>();
}
}

View File

@ -259,7 +259,7 @@ namespace osu.Game
RegisterAudioManager(audioManager);
}
private OsuBindableBeatmap(WorkingBeatmap defaultValue)
public OsuBindableBeatmap(WorkingBeatmap defaultValue)
: base(defaultValue)
{
}

View File

@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using osuTK.Graphics;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
@ -110,7 +111,7 @@ namespace osu.Game.Overlays.Music
{
sprite.TextSize = 16;
sprite.Font = @"Exo2.0-Regular";
});
}).OfType<SpriteText>();
text.AddText(artistBind.Value, sprite =>
{

View File

@ -17,7 +17,9 @@ using osu.Framework.Threading;
using osu.Game.Graphics;
using osu.Game.Input;
using osu.Game.Input.Bindings;
using osu.Game.Online.API;
using osu.Game.Overlays;
using osu.Game.Overlays.Notifications;
using osuTK;
using osuTK.Graphics;
using osuTK.Input;
@ -90,7 +92,7 @@ namespace osu.Game.Screens.Menu
buttonArea.Flow.CentreTarget = iconFacade;
buttonsPlay.Add(new Button(@"solo", @"button-solo-select", FontAwesome.fa_user, new Color4(102, 68, 204, 255), () => OnSolo?.Invoke(), WEDGE_WIDTH, Key.P));
buttonsPlay.Add(new Button(@"multi", @"button-generic-select", FontAwesome.fa_users, new Color4(94, 63, 186, 255), () => OnMulti?.Invoke(), 0, Key.M));
buttonsPlay.Add(new Button(@"multi", @"button-generic-select", FontAwesome.fa_users, new Color4(94, 63, 186, 255), onMulti, 0, Key.M));
buttonsPlay.Add(new Button(@"chart", @"button-generic-select", FontAwesome.fa_osu_charts, new Color4(80, 53, 160, 255), () => OnChart?.Invoke()));
buttonsPlay.ForEach(b => b.VisibleState = ButtonSystemState.Play);
@ -103,19 +105,40 @@ namespace osu.Game.Screens.Menu
buttonArea.AddRange(buttonsTopLevel);
}
private OsuGame game;
[Resolved]
private OsuGame game { get; set; }
[Resolved]
private APIAccess api { get; set; }
[Resolved]
private NotificationOverlay notifications { get; set; }
[BackgroundDependencyLoader(true)]
private void load(AudioManager audio, OsuGame game, IdleTracker idleTracker)
private void load(AudioManager audio, IdleTracker idleTracker)
{
this.game = game;
isIdle.ValueChanged += updateIdleState;
if (idleTracker != null) isIdle.BindTo(idleTracker.IsIdle);
sampleBack = audio.Sample.Get(@"Menu/button-back-select");
}
private void onMulti()
{
if (!api.IsLoggedIn)
{
notifications.Post(new SimpleNotification
{
Text = "You gotta be logged in to multi 'yo!",
Icon = FontAwesome.fa_globe
});
return;
}
OnMulti?.Invoke();
}
private void updateIdleState(bool isIdle)
{
if (isIdle && State != ButtonSystemState.Exit)

View File

@ -1,6 +1,7 @@
// 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.Configuration;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Localisation;
@ -9,7 +10,7 @@ using osu.Game.Graphics.Sprites;
namespace osu.Game.Screens.Multi.Components
{
public class BeatmapTitle : FillFlowContainer<OsuSpriteText>
public class BeatmapTitle : CompositeDrawable
{
private readonly OsuSpriteText beatmapTitle, beatmapDash, beatmapArtist;
@ -18,31 +19,25 @@ namespace osu.Game.Screens.Multi.Components
set { beatmapTitle.TextSize = beatmapDash.TextSize = beatmapArtist.TextSize = value; }
}
private BeatmapInfo beatmap;
public BeatmapInfo Beatmap
{
set
{
if (value == beatmap) return;
beatmap = value;
if (IsLoaded)
updateText();
}
}
public readonly Bindable<BeatmapInfo> Beatmap = new Bindable<BeatmapInfo>();
public BeatmapTitle()
{
AutoSizeAxes = Axes.Both;
Direction = FillDirection.Horizontal;
Children = new[]
InternalChild = new FillFlowContainer
{
beatmapTitle = new OsuSpriteText { Font = @"Exo2.0-BoldItalic", },
beatmapDash = new OsuSpriteText { Font = @"Exo2.0-BoldItalic", },
beatmapArtist = new OsuSpriteText { Font = @"Exo2.0-RegularItalic", },
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Horizontal,
Children = new[]
{
beatmapTitle = new OsuSpriteText { Font = @"Exo2.0-BoldItalic", },
beatmapDash = new OsuSpriteText { Font = @"Exo2.0-BoldItalic", },
beatmapArtist = new OsuSpriteText { Font = @"Exo2.0-RegularItalic", },
}
};
Beatmap.BindValueChanged(v => updateText());
}
protected override void LoadComplete()
@ -53,16 +48,19 @@ namespace osu.Game.Screens.Multi.Components
private void updateText()
{
if (beatmap == null)
if (!IsLoaded)
return;
if (Beatmap.Value == null)
{
beatmapTitle.Text = "Changing map";
beatmapDash.Text = beatmapArtist.Text = string.Empty;
}
else
{
beatmapTitle.Text = new LocalisedString((beatmap.Metadata.TitleUnicode, beatmap.Metadata.Title));
beatmapTitle.Text = new LocalisedString((Beatmap.Value.Metadata.TitleUnicode, Beatmap.Value.Metadata.Title));
beatmapDash.Text = @" - ";
beatmapArtist.Text = new LocalisedString((beatmap.Metadata.ArtistUnicode, beatmap.Metadata.Artist));
beatmapArtist.Text = new LocalisedString((Beatmap.Value.Metadata.ArtistUnicode, Beatmap.Value.Metadata.Artist));
}
}
}

View File

@ -2,6 +2,7 @@
// 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.Framework.Graphics.Containers;
using osu.Game.Beatmaps;
@ -12,53 +13,55 @@ using osuTK;
namespace osu.Game.Screens.Multi.Components
{
public class BeatmapTypeInfo : FillFlowContainer
public class BeatmapTypeInfo : CompositeDrawable
{
private readonly ModeTypeInfo modeTypeInfo;
private readonly BeatmapTitle beatmapTitle;
private readonly OsuSpriteText beatmapAuthor;
public BeatmapInfo Beatmap
{
set
{
modeTypeInfo.Beatmap = beatmapTitle.Beatmap = value;
beatmapAuthor.Text = value == null ? string.Empty : $"mapped by {value.Metadata.Author}";
}
}
public readonly Bindable<BeatmapInfo> Beatmap = new Bindable<BeatmapInfo>();
public GameType Type
{
set { modeTypeInfo.Type = value; }
}
public readonly Bindable<GameType> Type = new Bindable<GameType>();
public BeatmapTypeInfo()
{
AutoSizeAxes = Axes.Both;
Direction = FillDirection.Horizontal;
LayoutDuration = 100;
Spacing = new Vector2(5f, 0f);
Children = new Drawable[]
BeatmapTitle beatmapTitle;
ModeTypeInfo modeTypeInfo;
InternalChild = new FillFlowContainer
{
modeTypeInfo = new ModeTypeInfo(),
new Container
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Horizontal,
LayoutDuration = 100,
Spacing = new Vector2(5, 0),
Children = new Drawable[]
{
AutoSizeAxes = Axes.X,
Height = 30,
Margin = new MarginPadding { Left = 5 },
Children = new Drawable[]
modeTypeInfo = new ModeTypeInfo(),
new Container
{
beatmapTitle = new BeatmapTitle(),
beatmapAuthor = new OsuSpriteText
AutoSizeAxes = Axes.X,
Height = 30,
Margin = new MarginPadding { Left = 5 },
Children = new Drawable[]
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
TextSize = 14,
beatmapTitle = new BeatmapTitle(),
beatmapAuthor = new OsuSpriteText
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
TextSize = 14,
},
},
},
},
}
};
modeTypeInfo.Beatmap.BindTo(Beatmap);
modeTypeInfo.Type.BindTo(Type);
beatmapTitle.Beatmap.BindTo(Beatmap);
Beatmap.BindValueChanged(v => beatmapAuthor.Text = v == null ? string.Empty : $"mapped by {v.Metadata.Author}");
}
[BackgroundDependencyLoader]

View File

@ -0,0 +1,45 @@
// 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.Configuration;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Input.Events;
using osuTK.Graphics;
namespace osu.Game.Screens.Multi.Components
{
public abstract class DisableableTabControl<T> : TabControl<T>
{
public readonly BindableBool ReadOnly = new BindableBool();
protected override void AddTabItem(TabItem<T> tab, bool addToDropdown = true)
{
if (tab is DisableableTabItem<T> disableable)
disableable.ReadOnly.BindTo(ReadOnly);
base.AddTabItem(tab, addToDropdown);
}
protected abstract class DisableableTabItem<T> : TabItem<T>
{
public readonly BindableBool ReadOnly = new BindableBool();
protected DisableableTabItem(T value)
: base(value)
{
ReadOnly.BindValueChanged(updateReadOnly);
}
private void updateReadOnly(bool readOnly)
{
Colour = readOnly ? Color4.Gray : Color4.White;
}
protected override bool OnClick(ClickEvent e)
{
if (ReadOnly)
return true;
return base.OnClick(e);
}
}
}
}

View File

@ -1,6 +1,7 @@
// 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.Configuration;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Beatmaps;
@ -10,74 +11,54 @@ using osuTK;
namespace osu.Game.Screens.Multi.Components
{
public class ModeTypeInfo : Container
public class ModeTypeInfo : CompositeDrawable
{
private const float height = 30;
private const float transition_duration = 100;
private readonly Container rulesetContainer, gameTypeContainer;
private readonly Container rulesetContainer;
public BeatmapInfo Beatmap
{
set
{
if (value != null)
{
rulesetContainer.FadeIn(transition_duration);
rulesetContainer.Children = new[]
{
new DifficultyIcon(value)
{
Size = new Vector2(height),
},
};
}
else
{
rulesetContainer.FadeOut(transition_duration);
}
}
}
public GameType Type
{
set
{
gameTypeContainer.Children = new[]
{
new DrawableGameType(value)
{
Size = new Vector2(height),
},
};
}
}
public readonly Bindable<BeatmapInfo> Beatmap = new Bindable<BeatmapInfo>();
public readonly Bindable<GameType> Type = new Bindable<GameType>();
public ModeTypeInfo()
{
AutoSizeAxes = Axes.Both;
Children = new[]
Container gameTypeContainer;
InternalChild = new FillFlowContainer
{
new FillFlowContainer
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Horizontal,
Spacing = new Vector2(5f, 0f),
LayoutDuration = 100,
Children = new[]
{
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Horizontal,
Spacing = new Vector2(5f, 0f),
LayoutDuration = 100,
Children = new[]
rulesetContainer = new Container
{
rulesetContainer = new Container
{
AutoSizeAxes = Axes.Both,
},
gameTypeContainer = new Container
{
AutoSizeAxes = Axes.Both,
},
AutoSizeAxes = Axes.Both,
},
gameTypeContainer = new Container
{
AutoSizeAxes = Axes.Both,
},
},
};
Beatmap.BindValueChanged(updateBeatmap);
Type.BindValueChanged(v => gameTypeContainer.Child = new DrawableGameType(v) { Size = new Vector2(height) });
}
private void updateBeatmap(BeatmapInfo beatmap)
{
if (beatmap != null)
{
rulesetContainer.FadeIn(transition_duration);
rulesetContainer.Child = new DifficultyIcon(beatmap) { Size = new Vector2(height) };
}
else
rulesetContainer.FadeOut(transition_duration);
}
}
}

View File

@ -1,69 +1,65 @@
// 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 osu.Framework.Configuration;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Graphics.Sprites;
using osu.Game.Users;
namespace osu.Game.Screens.Multi.Components
{
public class ParticipantCount : FillFlowContainer
public class ParticipantCount : CompositeDrawable
{
private const float text_size = 30;
private const float transition_duration = 100;
private readonly OsuSpriteText count, slash, maxText;
private readonly OsuSpriteText slash, maxText;
public int Count
{
set => count.Text = value.ToString();
}
private int? max;
public int? Max
{
get => max;
set
{
if (value == max) return;
max = value;
updateMax();
}
}
public readonly Bindable<IEnumerable<User>> Participants = new Bindable<IEnumerable<User>>();
public readonly Bindable<int?> MaxParticipants = new Bindable<int?>();
public ParticipantCount()
{
AutoSizeAxes = Axes.Both;
Direction = FillDirection.Horizontal;
LayoutDuration = transition_duration;
Children = new[]
OsuSpriteText count;
InternalChild = new FillFlowContainer
{
count = new OsuSpriteText
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Horizontal,
LayoutDuration = transition_duration,
Children = new[]
{
TextSize = text_size,
Font = @"Exo2.0-Bold"
},
slash = new OsuSpriteText
{
Text = @"/",
TextSize = text_size,
Font = @"Exo2.0-Light"
},
maxText = new OsuSpriteText
{
TextSize = text_size,
Font = @"Exo2.0-Light"
},
count = new OsuSpriteText
{
TextSize = text_size,
Font = @"Exo2.0-Bold"
},
slash = new OsuSpriteText
{
Text = @"/",
TextSize = text_size,
Font = @"Exo2.0-Light"
},
maxText = new OsuSpriteText
{
TextSize = text_size,
Font = @"Exo2.0-Light"
},
}
};
updateMax();
Participants.BindValueChanged(v => count.Text = v.Count().ToString());
MaxParticipants.BindValueChanged(_ => updateMax(), true);
}
private void updateMax()
{
if (Max == null)
if (MaxParticipants.Value == null)
{
slash.FadeOut(transition_duration);
maxText.FadeOut(transition_duration);
@ -71,7 +67,7 @@ namespace osu.Game.Screens.Multi.Components
else
{
slash.FadeIn(transition_duration);
maxText.Text = Max.ToString();
maxText.Text = MaxParticipants.Value.ToString();
maxText.FadeIn(transition_duration);
}
}

View File

@ -10,7 +10,6 @@ using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
using osu.Game.Overlays.SearchableList;
using osu.Game.Screens.Multi.Screens;
using osuTK;
using osuTK.Graphics;
@ -86,7 +85,7 @@ namespace osu.Game.Screens.Multi
},
};
breadcrumbs.Current.ValueChanged += s => screenType.Text = ((MultiplayerScreen)s).Type.ToLowerInvariant();
breadcrumbs.Current.ValueChanged += s => screenType.Text = ((IMultiplayerScreen)s).ShortTitle.ToLowerInvariant();
breadcrumbs.Current.TriggerChange();
}

View File

@ -0,0 +1,10 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
namespace osu.Game.Screens.Multi
{
public interface IMultiplayerScreen
{
string ShortTitle { get; }
}
}

View File

@ -10,7 +10,6 @@ using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Input.Events;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Drawables;
using osu.Game.Graphics;
@ -18,11 +17,12 @@ using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
using osu.Game.Online.Multiplayer;
using osu.Game.Screens.Multi.Components;
using osu.Game.Users;
using osuTK;
using osuTK.Graphics;
namespace osu.Game.Screens.Multi.Components
namespace osu.Game.Screens.Multi.Lounge.Components
{
public class DrawableRoom : OsuClickableContainer, IStateful<SelectionState>, IFilterable
{
@ -34,15 +34,22 @@ namespace osu.Game.Screens.Multi.Components
private const float side_strip_width = 5;
private const float cover_width = 145;
public event Action<SelectionState> StateChanged;
private readonly Box selectionBox;
private readonly Bindable<string> nameBind = new Bindable<string>();
private readonly Bindable<BeatmapInfo> beatmapBind = new Bindable<BeatmapInfo>();
private readonly Bindable<User> hostBind = new Bindable<User>();
private readonly Bindable<RoomStatus> statusBind = new Bindable<RoomStatus>();
private readonly Bindable<GameType> typeBind = new Bindable<GameType>();
private readonly Bindable<BeatmapInfo> beatmapBind = new Bindable<BeatmapInfo>();
private readonly Bindable<IEnumerable<User>> participantsBind = new Bindable<IEnumerable<User>>();
private readonly Bindable<WorkingBeatmap> beatmap = new Bindable<WorkingBeatmap>();
[Resolved]
private BeatmapManager beatmaps { get; set; }
public readonly Room Room;
private SelectionState state;
@ -76,19 +83,6 @@ namespace osu.Game.Screens.Multi.Components
}
}
private Action<DrawableRoom> action;
public new Action<DrawableRoom> Action
{
get { return action; }
set
{
action = value;
Enabled.Value = action != null;
}
}
public event Action<SelectionState> StateChanged;
public DrawableRoom(Room room)
{
Room = room;
@ -110,11 +104,12 @@ namespace osu.Game.Screens.Multi.Components
private void load(OsuColour colours)
{
Box sideStrip;
UpdateableBeatmapSetCover cover;
OsuSpriteText name, status;
UpdateableBeatmapBackgroundSprite background;
OsuSpriteText status;
ParticipantInfo participantInfo;
BeatmapTitle beatmapTitle;
ModeTypeInfo modeTypeInfo;
OsuSpriteText name;
Children = new Drawable[]
{
@ -146,12 +141,13 @@ namespace osu.Game.Screens.Multi.Components
RelativeSizeAxes = Axes.Y,
Width = side_strip_width,
},
cover = new UpdateableBeatmapSetCover
new Container
{
Width = cover_width,
RelativeSizeAxes = Axes.Y,
Width = cover_width,
Masking = true,
Margin = new MarginPadding { Left = side_strip_width },
Child = background = new UpdateableBeatmapBackgroundSprite { RelativeSizeAxes = Axes.Both }
},
new Container
{
@ -172,10 +168,7 @@ namespace osu.Game.Screens.Multi.Components
Spacing = new Vector2(5f),
Children = new Drawable[]
{
name = new OsuSpriteText
{
TextSize = 18,
},
name = new OsuSpriteText { TextSize = 18 },
participantInfo = new ParticipantInfo(),
},
},
@ -212,11 +205,6 @@ namespace osu.Game.Screens.Multi.Components
},
};
nameBind.ValueChanged += n => name.Text = n;
hostBind.ValueChanged += h => participantInfo.Host = h;
typeBind.ValueChanged += m => modeTypeInfo.Type = m;
participantsBind.ValueChanged += p => participantInfo.Participants = p;
statusBind.ValueChanged += s =>
{
status.Text = s.Message;
@ -225,12 +213,10 @@ namespace osu.Game.Screens.Multi.Components
d.FadeColour(s.GetAppropriateColour(colours), transition_duration);
};
beatmapBind.ValueChanged += b =>
{
cover.BeatmapSet = b?.BeatmapSet;
beatmapTitle.Beatmap = b;
modeTypeInfo.Beatmap = b;
};
background.Beatmap.BindTo(beatmap);
beatmapBind.BindValueChanged(b => beatmap.Value = beatmaps.GetWorkingBeatmap(b));
nameBind.BindValueChanged(n => name.Text = n);
nameBind.BindTo(Room.Name);
hostBind.BindTo(Room.Host);
@ -238,6 +224,14 @@ namespace osu.Game.Screens.Multi.Components
typeBind.BindTo(Room.Type);
beatmapBind.BindTo(Room.Beatmap);
participantsBind.BindTo(Room.Participants);
modeTypeInfo.Beatmap.BindTo(beatmapBind);
modeTypeInfo.Type.BindTo(typeBind);
participantInfo.Host.BindTo(hostBind);
participantInfo.Participants.BindTo(participantsBind);
beatmapTitle.Beatmap.BindTo(beatmapBind);
}
protected override void LoadComplete()
@ -245,16 +239,5 @@ namespace osu.Game.Screens.Multi.Components
base.LoadComplete();
this.FadeInFromZero(transition_duration);
}
protected override bool OnClick(ClickEvent e)
{
if (Enabled.Value)
{
Action?.Invoke(this);
State = SelectionState.Selected;
}
return true;
}
}
}

View File

@ -6,7 +6,7 @@ using osu.Game.Online.Multiplayer;
using osu.Game.Overlays.SearchableList;
using osuTK.Graphics;
namespace osu.Game.Screens.Multi.Screens.Lounge
namespace osu.Game.Screens.Multi.Lounge.Components
{
public class FilterControl : SearchableListFilterControl<LoungeTab, LoungeTab>
{
@ -17,11 +17,29 @@ namespace osu.Game.Screens.Multi.Screens.Lounge
{
DisplayStyleControl.Hide();
}
public FilterCriteria CreateCriteria() => new FilterCriteria { Availability = availability };
private RoomAvailability availability
{
get
{
switch (Tabs.Current.Value)
{
default:
case LoungeTab.Public:
return RoomAvailability.Public;
case LoungeTab.Private:
return RoomAvailability.FriendsOnly;
}
}
}
}
public enum LoungeTab
{
Public = RoomAvailability.Public,
Private = RoomAvailability.FriendsOnly,
Create,
Public,
Private,
}
}

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

@ -4,6 +4,7 @@
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Configuration;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
@ -12,40 +13,25 @@ using osu.Game.Graphics.Sprites;
using osu.Game.Users;
using osuTK;
namespace osu.Game.Screens.Multi.Components
namespace osu.Game.Screens.Multi.Lounge.Components
{
public class ParticipantInfo : Container
{
private readonly Container flagContainer;
private readonly OsuSpriteText host;
private readonly FillFlowContainer levelRangeContainer;
private readonly OsuSpriteText levelRangeLower;
private readonly OsuSpriteText levelRangeHigher;
public User Host
{
set
{
host.Text = value.Username;
flagContainer.Children = new[] { new DrawableFlag(value.Country) { RelativeSizeAxes = Axes.Both } };
}
}
public IEnumerable<User> Participants
{
set
{
var ranks = value.Select(u => u.Statistics.Ranks.Global);
levelRangeLower.Text = ranks.Min().ToString();
levelRangeHigher.Text = ranks.Max().ToString();
}
}
public readonly Bindable<User> Host = new Bindable<User>();
public readonly Bindable<IEnumerable<User>> Participants = new Bindable<IEnumerable<User>>();
public ParticipantInfo(string rankPrefix = null)
{
RelativeSizeAxes = Axes.X;
Height = 15f;
OsuSpriteText levelRangeHigher;
OsuSpriteText levelRangeLower;
Container flagContainer;
Children = new Drawable[]
{
new FillFlowContainer
@ -133,6 +119,19 @@ namespace osu.Game.Screens.Multi.Components
},
},
};
Host.BindValueChanged(v =>
{
host.Text = v.Username;
flagContainer.Child = new DrawableFlag(v.Country) { RelativeSizeAxes = Axes.Both };
});
Participants.BindValueChanged(v =>
{
var ranks = v.Select(u => u.Statistics.Ranks.Global);
levelRangeLower.Text = ranks.Min().ToString();
levelRangeHigher.Text = ranks.Max().ToString();
});
}
[BackgroundDependencyLoader]

View File

@ -17,28 +17,33 @@ using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites;
using osu.Game.Online.Multiplayer;
using osu.Game.Screens.Multi.Components;
using osu.Game.Users;
using osuTK;
using osuTK.Graphics;
namespace osu.Game.Screens.Multi.Components
namespace osu.Game.Screens.Multi.Lounge.Components
{
public class RoomInspector : Container
{
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>();
private readonly Bindable<User> hostBind = new Bindable<User>();
private readonly Bindable<RoomStatus> statusBind = new Bindable<RoomStatus>();
private readonly Bindable<GameType> typeBind = new Bindable<GameType>();
private readonly Bindable<BeatmapInfo> beatmapBind = new Bindable<BeatmapInfo>();
private readonly Bindable<int?> maxParticipantsBind = new Bindable<int?>();
private readonly Bindable<IEnumerable<User>> participantsBind = new Bindable<IEnumerable<User>>();
private readonly Bindable<WorkingBeatmap> beatmap = new Bindable<WorkingBeatmap>();
private OsuColour colours;
private Box statusStrip;
private UpdateableBeatmapSetCover cover;
private UpdateableBeatmapBackgroundSprite background;
private ParticipantCount participantCount;
private FillFlowContainer topFlow, participantsFlow;
private OsuSpriteText name, status;
@ -46,37 +51,8 @@ namespace osu.Game.Screens.Multi.Components
private ScrollContainer participantsScroll;
private ParticipantInfo participantInfo;
private Room room;
public Room Room
{
get { return room; }
set
{
if (value == room) return;
room = value;
nameBind.UnbindBindings();
hostBind.UnbindBindings();
statusBind.UnbindBindings();
typeBind.UnbindBindings();
beatmapBind.UnbindBindings();
maxParticipantsBind.UnbindBindings();
participantsBind.UnbindBindings();
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();
}
}
[Resolved]
private BeatmapManager beatmaps { get; set; }
[BackgroundDependencyLoader]
private void load(OsuColour colours)
@ -104,10 +80,7 @@ namespace osu.Game.Screens.Multi.Components
Masking = true,
Children = new Drawable[]
{
cover = new UpdateableBeatmapSetCover
{
RelativeSizeAxes = Axes.Both,
},
background = new UpdateableBeatmapBackgroundSprite { RelativeSizeAxes = Axes.Both },
new Box
{
RelativeSizeAxes = Axes.Both,
@ -201,26 +174,69 @@ namespace osu.Game.Screens.Multi.Components
},
};
nameBind.ValueChanged += n => name.Text = n;
hostBind.ValueChanged += h => participantInfo.Host = h;
typeBind.ValueChanged += t => beatmapTypeInfo.Type = t;
maxParticipantsBind.ValueChanged += m => participantCount.Max = m;
statusBind.ValueChanged += displayStatus;
statusBind.BindValueChanged(displayStatus);
beatmapBind.BindValueChanged(b => beatmap.Value = beatmaps.GetWorkingBeatmap(b));
participantsBind.BindValueChanged(p => participantsFlow.ChildrenEnumerable = p.Select(u => new UserTile(u)));
beatmapBind.ValueChanged += b =>
nameBind.BindValueChanged(n => name.Text = n);
background.Beatmap.BindTo(beatmap);
participantInfo.Host.BindTo(hostBind);
participantInfo.Participants.BindTo(participantsBind);
participantCount.Participants.BindTo(participantsBind);
participantCount.MaxParticipants.BindTo(maxParticipantsBind);
beatmapTypeInfo.Type.BindTo(typeBind);
beatmapTypeInfo.Beatmap.BindTo(beatmapBind);
Room.BindValueChanged(updateRoom, true);
}
private Room lastRoom;
private void updateRoom(Room newRoom)
{
if (lastRoom != null)
{
cover.BeatmapSet = b?.BeatmapSet;
beatmapTypeInfo.Beatmap = b;
};
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);
}
participantsBind.ValueChanged += p =>
if (newRoom != null)
{
participantCount.Count = p.Count();
participantInfo.Participants = p;
participantsFlow.ChildrenEnumerable = p.Select(u => new UserTile(u));
};
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);
updateState();
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()
@ -239,32 +255,6 @@ namespace osu.Game.Screens.Multi.Components
status.FadeColour(c, transition_duration);
}
private void updateState()
{
if (Room == null)
{
cover.BeatmapSet = 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,62 +1,40 @@
// 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 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.Components;
using osuTK;
using osu.Game.Screens.Multi.Lounge.Components;
using osu.Game.Screens.Multi.Match;
namespace osu.Game.Screens.Multi.Screens.Lounge
namespace osu.Game.Screens.Multi.Lounge
{
public class Lounge : MultiplayerScreen
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";
protected override Container<Drawable> TransitionContent => content;
protected override Drawable TransitionContent => content;
private IEnumerable<Room> rooms;
public IEnumerable<Room> Rooms
public LoungeScreen()
{
get { return rooms; }
set
{
if (Equals(value, rooms)) return;
rooms = value;
RoomInspector inspector;
var enumerable = rooms.ToList();
RoomsContainer.Children = enumerable.Select(r => new DrawableRoom(r)
{
Action = didSelect,
}).ToList();
if (!enumerable.Contains(Inspector.Room))
Inspector.Room = null;
filterRooms();
}
}
public Lounge()
{
Children = new Drawable[]
{
Filter = new FilterControl(),
Filter = new FilterControl { Depth = -1 },
content = new Container
{
RelativeSizeAxes = Axes.Both,
@ -75,16 +53,10 @@ namespace osu.Game.Screens.Multi.Screens.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,
@ -93,8 +65,11 @@ namespace osu.Game.Screens.Multi.Screens.Lounge
},
},
},
manager = new RoomManager()
};
inspector.Room.BindTo(manager.Current);
Filter.Search.Current.ValueChanged += s => filterRooms();
Filter.Tabs.Current.ValueChanged += t => filterRooms();
Filter.Search.Exit += Exit;
@ -132,6 +107,7 @@ namespace osu.Game.Screens.Multi.Screens.Lounge
protected override void OnResuming(Screen last)
{
base.OnResuming(last);
Filter.Search.HoldFocus = true;
}
@ -143,49 +119,24 @@ namespace osu.Game.Screens.Multi.Screens.Lounge
private void filterRooms()
{
if (Filter.Tabs.Current.Value == LoungeTab.Create)
{
Filter.Tabs.Current.Value = LoungeTab.Public;
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 == (RoomAvailability)Filter.Tabs.Current.Value;
}
rooms.Filter(Filter.CreateCriteria());
}
private void didSelect(DrawableRoom room)
private void openRoom(Room room)
{
RoomsContainer.Children.ForEach(c =>
{
if (c != room)
c.State = SelectionState.NotSelected;
});
// Handles the case where a room is clicked 3 times in quick succession
if (!IsCurrentScreen)
return;
Inspector.Room = room.Room;
// open the room if its selected and is clicked again
if (room.State == SelectionState.Selected)
Push(new Match.Match(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

@ -12,14 +12,15 @@ using osu.Game.Online.Multiplayer;
using osu.Game.Screens.Multi.Components;
using osuTK;
namespace osu.Game.Screens.Multi.Screens.Match.Settings
namespace osu.Game.Screens.Multi.Match.Components
{
public class GameTypePicker : TabControl<GameType>
public class GameTypePicker : DisableableTabControl<GameType>
{
private const float height = 40;
private const float selection_width = 3;
protected override TabItem<GameType> CreateTabItem(GameType value) => new GameTypePickerItem(value);
protected override Dropdown<GameType> CreateDropdown() => null;
public GameTypePicker()
@ -31,15 +32,17 @@ namespace osu.Game.Screens.Multi.Screens.Match.Settings
AddItem(new GameTypeVersus());
AddItem(new GameTypeTagTeam());
AddItem(new GameTypeTeamVersus());
AddItem(new GameTypeTimeshift());
}
private class GameTypePickerItem : TabItem<GameType>
private class GameTypePickerItem : DisableableTabItem<GameType>
{
private const float transition_duration = 200;
private readonly CircularContainer hover, selection;
public GameTypePickerItem(GameType value) : base(value)
public GameTypePickerItem(GameType value)
: base(value)
{
AutoSizeAxes = Axes.Both;

View File

@ -3,36 +3,31 @@
using System;
using osu.Framework.Allocation;
using osu.Framework.Configuration;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Input.Events;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Drawables;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
using osu.Game.Online.Multiplayer;
using osu.Game.Overlays.SearchableList;
using osuTK.Graphics;
namespace osu.Game.Screens.Multi.Screens.Match
namespace osu.Game.Screens.Multi.Match.Components
{
public class Header : Container
{
public const float HEIGHT = 200;
public readonly IBindable<WorkingBeatmap> Beatmap = new Bindable<WorkingBeatmap>();
private readonly Box tabStrip;
private readonly UpdateableBeatmapSetCover cover;
public readonly PageTabControl<MatchHeaderPage> Tabs;
public BeatmapSetInfo BeatmapSet
{
set => cover.BeatmapSet = value;
}
public readonly MatchTabControl Tabs;
public Action OnRequestSelectBeatmap;
@ -42,12 +37,14 @@ namespace osu.Game.Screens.Multi.Screens.Match
Height = HEIGHT;
BeatmapSelectButton beatmapButton;
UpdateableBeatmapBackgroundSprite background;
Children = new Drawable[]
{
cover = new UpdateableBeatmapSetCover
new Container
{
RelativeSizeAxes = Axes.Both,
Masking = true,
Child = background = new HeaderBeatmapBackgroundSprite { RelativeSizeAxes = Axes.Both }
},
new Box
{
@ -77,19 +74,22 @@ namespace osu.Game.Screens.Multi.Screens.Match
Child = beatmapButton = new BeatmapSelectButton
{
RelativeSizeAxes = Axes.Both,
Height = 1
},
},
Tabs = new PageTabControl<MatchHeaderPage>
Tabs = new MatchTabControl
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
RelativeSizeAxes = Axes.X,
RelativeSizeAxes = Axes.X
},
},
},
};
beatmapButton.Action = () => OnRequestSelectBeatmap?.Invoke();
background.Beatmap.BindTo(Beatmap);
}
[BackgroundDependencyLoader]
@ -98,87 +98,29 @@ namespace osu.Game.Screens.Multi.Screens.Match
tabStrip.Colour = colours.Yellow;
}
private class BeatmapSelectButton : OsuClickableContainer
private class BeatmapSelectButton : TriangleButton
{
private const float corner_radius = 5;
private const float bg_opacity = 0.5f;
private const float transition_duration = 100;
private readonly IBindable<bool> createdBind = new Bindable<bool>();
private readonly Box bg;
private readonly Container border;
[Resolved]
private Room room { get; set; }
public BeatmapSelectButton()
{
Masking = true;
CornerRadius = corner_radius;
Children = new Drawable[]
{
bg = new Box
{
RelativeSizeAxes = Axes.Both,
Colour = Color4.Black,
Alpha = bg_opacity,
},
new OsuSpriteText
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Font = @"Exo2.0-Bold",
Text = "Select Beatmap",
},
border = new Container
{
RelativeSizeAxes = Axes.Both,
Masking = true,
CornerRadius = corner_radius,
BorderThickness = 4,
Alpha = 0,
Child = new Box // needs a child to show the border
{
RelativeSizeAxes = Axes.Both,
Alpha = 0,
AlwaysPresent = true
},
},
};
Text = "Select beatmap";
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
private void load()
{
border.BorderColour = colours.Yellow;
}
protected override bool OnHover(HoverEvent e)
{
border.FadeIn(transition_duration);
return base.OnHover(e);
}
protected override void OnHoverLost(HoverLostEvent e)
{
base.OnHoverLost(e);
border.FadeOut(transition_duration);
}
protected override bool OnMouseDown(MouseDownEvent e)
{
bg.FadeTo(0.75f, 1000, Easing.Out);
return base.OnMouseDown(e);
}
protected override bool OnMouseUp(MouseUpEvent e)
{
bg.FadeTo(bg_opacity, transition_duration);
return base.OnMouseUp(e);
createdBind.BindTo(room.Created);
createdBind.BindValueChanged(v => Enabled.Value = !v, true);
}
}
}
public enum MatchHeaderPage
{
Settings,
Room,
private class HeaderBeatmapBackgroundSprite : UpdateableBeatmapBackgroundSprite
{
protected override double FadeDuration => 0;
}
}
}

View File

@ -17,66 +17,33 @@ using osu.Game.Overlays.SearchableList;
using osu.Game.Screens.Multi.Components;
using osuTK;
namespace osu.Game.Screens.Multi.Screens.Match
namespace osu.Game.Screens.Multi.Match.Components
{
public class Info : Container
{
public const float HEIGHT = 128;
private readonly OsuSpriteText name, availabilityStatus;
private readonly BeatmapTypeInfo beatmapTypeInfo;
private readonly OsuSpriteText availabilityStatus;
private readonly ReadyButton readyButton;
private OsuColour colours;
public Bindable<bool> Ready => readyButton.Ready;
public string Name
{
set { name.Text = value; }
}
private RoomAvailability availability;
public RoomAvailability Availability
{
set
{
if (value == availability) return;
availability = value;
if (IsLoaded)
updateAvailabilityStatus();
}
}
private RoomStatus status;
public RoomStatus Status
{
set
{
if (value == status) return;
status = value;
if (IsLoaded)
updateAvailabilityStatus();
}
}
public BeatmapInfo Beatmap
{
set { beatmapTypeInfo.Beatmap = value; }
}
public GameType Type
{
set { beatmapTypeInfo.Type = value; }
}
public readonly Bindable<string> Name = new Bindable<string>();
public readonly Bindable<RoomAvailability> Availability = new Bindable<RoomAvailability>();
public readonly Bindable<RoomStatus> Status = new Bindable<RoomStatus>();
public readonly Bindable<BeatmapInfo> Beatmap = new Bindable<BeatmapInfo>();
public readonly Bindable<GameType> Type = new Bindable<GameType>();
public Info()
{
RelativeSizeAxes = Axes.X;
Height = HEIGHT;
BeatmapTypeInfo beatmapTypeInfo;
OsuSpriteText name;
Children = new Drawable[]
{
new Box
@ -103,14 +70,8 @@ namespace osu.Game.Screens.Multi.Screens.Match
Direction = FillDirection.Vertical,
Children = new Drawable[]
{
name = new OsuSpriteText
{
TextSize = 30,
},
availabilityStatus = new OsuSpriteText
{
TextSize = 14,
},
name = new OsuSpriteText { TextSize = 30 },
availabilityStatus = new OsuSpriteText { TextSize = 14 },
},
},
beatmapTypeInfo = new BeatmapTypeInfo
@ -131,6 +92,13 @@ namespace osu.Game.Screens.Multi.Screens.Match
},
},
};
beatmapTypeInfo.Beatmap.BindTo(Beatmap);
beatmapTypeInfo.Type.BindTo(Type);
Availability.BindValueChanged(_ => updateAvailabilityStatus());
Status.BindValueChanged(_ => updateAvailabilityStatus());
Name.BindValueChanged(n => name.Text = n);
}
[BackgroundDependencyLoader]
@ -148,10 +116,13 @@ namespace osu.Game.Screens.Multi.Screens.Match
private void updateAvailabilityStatus()
{
if (status != null)
if (!IsLoaded)
return;
if (Status.Value != null)
{
availabilityStatus.FadeColour(status.GetAppropriateColour(colours), 100);
availabilityStatus.Text = $"{availability.GetDescription()}, {status.Message}";
availabilityStatus.FadeColour(Status.Value.GetAppropriateColour(colours), 100);
availabilityStatus.Text = $"{Availability.Value.GetDescription()}, {Status.Value.Message}";
}
}

View File

@ -0,0 +1,28 @@
// 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.Configuration;
namespace osu.Game.Screens.Multi.Match.Components
{
public abstract class MatchPage
{
public abstract string Name { get; }
public readonly BindableBool Enabled = new BindableBool(true);
public override string ToString() => Name;
public override int GetHashCode() => GetType().GetHashCode();
public override bool Equals(object obj) => GetType() == obj?.GetType();
}
public class SettingsMatchPage : MatchPage
{
public override string Name => "Settings";
}
public class RoomMatchPage : MatchPage
{
public override string Name => "Room";
}
}

View File

@ -0,0 +1,68 @@
// 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.Extensions.IEnumerableExtensions;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Input.Events;
using osu.Game.Graphics.UserInterface;
using osu.Game.Online.Multiplayer;
using osuTK.Graphics;
namespace osu.Game.Screens.Multi.Match.Components
{
public class MatchTabControl : PageTabControl<MatchPage>
{
private readonly IBindable<bool> created = new Bindable<bool>();
[Resolved]
private Room room { get; set; }
public MatchTabControl()
{
AddItem(new SettingsMatchPage());
AddItem(new RoomMatchPage());
}
[BackgroundDependencyLoader]
private void load()
{
created.BindTo(room.Created);
created.BindValueChanged(v =>
{
if (v)
{
Items.ForEach(t => t.Enabled.Value = !(t is SettingsMatchPage));
Current.Value = new RoomMatchPage();
}
else
{
Items.ForEach(t => t.Enabled.Value = t is SettingsMatchPage);
Current.Value = new SettingsMatchPage();
}
}, true);
}
protected override TabItem<MatchPage> CreateTabItem(MatchPage value) => new TabItem(value);
private class TabItem : PageTabItem
{
private readonly IBindable<bool> enabled = new BindableBool();
public TabItem(MatchPage value)
: base(value)
{
enabled.BindTo(value.Enabled);
enabled.BindValueChanged(v => Colour = v ? Color4.White : Color4.Gray);
}
protected override bool OnClick(ClickEvent e)
{
if (!enabled.Value)
return true;
return base.OnClick(e);
}
}
}
}

View File

@ -3,6 +3,7 @@
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Configuration;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Overlays.SearchableList;
@ -10,36 +11,25 @@ using osu.Game.Screens.Multi.Components;
using osu.Game.Users;
using osuTK;
namespace osu.Game.Screens.Multi.Screens.Match
namespace osu.Game.Screens.Multi.Match.Components
{
public class Participants : Container
public class Participants : CompositeDrawable
{
private readonly ParticipantCount count;
private readonly FillFlowContainer<UserPanel> usersFlow;
public readonly Bindable<IEnumerable<User>> Users = new Bindable<IEnumerable<User>>();
public readonly Bindable<int?> MaxParticipants = new Bindable<int?>();
public IEnumerable<User> Users
public new MarginPadding Padding
{
set {
usersFlow.Children = value.Select(u => new UserPanel(u)
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Width = 300,
OnLoadComplete = d => d.FadeInFromZero(60),
}).ToList();
count.Count = value.Count();
}
}
public int? Max
{
set => count.Max = value;
get => base.Padding;
set => base.Padding = value;
}
public Participants()
{
Child = new Container
FillFlowContainer<UserPanel> usersFlow;
ParticipantCount count;
InternalChild = new Container
{
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding { Horizontal = SearchableListOverlay.WIDTH_PADDING },
@ -69,6 +59,20 @@ namespace osu.Game.Screens.Multi.Screens.Match
},
},
};
count.Participants.BindTo(Users);
count.MaxParticipants.BindTo(MaxParticipants);
Users.BindValueChanged(v =>
{
usersFlow.Children = v.Select(u => new UserPanel(u)
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Width = 300,
OnLoadComplete = d => d.FadeInFromZero(60),
}).ToList();
});
}
}
}

View File

@ -10,12 +10,13 @@ using osu.Framework.Input.Events;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Online.Multiplayer;
using osu.Game.Screens.Multi.Components;
using osuTK;
using osuTK.Graphics;
namespace osu.Game.Screens.Multi.Screens.Match.Settings
namespace osu.Game.Screens.Multi.Match.Components
{
public class RoomAvailabilityPicker : TabControl<RoomAvailability>
public class RoomAvailabilityPicker : DisableableTabControl<RoomAvailability>
{
protected override TabItem<RoomAvailability> CreateTabItem(RoomAvailability value) => new RoomAvailabilityPickerItem(value);
protected override Dropdown<RoomAvailability> CreateDropdown() => null;
@ -32,7 +33,7 @@ namespace osu.Game.Screens.Multi.Screens.Match.Settings
AddItem(RoomAvailability.InviteOnly);
}
private class RoomAvailabilityPickerItem : TabItem<RoomAvailability>
private class RoomAvailabilityPickerItem : DisableableTabItem<RoomAvailability>
{
private const float transition_duration = 200;
@ -41,7 +42,7 @@ namespace osu.Game.Screens.Multi.Screens.Match.Settings
public RoomAvailabilityPickerItem(RoomAvailability value) : base(value)
{
RelativeSizeAxes = Axes.Y;
Width = 120;
Width = 102;
Masking = true;
CornerRadius = 5;

View File

@ -6,6 +6,7 @@ using osu.Framework.Configuration;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Game.Beatmaps;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
@ -14,7 +15,7 @@ using osu.Game.Overlays.SearchableList;
using osuTK;
using osuTK.Graphics;
namespace osu.Game.Screens.Multi.Screens.Match.Settings
namespace osu.Game.Screens.Multi.Match.Components
{
public class RoomSettingsOverlay : FocusedOverlayContainer
{
@ -22,19 +23,28 @@ namespace osu.Game.Screens.Multi.Screens.Match.Settings
private const float field_padding = 45;
private readonly Bindable<string> nameBind = new Bindable<string>();
private readonly Bindable<BeatmapInfo> beatmapBind = new Bindable<BeatmapInfo>();
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 Container content;
private readonly OsuSpriteText typeLabel;
protected readonly OsuTextBox NameField, MaxParticipantsField;
protected readonly RoomAvailabilityPicker AvailabilityPicker;
protected readonly GameTypePicker TypePicker;
protected readonly TriangleButton ApplyButton;
protected readonly OsuPasswordTextBox PasswordField;
public RoomSettingsOverlay(Room room)
[Resolved]
private RoomManager manager { get; set; }
[Resolved]
private Room room { get; set; }
public RoomSettingsOverlay()
{
Masking = true;
@ -114,11 +124,11 @@ namespace osu.Game.Screens.Multi.Screens.Match.Settings
},
new Section("PASSWORD (OPTIONAL)")
{
Child = new SettingsPasswordTextBox
Child = PasswordField = new SettingsPasswordTextBox
{
RelativeSizeAxes = Axes.X,
TabbableContentContainer = this,
OnCommit = (sender, text) => apply(),
OnCommit = (sender, text) => apply()
},
},
},
@ -142,19 +152,35 @@ namespace osu.Game.Screens.Multi.Screens.Match.Settings
availabilityBind.ValueChanged += a => AvailabilityPicker.Current.Value = a;
typeBind.ValueChanged += t => TypePicker.Current.Value = t;
maxParticipantsBind.ValueChanged += m => MaxParticipantsField.Text = m?.ToString();
nameBind.BindTo(room.Name);
availabilityBind.BindTo(room.Availability);
typeBind.BindTo(room.Type);
maxParticipantsBind.BindTo(room.MaxParticipants);
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
typeLabel.Colour = colours.Yellow;
nameBind.BindTo(room.Name);
beatmapBind.BindTo(room.Beatmap);
availabilityBind.BindTo(room.Availability);
typeBind.BindTo(room.Type);
maxParticipantsBind.BindTo(room.MaxParticipants);
MaxParticipantsField.ReadOnly = true;
PasswordField.ReadOnly = true;
AvailabilityPicker.ReadOnly.Value = true;
TypePicker.ReadOnly.Value = true;
ApplyButton.Enabled.Value = false;
}
protected override void Update()
{
base.Update();
ApplyButton.Enabled.Value = hasValidSettings;
}
private bool hasValidSettings => NameField.Text.Length > 0 && beatmapBind.Value != null;
protected override void PopIn()
{
// reapply the rooms values if the overlay was completely closed
@ -185,7 +211,7 @@ namespace osu.Game.Screens.Multi.Screens.Match.Settings
else
maxParticipantsBind.Value = null;
Hide();
manager.CreateRoom(room);
}
private class SettingsTextBox : OsuTextBox

View File

@ -2,62 +2,82 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Collections.Generic;
using osu.Framework.Allocation;
using osu.Framework.Configuration;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Beatmaps;
using osu.Game.Online.API;
using osu.Game.Online.Multiplayer;
using osu.Game.Screens.Multi.Screens.Match.Settings;
using osu.Game.Screens.Multi.Match.Components;
using osu.Game.Screens.Select;
using osu.Game.Users;
namespace osu.Game.Screens.Multi.Screens.Match
namespace osu.Game.Screens.Multi.Match
{
public class Match : MultiplayerScreen
public class MatchScreen : MultiplayerScreen
{
private readonly Room room;
private readonly Participants participants;
private readonly Bindable<string> nameBind = new Bindable<string>();
private readonly Bindable<BeatmapInfo> beatmapBind = new Bindable<BeatmapInfo>();
private readonly Bindable<RoomStatus> statusBind = new Bindable<RoomStatus>();
private readonly Bindable<RoomAvailability> availabilityBind = new Bindable<RoomAvailability>();
private readonly Bindable<GameType> typeBind = new Bindable<GameType>();
private readonly Bindable<BeatmapInfo> beatmapBind = new Bindable<BeatmapInfo>();
private readonly Bindable<int?> maxParticipantsBind = new Bindable<int?>();
private readonly Bindable<IEnumerable<User>> participantsBind = new Bindable<IEnumerable<User>>();
protected override Container<Drawable> TransitionContent => participants;
protected override Drawable TransitionContent => participants;
public override string Type => "room";
public override string Title => room.Name.Value;
public Match(Room room)
public override string ShortTitle => "room";
[Cached]
private readonly Room room;
[Resolved]
private BeatmapManager beatmapManager { get; set; }
[Resolved]
private APIAccess api { get; set; }
public MatchScreen(Room room)
{
this.room = room;
Header header;
nameBind.BindTo(room.Name);
beatmapBind.BindTo(room.Beatmap);
statusBind.BindTo(room.Status);
availabilityBind.BindTo(room.Availability);
typeBind.BindTo(room.Type);
participantsBind.BindTo(room.Participants);
maxParticipantsBind.BindTo(room.MaxParticipants);
Components.Header header;
RoomSettingsOverlay settings;
Info info;
Children = new Drawable[]
{
header = new Header
header = new Components.Header
{
Depth = -1,
},
info = new Info
{
Margin = new MarginPadding { Top = Header.HEIGHT },
Margin = new MarginPadding { Top = Components.Header.HEIGHT },
},
participants = new Participants
{
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding { Top = Header.HEIGHT + Info.HEIGHT },
Padding = new MarginPadding { Top = Components.Header.HEIGHT + Info.HEIGHT },
},
new Container
{
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding { Top = Header.HEIGHT },
Child = settings = new RoomSettingsOverlay(room)
Padding = new MarginPadding { Top = Components.Header.HEIGHT },
Child = settings = new RoomSettingsOverlay
{
RelativeSizeAxes = Axes.Both,
Height = 0.9f,
@ -66,45 +86,32 @@ namespace osu.Game.Screens.Multi.Screens.Match
};
header.OnRequestSelectBeatmap = () => Push(new MatchSongSelect());
beatmapBind.BindTo(room.Beatmap);
beatmapBind.BindValueChanged(b =>
{
header.BeatmapSet = b?.BeatmapSet;
info.Beatmap = b;
}, true);
header.Beatmap.BindTo(Beatmap);
header.Tabs.Current.ValueChanged += t =>
{
if (t == MatchHeaderPage.Settings)
if (t is SettingsMatchPage)
settings.Show();
else
settings.Hide();
};
settings.StateChanged += s =>
{
if (s == Visibility.Hidden)
header.Tabs.Current.Value = MatchHeaderPage.Room;
};
info.Beatmap.BindTo(beatmapBind);
info.Name.BindTo(nameBind);
info.Status.BindTo(statusBind);
info.Availability.BindTo(availabilityBind);
info.Type.BindTo(typeBind);
nameBind.BindTo(room.Name);
nameBind.BindValueChanged(n => info.Name = n, true);
participants.Users.BindTo(participantsBind);
participants.MaxParticipants.BindTo(maxParticipantsBind);
}
statusBind.BindTo(room.Status);
statusBind.BindValueChanged(s => info.Status = s, true);
availabilityBind.BindTo(room.Availability);
availabilityBind.BindValueChanged(a => info.Availability = a, true);
typeBind.BindTo(room.Type);
typeBind.BindValueChanged(t => info.Type = t, true);
maxParticipantsBind.BindTo(room.MaxParticipants);
maxParticipantsBind.BindValueChanged(m => { participants.Max = m; }, true);
participantsBind.BindTo(room.Participants);
participantsBind.BindValueChanged(p => participants.Users = p, true);
[BackgroundDependencyLoader]
private void load()
{
beatmapBind.BindTo(room.Beatmap);
beatmapBind.BindValueChanged(b => Beatmap.Value = beatmapManager.GetWorkingBeatmap(room.Beatmap.Value), true);
Beatmap.BindValueChanged(b => beatmapBind.Value = b.BeatmapInfo);
}
}
}

View File

@ -9,7 +9,7 @@ using osu.Game.Graphics;
using osu.Game.Graphics.Backgrounds;
using osu.Game.Graphics.Containers;
using osu.Game.Screens.Menu;
using osu.Game.Screens.Multi.Screens.Lounge;
using osu.Game.Screens.Multi.Lounge;
namespace osu.Game.Screens.Multi
{
@ -26,7 +26,7 @@ namespace osu.Game.Screens.Multi
RelativeSizeAxes = Axes.Both,
};
Lounge lounge;
LoungeScreen loungeScreen;
Children = new Drawable[]
{
new Container
@ -53,12 +53,12 @@ namespace osu.Game.Screens.Multi
{
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding { Top = Header.HEIGHT },
Child = lounge = new Lounge(),
Child = loungeScreen = new LoungeScreen(),
},
new Header(lounge),
new Header(loungeScreen)
};
lounge.Exited += s => Exit();
loungeScreen.Exited += s => Exit();
}
protected override void OnEntering(Screen last)

View File

@ -2,20 +2,16 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Screens;
using osu.Game.Graphics.Containers;
namespace osu.Game.Screens.Multi.Screens
namespace osu.Game.Screens.Multi
{
public abstract class MultiplayerScreen : OsuScreen
public abstract class MultiplayerScreen : OsuScreen, IMultiplayerScreen
{
protected virtual Container<Drawable> TransitionContent => Content;
protected virtual Drawable TransitionContent => Content;
/// <summary>
/// The type to display in the title of the <see cref="Header"/>.
/// </summary>
public virtual string Type => Title;
public virtual string ShortTitle => Title;
protected override void OnEntering(Screen last)
{

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);
}
}
}

View File

@ -1,10 +1,14 @@
// 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.Screens.Multi;
namespace osu.Game.Screens.Select
{
public class MatchSongSelect : SongSelect
public class MatchSongSelect : SongSelect, IMultiplayerScreen
{
public string ShortTitle => "song selection";
protected override bool OnStart()
{
if (IsCurrentScreen) Exit();

View File

@ -29,6 +29,9 @@ namespace osu.Game.Tests.Visual
{
Dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
// This is the earliest we can get OsuGameBase, which is used by the dummy working beatmap to find textures
beatmap.Default = new DummyWorkingBeatmap(Dependencies.Get<OsuGameBase>());
Dependencies.CacheAs<BindableBeatmap>(beatmap);
Dependencies.CacheAs<IBindableBeatmap>(beatmap);

View File

@ -18,7 +18,7 @@
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.0" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.1" />
<PackageReference Include="ppy.osu.Framework" Version="2018.1207.0" />
<PackageReference Include="ppy.osu.Framework" Version="0.0.7654" />
<PackageReference Include="SharpCompress" Version="0.22.0" />
<PackageReference Include="NUnit" Version="3.11.0" />
<PackageReference Include="SharpRaven" Version="2.4.0" />