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

Merge remote-tracking branch 'origin/master' into disallow-beatmap-change

# Conflicts:
#	osu.Game/Overlays/Music/PlaylistOverlay.cs
#	osu.Game/Screens/OsuScreen.cs
This commit is contained in:
smoogipoo 2018-05-28 18:01:15 +09:00
commit a3470f9ec3
38 changed files with 841 additions and 142 deletions

@ -1 +1 @@
Subproject commit 2893a3ec94b403bc11295fd435af0431dbe23b7a Subproject commit 84fdfc77a86d581638e69f5e8061c118de4b30f9

View File

@ -28,7 +28,20 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
var endTime = obj as IHasEndTime; var endTime = obj as IHasEndTime;
if (positionData == null) if (positionData == null)
{
if (endTime != null)
{
yield return new BananaShower
{
StartTime = obj.StartTime,
Samples = obj.Samples,
Duration = endTime.Duration,
NewCombo = comboData?.NewCombo ?? false
};
}
yield break; yield break;
}
if (curveData != null) if (curveData != null)
{ {
@ -48,19 +61,6 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
yield break; yield break;
} }
if (endTime != null)
{
yield return new BananaShower
{
StartTime = obj.StartTime,
Samples = obj.Samples,
Duration = endTime.Duration,
NewCombo = comboData?.NewCombo ?? false
};
yield break;
}
yield return new Fruit yield return new Fruit
{ {
StartTime = obj.StartTime, StartTime = obj.StartTime,

View File

@ -105,7 +105,8 @@ namespace osu.Game.Rulesets.Mania.Difficulty
private double computeAccuracyValue(double strainValue) private double computeAccuracyValue(double strainValue)
{ {
double hitWindowGreat = (Beatmap.HitObjects.First().HitWindows.Great / 2 - 0.5) / TimeRate; // Todo: This int cast is temporary to achieve 1:1 results with osu!stable, and should be remoevd in the future
double hitWindowGreat = (int)(Beatmap.HitObjects.First().HitWindows.Great / 2) / TimeRate;
if (hitWindowGreat <= 0) if (hitWindowGreat <= 0)
return 0; return 0;

View File

@ -61,20 +61,12 @@ namespace osu.Game.Rulesets.Osu.Difficulty
if (mods.Any(m => !m.Ranked)) if (mods.Any(m => !m.Ranked))
return 0; return 0;
// Todo: In the future we should apply changes to PreEmpt/AR at an OsuHitObject/BaseDifficulty level, but this is done // Todo: These int casts are temporary to achieve 1:1 results with osu!stable, and should be remoevd in the future
// locally for now as doing so would modify animations and other things unexpectedly double hitWindowGreat = (int)(Beatmap.HitObjects.First().HitWindows.Great / 2) / TimeRate;
// DO NOT MODIFY THIS double preEmpt = (int)BeatmapDifficulty.DifficultyRange(Beatmap.BeatmapInfo.BaseDifficulty.ApproachRate, 1800, 1200, 450) / TimeRate;
double ar = Beatmap.BeatmapInfo.BaseDifficulty.ApproachRate;
if (mods.Any(m => m is OsuModHardRock))
ar = Math.Min(10, ar * 1.4);
if (mods.Any(m => m is OsuModEasy))
ar = Math.Max(0, ar / 2);
double preEmpt = BeatmapDifficulty.DifficultyRange(ar, 1800, 1200, 450) / TimeRate;
double hitWindowGreat = (Beatmap.HitObjects.First().HitWindows.Great / 2 - 0.5) / TimeRate;
realApproachRate = preEmpt > 1200 ? (1800 - preEmpt) / 120 : (1200 - preEmpt) / 150 + 5; realApproachRate = preEmpt > 1200 ? (1800 - preEmpt) / 120 : (1200 - preEmpt) / 150 + 5;
realOverallDifficulty = (80 - 0.5 - hitWindowGreat) / 6; realOverallDifficulty = (80 - hitWindowGreat) / 6;
// Custom multipliers for NoFail and SpunOut. // Custom multipliers for NoFail and SpunOut.
double multiplier = 1.12f; // This is being adjusted to keep the final pp value scaled around what it used to be when changing things double multiplier = 1.12f; // This is being adjusted to keep the final pp value scaled around what it used to be when changing things

View File

@ -94,7 +94,8 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
private double computeAccuracyValue() private double computeAccuracyValue()
{ {
double hitWindowGreat = (Beatmap.HitObjects.First().HitWindows.Great / 2 - 0.5) / TimeRate; // Todo: This int cast is temporary to achieve 1:1 results with osu!stable, and should be remoevd in the future
double hitWindowGreat = (int)(Beatmap.HitObjects.First().HitWindows.Great / 2) / TimeRate;
if (hitWindowGreat <= 0) if (hitWindowGreat <= 0)
return 0; return 0;

View File

@ -5,6 +5,7 @@ using System.ComponentModel;
using System.Linq; using System.Linq;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Rulesets; using osu.Game.Rulesets;
using osu.Game.Rulesets.Scoring;
using osu.Game.Screens.Play; using osu.Game.Screens.Play;
namespace osu.Game.Tests.Visual namespace osu.Game.Tests.Visual
@ -15,7 +16,19 @@ namespace osu.Game.Tests.Visual
protected override Player CreatePlayer(WorkingBeatmap beatmap, Ruleset ruleset) protected override Player CreatePlayer(WorkingBeatmap beatmap, Ruleset ruleset)
{ {
beatmap.Mods.Value = beatmap.Mods.Value.Concat(new[] { ruleset.GetAutoplayMod() }); beatmap.Mods.Value = beatmap.Mods.Value.Concat(new[] { ruleset.GetAutoplayMod() });
return base.CreatePlayer(beatmap, ruleset); return new ScoreAccessiblePlayer
{
AllowPause = false,
AllowLeadIn = false,
AllowResults = false,
};
}
protected override bool ContinueCondition(Player player) => base.ContinueCondition(player) && ((ScoreAccessiblePlayer)player).ScoreProcessor.TotalScore > 0;
private class ScoreAccessiblePlayer : Player
{
public new ScoreProcessor ScoreProcessor => base.ScoreProcessor;
} }
} }
} }

View File

@ -19,12 +19,12 @@ namespace osu.Game.Tests.Visual
[TestFixture] [TestFixture]
public class TestCaseCursors : ManualInputManagerTestCase public class TestCaseCursors : ManualInputManagerTestCase
{ {
private readonly CursorOverrideContainer cursorOverrideContainer; private readonly MenuCursorContainer menuCursorContainer;
private readonly CustomCursorBox[] cursorBoxes = new CustomCursorBox[6]; private readonly CustomCursorBox[] cursorBoxes = new CustomCursorBox[6];
public TestCaseCursors() public TestCaseCursors()
{ {
Child = cursorOverrideContainer = new CursorOverrideContainer Child = menuCursorContainer = new MenuCursorContainer
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Children = new[] Children = new[]
@ -99,7 +99,7 @@ namespace osu.Game.Tests.Visual
AddAssert("Check green cursor at mouse", () => checkAtMouse(cursorBoxes[0].Cursor)); AddAssert("Check green cursor at mouse", () => checkAtMouse(cursorBoxes[0].Cursor));
AddStep("Move out", moveOut); AddStep("Move out", moveOut);
AddAssert("Check green cursor invisible", () => !checkVisible(cursorBoxes[0].Cursor)); AddAssert("Check green cursor invisible", () => !checkVisible(cursorBoxes[0].Cursor));
AddAssert("Check global cursor visible", () => checkVisible(cursorOverrideContainer.Cursor)); AddAssert("Check global cursor visible", () => checkVisible(menuCursorContainer.Cursor));
} }
/// <summary> /// <summary>
@ -112,11 +112,11 @@ namespace osu.Game.Tests.Visual
AddStep("Move to purple area", () => InputManager.MoveMouseTo(cursorBoxes[3])); AddStep("Move to purple area", () => InputManager.MoveMouseTo(cursorBoxes[3]));
AddAssert("Check purple cursor visible", () => checkVisible(cursorBoxes[3].Cursor)); AddAssert("Check purple cursor visible", () => checkVisible(cursorBoxes[3].Cursor));
AddAssert("Check purple cursor at mouse", () => checkAtMouse(cursorBoxes[3].Cursor)); AddAssert("Check purple cursor at mouse", () => checkAtMouse(cursorBoxes[3].Cursor));
AddAssert("Check global cursor visible", () => checkVisible(cursorOverrideContainer.Cursor)); AddAssert("Check global cursor visible", () => checkVisible(menuCursorContainer.Cursor));
AddAssert("Check global cursor at mouse", () => checkAtMouse(cursorOverrideContainer.Cursor)); AddAssert("Check global cursor at mouse", () => checkAtMouse(menuCursorContainer.Cursor));
AddStep("Move out", moveOut); AddStep("Move out", moveOut);
AddAssert("Check purple cursor visible", () => checkVisible(cursorBoxes[3].Cursor)); AddAssert("Check purple cursor visible", () => checkVisible(cursorBoxes[3].Cursor));
AddAssert("Check global cursor visible", () => checkVisible(cursorOverrideContainer.Cursor)); AddAssert("Check global cursor visible", () => checkVisible(menuCursorContainer.Cursor));
} }
/// <summary> /// <summary>

View File

@ -0,0 +1,23 @@
// 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 osu.Game.Graphics.UserInterface;
using OpenTK;
namespace osu.Game.Tests.Visual
{
public class TestCaseExternalLinkButton : OsuTestCase
{
public override IReadOnlyList<Type> RequiredTypes => new[] { typeof(ExternalLinkButton) };
public TestCaseExternalLinkButton()
{
Child = new ExternalLinkButton("https://osu.ppy.sh/home")
{
Size = new Vector2(50)
};
}
}
}

View File

@ -0,0 +1,211 @@
// 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;
using osu.Game.Online.Multiplayer;
using osu.Game.Rulesets;
using osu.Game.Screens.Multi.Components;
using osu.Game.Screens.Multi.Screens.Lounge;
using osu.Game.Users;
using OpenTK.Input;
namespace osu.Game.Tests.Visual
{
[TestFixture]
public class TestCaseLounge : ManualInputManagerTestCase
{
private TestLounge lounge;
[BackgroundDependencyLoader]
private void load(RulesetStore rulesets)
{
lounge = new TestLounge();
Room[] rooms =
{
new Room
{
Name = { Value = @"Just Another Room" },
Host = { Value = new User { Username = @"DrabWeb", Id = 6946022, Country = new Country { FlagName = @"CA" } } },
Status = { Value = new RoomStatusPlaying() },
Availability = { Value = RoomAvailability.Public },
Type = { Value = new GameTypeTagTeam() },
Beatmap =
{
Value = new BeatmapInfo
{
StarDifficulty = 5.65,
Ruleset = rulesets.GetRuleset(0),
Metadata = new BeatmapMetadata
{
Title = @"Sidetracked Day (Short Ver.)",
Artist = @"VINXIS",
AuthorString = @"Hobbes2",
},
BeatmapSet = new BeatmapSetInfo
{
OnlineInfo = new BeatmapSetOnlineInfo
{
Covers = new BeatmapSetOnlineCovers
{
Cover = @"https://assets.ppy.sh/beatmaps/767600/covers/cover.jpg?1526243446",
},
},
},
}
},
MaxParticipants = { Value = 10 },
Participants =
{
Value = new[]
{
new User { Username = @"flyte", Id = 3103765, Statistics = new UserStatistics { Ranks = new UserStatistics.UserRanks { Global = 142 } } },
new User { Username = @"Cookiezi", Id = 124493, Statistics = new UserStatistics { Ranks = new UserStatistics.UserRanks { Global = 546 } } },
new User { Username = @"Angelsim", Id = 1777162, Statistics = new UserStatistics { Ranks = new UserStatistics.UserRanks { Global = 287 } } },
new User { Username = @"Rafis", Id = 2558286, Statistics = new UserStatistics { Ranks = new UserStatistics.UserRanks { Global = 468 } } },
new User { Username = @"hvick225", Id = 50265, Statistics = new UserStatistics { Ranks = new UserStatistics.UserRanks { Global = 325 } } },
new User { Username = @"peppy", Id = 2, Statistics = new UserStatistics { Ranks = new UserStatistics.UserRanks { Global = 625 } } },
}
}
},
new Room
{
Name = { Value = @"Not Just Any Room" },
Host = { Value = new User { Username = @"Monstrata", Id = 2706438, Country = new Country { FlagName = @"CA" } } },
Status = { Value = new RoomStatusOpen() },
Availability = { Value = RoomAvailability.FriendsOnly },
Type = { Value = new GameTypeTeamVersus() },
Beatmap =
{
Value = new BeatmapInfo
{
StarDifficulty = 2.73,
Ruleset = rulesets.GetRuleset(0),
Metadata = new BeatmapMetadata
{
Title = @"lit(var)",
Artist = @"kensuke ushio",
AuthorString = @"Monstrata",
},
BeatmapSet = new BeatmapSetInfo
{
OnlineInfo = new BeatmapSetOnlineInfo
{
Covers = new BeatmapSetOnlineCovers
{
Cover = @"https://assets.ppy.sh/beatmaps/623972/covers/cover.jpg?1521167183",
},
},
},
}
},
Participants =
{
Value = new[]
{
new User { Username = @"Jeby", Id = 3136279, Statistics = new UserStatistics { Ranks = new UserStatistics.UserRanks { Global = 3497 } } },
new User { Username = @"DualAkira", Id = 5220933, Statistics = new UserStatistics { Ranks = new UserStatistics.UserRanks { Global = 643 } } },
new User { Username = @"Datenshi Yohane", Id = 7171857, Statistics = new UserStatistics { Ranks = new UserStatistics.UserRanks { Global = 10555 } } },
}
}
},
new Room
{
Name = { Value = @"room THE FINAL" },
Host = { Value = new User { Username = @"Delis", Id = 1603923, Country = new Country { FlagName = @"JP" } } },
Status = { Value = new RoomStatusPlaying() },
Availability = { Value = RoomAvailability.Public },
Type = { Value = new GameTypeTagTeam() },
Beatmap =
{
Value = new BeatmapInfo
{
StarDifficulty = 4.48,
Ruleset = rulesets.GetRuleset(3),
Metadata = new BeatmapMetadata
{
Title = @"ONIGIRI FREEWAY",
Artist = @"OISHII",
AuthorString = @"Mentholzzz",
},
BeatmapSet = new BeatmapSetInfo
{
OnlineInfo = new BeatmapSetOnlineInfo
{
Covers = new BeatmapSetOnlineCovers
{
Cover = @"https://assets.ppy.sh/beatmaps/663098/covers/cover.jpg?1521898837",
},
},
},
}
},
MaxParticipants = { Value = 30 },
Participants =
{
Value = new[]
{
new User { Username = @"KizuA", Id = 6510442, Statistics = new UserStatistics { Ranks = new UserStatistics.UserRanks { Global = 5372 } } },
new User { Username = @"Colored", Id = 827563, Statistics = new UserStatistics { Ranks = new UserStatistics.UserRanks { Global = 810 } } },
new User { Username = @"Beryl", Id = 3817591, Statistics = new UserStatistics { Ranks = new UserStatistics.UserRanks { Global = 10096 } } },
}
}
},
};
AddStep(@"show", () => Add(lounge));
AddStep(@"set rooms", () => lounge.Rooms = rooms);
selectAssert(0);
AddStep(@"clear rooms", () => lounge.Rooms = new Room[] {});
AddAssert(@"no room selected", () => lounge.SelectedRoom == null);
AddStep(@"set rooms", () => lounge.Rooms = rooms);
selectAssert(1);
AddStep(@"open room 1", () => clickRoom(1));
AddStep(@"make lounge current", lounge.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);
}
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);
}
private class TestLounge : Lounge
{
public IEnumerable<DrawableRoom> ChildRooms => RoomsContainer.Children.Where(r => r.MatchingFilter);
public Room SelectedRoom => Inspector.Room;
public void SetFilter(string filter, LoungeTab tab)
{
Filter.Search.Current.Value = filter;
Filter.Tabs.Current.Value = tab;
}
}
}
}

View File

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

View File

@ -31,10 +31,6 @@ namespace osu.Game.Tests.Visual
var text = quitButton.Children.OfType<SpriteText>().First(); var text = quitButton.Children.OfType<SpriteText>().First();
// initial display
AddUntilStep(() => text.IsPresent && !exitAction, "Text visible");
AddUntilStep(() => !text.IsPresent && !exitAction, "Text is not visible");
AddStep("Trigger text fade in", () => InputManager.MoveMouseTo(quitButton)); AddStep("Trigger text fade in", () => InputManager.MoveMouseTo(quitButton));
AddUntilStep(() => text.IsPresent && !exitAction, "Text visible"); AddUntilStep(() => text.IsPresent && !exitAction, "Text visible");
AddStep("Trigger text fade out", () => InputManager.MoveMouseTo(Vector2.One)); AddStep("Trigger text fade out", () => InputManager.MoveMouseTo(Vector2.One));
@ -44,13 +40,13 @@ namespace osu.Game.Tests.Visual
{ {
exitAction = false; exitAction = false;
InputManager.MoveMouseTo(quitButton); InputManager.MoveMouseTo(quitButton);
InputManager.ButtonDown(MouseButton.Left); InputManager.PressButton(MouseButton.Left);
}); });
AddStep("Early release", () => InputManager.ButtonUp(MouseButton.Left)); AddStep("Early release", () => InputManager.ReleaseButton(MouseButton.Left));
AddAssert("action not triggered", () => !exitAction); AddAssert("action not triggered", () => !exitAction);
AddStep("Trigger exit action", () => InputManager.ButtonDown(MouseButton.Left)); AddStep("Trigger exit action", () => InputManager.PressButton(MouseButton.Left));
AddUntilStep(() => exitAction, $"{nameof(quitButton.Action)} was triggered"); AddUntilStep(() => exitAction, $"{nameof(quitButton.Action)} was triggered");
} }
} }

View File

@ -84,12 +84,9 @@ namespace osu.Game.Tests.Visual
private abstract class TestScreen : OsuScreen private abstract class TestScreen : OsuScreen
{ {
protected abstract string Title { get; }
protected abstract string NextTitle { get; } protected abstract string NextTitle { get; }
protected abstract TestScreen CreateNextScreen(); protected abstract TestScreen CreateNextScreen();
public override string ToString() => Title;
public TestScreen PushNext() public TestScreen PushNext()
{ {
TestScreen screen = CreateNextScreen(); TestScreen screen = CreateNextScreen();
@ -130,14 +127,14 @@ namespace osu.Game.Tests.Visual
private class TestScreenOne : TestScreen private class TestScreenOne : TestScreen
{ {
protected override string Title => @"Screen One"; public override string Title => @"Screen One";
protected override string NextTitle => @"Two"; protected override string NextTitle => @"Two";
protected override TestScreen CreateNextScreen() => new TestScreenTwo(); protected override TestScreen CreateNextScreen() => new TestScreenTwo();
} }
private class TestScreenTwo : TestScreen private class TestScreenTwo : TestScreen
{ {
protected override string Title => @"Screen Two"; public override string Title => @"Screen Two";
protected override string NextTitle => @"One"; protected override string NextTitle => @"One";
protected override TestScreen CreateNextScreen() => new TestScreenOne(); protected override TestScreen CreateNextScreen() => new TestScreenOne();
} }

View File

@ -12,7 +12,7 @@ namespace osu.Game.Graphics.Cursor
/// <summary> /// <summary>
/// A container which provides a <see cref="MenuCursor"/> which can be overridden by hovered <see cref="Drawable"/>s. /// A container which provides a <see cref="MenuCursor"/> which can be overridden by hovered <see cref="Drawable"/>s.
/// </summary> /// </summary>
public class CursorOverrideContainer : Container, IProvideCursor public class MenuCursorContainer : Container, IProvideCursor
{ {
protected override Container<Drawable> Content => content; protected override Container<Drawable> Content => content;
private readonly Container content; private readonly Container content;
@ -25,7 +25,7 @@ namespace osu.Game.Graphics.Cursor
public CursorContainer Cursor { get; } public CursorContainer Cursor { get; }
public bool ProvidingUserCursor => true; public bool ProvidingUserCursor => true;
public CursorOverrideContainer() public MenuCursorContainer()
{ {
AddRangeInternal(new Drawable[] AddRangeInternal(new Drawable[]
{ {

View File

@ -0,0 +1,63 @@
// 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.Diagnostics;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Input;
using OpenTK;
using OpenTK.Graphics;
namespace osu.Game.Graphics.UserInterface
{
public class ExternalLinkButton : CompositeDrawable, IHasTooltip
{
public string Link { get; set; }
private Color4 hoverColour;
public ExternalLinkButton(string link = null)
{
Link = link;
Size = new Vector2(12);
InternalChild = new SpriteIcon
{
Icon = FontAwesome.fa_external_link,
RelativeSizeAxes = Axes.Both
};
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
hoverColour = colours.Yellow;
}
protected override bool OnHover(InputState state)
{
InternalChild.FadeColour(hoverColour, 500, Easing.OutQuint);
return base.OnHover(state);
}
protected override void OnHoverLost(InputState state)
{
InternalChild.FadeColour(Color4.White, 500, Easing.OutQuint);
base.OnHoverLost(state);
}
protected override bool OnClick(InputState state)
{
if(Link != null)
Process.Start(new ProcessStartInfo
{
FileName = Link,
UseShellExecute = true //see https://github.com/dotnet/corefx/issues/10361
});
return true;
}
public string TooltipText => "View in browser";
}
}

View File

@ -6,6 +6,7 @@ using System.Linq;
using OpenTK; using OpenTK;
using OpenTK.Graphics; using OpenTK.Graphics;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Configuration;
using osu.Framework.Extensions; using osu.Framework.Extensions;
using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
@ -157,7 +158,7 @@ namespace osu.Game.Graphics.UserInterface
Margin = new MarginPadding { Top = 5, Bottom = 5 }, Margin = new MarginPadding { Top = 5, Bottom = 5 },
Origin = Anchor.BottomLeft, Origin = Anchor.BottomLeft,
Anchor = Anchor.BottomLeft, Anchor = Anchor.BottomLeft,
Text = (value as Enum)?.GetDescription() ?? value.ToString(), Text = (value as IHasDescription)?.Description ?? (value as Enum)?.GetDescription() ?? value.ToString(),
TextSize = 14, TextSize = 14,
Font = @"Exo2.0-Bold", // Font should only turn bold when active? Font = @"Exo2.0-Bold", // Font should only turn bold when active?
}, },

View File

@ -12,6 +12,7 @@ namespace osu.Game.Online.Multiplayer
public Bindable<string> Name = new Bindable<string>(); public Bindable<string> Name = new Bindable<string>();
public Bindable<User> Host = new Bindable<User>(); public Bindable<User> Host = new Bindable<User>();
public Bindable<RoomStatus> Status = new Bindable<RoomStatus>(); public Bindable<RoomStatus> Status = new Bindable<RoomStatus>();
public Bindable<RoomAvailability> Availability = new Bindable<RoomAvailability>();
public Bindable<GameType> Type = new Bindable<GameType>(); public Bindable<GameType> Type = new Bindable<GameType>();
public Bindable<BeatmapInfo> Beatmap = new Bindable<BeatmapInfo>(); public Bindable<BeatmapInfo> Beatmap = new Bindable<BeatmapInfo>();
public Bindable<int?> MaxParticipants = new Bindable<int?>(); public Bindable<int?> MaxParticipants = new Bindable<int?>();

View File

@ -0,0 +1,18 @@
// 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.ComponentModel;
namespace osu.Game.Online.Multiplayer
{
public enum RoomAvailability
{
Public,
[Description(@"Friends Only")]
FriendsOnly,
[Description(@"Invite Only")]
InviteOnly,
}
}

View File

@ -212,7 +212,7 @@ namespace osu.Game
protected override void LoadComplete() protected override void LoadComplete()
{ {
// this needs to be cached before base.LoadComplete as it is used by CursorOverrideContainer. // this needs to be cached before base.LoadComplete as it is used by MenuCursorContainer.
dependencies.Cache(screenshotManager = new ScreenshotManager()); dependencies.Cache(screenshotManager = new ScreenshotManager());
base.LoadComplete(); base.LoadComplete();
@ -220,7 +220,7 @@ namespace osu.Game
// The next time this is updated is in UpdateAfterChildren, which occurs too late and results // The next time this is updated is in UpdateAfterChildren, which occurs too late and results
// in the cursor being shown for a few frames during the intro. // in the cursor being shown for a few frames during the intro.
// This prevents the cursor from showing until we have a screen with CursorVisible = true // This prevents the cursor from showing until we have a screen with CursorVisible = true
CursorOverrideContainer.CanShowCursor = currentScreen?.CursorVisible ?? false; MenuCursorContainer.CanShowCursor = currentScreen?.CursorVisible ?? false;
// hook up notifications to components. // hook up notifications to components.
SkinManager.PostNotification = n => notifications?.Post(n); SkinManager.PostNotification = n => notifications?.Post(n);
@ -548,7 +548,7 @@ namespace osu.Game
mainContent.Padding = new MarginPadding { Top = ToolbarOffset }; mainContent.Padding = new MarginPadding { Top = ToolbarOffset };
CursorOverrideContainer.CanShowCursor = currentScreen?.CursorVisible ?? false; MenuCursorContainer.CanShowCursor = currentScreen?.CursorVisible ?? false;
} }
private void screenAdded(Screen newScreen) private void screenAdded(Screen newScreen)

View File

@ -56,7 +56,7 @@ namespace osu.Game
protected SettingsStore SettingsStore; protected SettingsStore SettingsStore;
protected CursorOverrideContainer CursorOverrideContainer; protected MenuCursorContainer MenuCursorContainer;
protected override string MainResourceFile => @"osu.Game.Resources.dll"; protected override string MainResourceFile => @"osu.Game.Resources.dll";
@ -173,14 +173,14 @@ namespace osu.Game
GlobalActionContainer globalBinding; GlobalActionContainer globalBinding;
CursorOverrideContainer = new CursorOverrideContainer { RelativeSizeAxes = Axes.Both }; MenuCursorContainer = new MenuCursorContainer { RelativeSizeAxes = Axes.Both };
CursorOverrideContainer.Child = globalBinding = new GlobalActionContainer(this) MenuCursorContainer.Child = globalBinding = new GlobalActionContainer(this)
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Child = content = new OsuTooltipContainer(CursorOverrideContainer.Cursor) { RelativeSizeAxes = Axes.Both } Child = content = new OsuTooltipContainer(MenuCursorContainer.Cursor) { RelativeSizeAxes = Axes.Both }
}; };
base.Content.Add(new DrawSizePreservingFillContainer { Child = CursorOverrideContainer }); base.Content.Add(new DrawSizePreservingFillContainer { Child = MenuCursorContainer });
KeyBindingStore.Register(globalBinding); KeyBindingStore.Register(globalBinding);
dependencies.Cache(globalBinding); dependencies.Cache(globalBinding);

View File

@ -11,6 +11,7 @@ using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Drawables; using osu.Game.Beatmaps.Drawables;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
using osu.Game.Overlays.BeatmapSet.Buttons; using osu.Game.Overlays.BeatmapSet.Buttons;
using OpenTK; using OpenTK;
using OpenTK.Graphics; using OpenTK.Graphics;
@ -93,6 +94,7 @@ namespace osu.Game.Overlays.BeatmapSet
public Header() public Header()
{ {
ExternalLinkButton externalLink;
RelativeSizeAxes = Axes.X; RelativeSizeAxes = Axes.X;
Height = 400; Height = 400;
Masking = true; Masking = true;
@ -160,10 +162,24 @@ namespace osu.Game.Overlays.BeatmapSet
Height = 113, Height = 113,
Child = Picker = new BeatmapPicker(), Child = Picker = new BeatmapPicker(),
}, },
title = new OsuSpriteText new FillFlowContainer
{ {
Font = @"Exo2.0-BoldItalic", Direction = FillDirection.Horizontal,
TextSize = 37, AutoSizeAxes = Axes.Both,
Children = new Drawable[]
{
title = new OsuSpriteText
{
Font = @"Exo2.0-BoldItalic",
TextSize = 37,
},
externalLink = new ExternalLinkButton
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
Margin = new MarginPadding { Left = 3, Bottom = 4 }, //To better lineup with the font
},
}
}, },
artist = new OsuSpriteText artist = new OsuSpriteText
{ {
@ -247,6 +263,7 @@ namespace osu.Game.Overlays.BeatmapSet
}; };
Picker.Beatmap.ValueChanged += b => Details.Beatmap = b; Picker.Beatmap.ValueChanged += b => Details.Beatmap = b;
Picker.Beatmap.ValueChanged += b => externalLink.Link = $@"https://osu.ppy.sh/beatmapsets/{BeatmapSet?.OnlineBeatmapSetID}#{b?.Ruleset.ShortName}/{b?.OnlineBeatmapID}";
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]

View File

@ -101,7 +101,7 @@ namespace osu.Game.Overlays.Music
private void updateSelectedSet() private void updateSelectedSet()
{ {
foreach (PlaylistItem s in items.Children) foreach (PlaylistItem s in items.Children)
s.Selected = s.BeatmapSetInfo.ID == beatmapBacking.Value.BeatmapSetInfo.ID; s.Selected = s.BeatmapSetInfo.ID == beatmapBacking.Value.BeatmapSetInfo?.ID;
} }
public string SearchTerm public string SearchTerm

View File

@ -81,7 +81,10 @@ namespace osu.Game.Overlays.Music
{ {
BeatmapInfo toSelect = list.FirstVisibleSet?.Beatmaps?.FirstOrDefault(); BeatmapInfo toSelect = list.FirstVisibleSet?.Beatmaps?.FirstOrDefault();
if (toSelect != null) if (toSelect != null)
{
beatmap.Value = beatmaps.GetWorkingBeatmap(toSelect); beatmap.Value = beatmaps.GetWorkingBeatmap(toSelect);
beatmap.Value.Track.Restart();
}
}; };
} }
@ -111,6 +114,7 @@ namespace osu.Game.Overlays.Music
} }
beatmap.Value = beatmaps.GetWorkingBeatmap(set.Beatmaps.First()); beatmap.Value = beatmaps.GetWorkingBeatmap(set.Beatmaps.First());
beatmap.Value.Track.Restart();
} }
} }

View File

@ -2,7 +2,6 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System; using System;
using System.Diagnostics;
using OpenTK; using OpenTK;
using OpenTK.Graphics; using OpenTK.Graphics;
using osu.Framework.Allocation; using osu.Framework.Allocation;
@ -10,13 +9,13 @@ using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures; using osu.Framework.Graphics.Textures;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.Containers; using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
using osu.Game.Overlays.Profile.Header; using osu.Game.Overlays.Profile.Header;
using osu.Game.Users; using osu.Game.Users;
@ -105,11 +104,28 @@ namespace osu.Game.Overlays.Profile
Y = -75, Y = -75,
Size = new Vector2(25, 25) Size = new Vector2(25, 25)
}, },
new ProfileLink(user) new FillFlowContainer
{ {
Direction = FillDirection.Horizontal,
AutoSizeAxes = Axes.Both,
Anchor = Anchor.BottomLeft, Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft, Origin = Anchor.BottomLeft,
Y = -48, Y = -48,
Children = new Drawable[]
{
new OsuSpriteText
{
Text = user.Username,
Font = @"Exo2.0-RegularItalic",
TextSize = 30,
},
new ExternalLinkButton($@"https://osu.ppy.sh/users/{user.Id}")
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
Margin = new MarginPadding { Left = 3, Bottom = 3 }, //To better lineup with the font
},
}
}, },
countryFlag = new DrawableFlag(user.Country) countryFlag = new DrawableFlag(user.Country)
{ {
@ -455,28 +471,6 @@ namespace osu.Game.Overlays.Profile
infoTextRight.NewLine(); infoTextRight.NewLine();
} }
private class ProfileLink : OsuHoverContainer, IHasTooltip
{
public string TooltipText => "View Profile in Browser";
public override bool HandleMouseInput => true;
public ProfileLink(User user)
{
Action = () => Process.Start($@"https://osu.ppy.sh/users/{user.Id}");
AutoSizeAxes = Axes.Both;
Child = new OsuSpriteText
{
Text = user.Username,
Font = @"Exo2.0-RegularItalic",
TextSize = 30,
};
}
}
private class GradeBadge : Container private class GradeBadge : Container
{ {
private const float width = 50; private const float width = 50;

View File

@ -48,7 +48,7 @@ namespace osu.Game.Screens.Edit
{ {
// TODO: should probably be done at a RulesetContainer level to share logic with Player. // TODO: should probably be done at a RulesetContainer level to share logic with Player.
var sourceClock = (IAdjustableClock)Beatmap.Value.Track ?? new StopwatchClock(); var sourceClock = (IAdjustableClock)Beatmap.Value.Track ?? new StopwatchClock();
clock = new EditorClock(Beatmap.Value.Beatmap.ControlPointInfo, beatDivisor) { IsCoupled = false }; clock = new EditorClock(Beatmap.Value, beatDivisor) { IsCoupled = false };
clock.ChangeSource(sourceClock); clock.ChangeSource(sourceClock);
dependencies.CacheAs<IFrameBasedClock>(clock); dependencies.CacheAs<IFrameBasedClock>(clock);

View File

@ -5,8 +5,10 @@ using System;
using System.Linq; using System.Linq;
using osu.Framework.MathUtils; using osu.Framework.MathUtils;
using osu.Framework.Timing; using osu.Framework.Timing;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints; using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Screens.Edit.Screens.Compose; using osu.Game.Screens.Edit.Screens.Compose;
using OpenTK;
namespace osu.Game.Screens.Edit namespace osu.Game.Screens.Edit
{ {
@ -15,15 +17,26 @@ namespace osu.Game.Screens.Edit
/// </summary> /// </summary>
public class EditorClock : DecoupleableInterpolatingFramedClock public class EditorClock : DecoupleableInterpolatingFramedClock
{ {
public readonly double TrackLength;
public ControlPointInfo ControlPointInfo; public ControlPointInfo ControlPointInfo;
private readonly BindableBeatDivisor beatDivisor; private readonly BindableBeatDivisor beatDivisor;
public EditorClock(ControlPointInfo controlPointInfo, BindableBeatDivisor beatDivisor) public EditorClock(WorkingBeatmap beatmap, BindableBeatDivisor beatDivisor)
{
this.beatDivisor = beatDivisor;
ControlPointInfo = beatmap.Beatmap.ControlPointInfo;
TrackLength = beatmap.Track.Length;
}
public EditorClock(ControlPointInfo controlPointInfo, double trackLength, BindableBeatDivisor beatDivisor)
{ {
this.beatDivisor = beatDivisor; this.beatDivisor = beatDivisor;
ControlPointInfo = controlPointInfo; ControlPointInfo = controlPointInfo;
TrackLength = trackLength;
} }
/// <summary> /// <summary>
@ -111,6 +124,8 @@ namespace osu.Game.Screens.Edit
if (seekTime > nextTimingPoint?.Time) if (seekTime > nextTimingPoint?.Time)
seekTime = nextTimingPoint.Time; seekTime = nextTimingPoint.Time;
// Ensure the sought point is within the boundaries
seekTime = MathHelper.Clamp(seekTime, 0, TrackLength);
Seek(seekTime); Seek(seekTime);
} }
} }

View File

@ -2,6 +2,7 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System; using System;
using System.Collections.Generic;
using osu.Framework; using osu.Framework;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Configuration; using osu.Framework.Configuration;
@ -9,6 +10,7 @@ using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Input;
using osu.Framework.Localisation; using osu.Framework.Localisation;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Drawables; using osu.Game.Beatmaps.Drawables;
@ -23,11 +25,11 @@ using OpenTK.Graphics;
namespace osu.Game.Screens.Multi.Components namespace osu.Game.Screens.Multi.Components
{ {
public class DrawableRoom : OsuClickableContainer, IStateful<SelectionState> public class DrawableRoom : OsuClickableContainer, IStateful<SelectionState>, IFilterable
{ {
public const float SELECTION_BORDER_WIDTH = 4;
private const float corner_radius = 5; private const float corner_radius = 5;
private const float selection_border_width = 4; private const float transition_duration = 60;
private const float transition_duration = 100;
private const float content_padding = 10; private const float content_padding = 10;
private const float height = 100; private const float height = 100;
private const float side_strip_width = 5; private const float side_strip_width = 5;
@ -62,6 +64,30 @@ namespace osu.Game.Screens.Multi.Components
} }
} }
public IEnumerable<string> FilterTerms => new[] { Room.Name.Value };
private bool matchingFilter;
public bool MatchingFilter
{
get { return matchingFilter; }
set
{
matchingFilter = value;
this.FadeTo(MatchingFilter ? 1 : 0, 200);
}
}
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 event Action<SelectionState> StateChanged;
public DrawableRoom(Room room) public DrawableRoom(Room room)
@ -69,8 +95,8 @@ namespace osu.Game.Screens.Multi.Components
Room = room; Room = room;
RelativeSizeAxes = Axes.X; RelativeSizeAxes = Axes.X;
Height = height + selection_border_width * 2; Height = height + SELECTION_BORDER_WIDTH * 2;
CornerRadius = corner_radius + selection_border_width / 2; CornerRadius = corner_radius + SELECTION_BORDER_WIDTH / 2;
Masking = true; Masking = true;
// create selectionBox here so State can be set before being loaded // create selectionBox here so State can be set before being loaded
@ -79,8 +105,6 @@ namespace osu.Game.Screens.Multi.Components
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Alpha = 0f, Alpha = 0f,
}; };
Action += () => State = SelectionState.Selected;
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
@ -98,7 +122,7 @@ namespace osu.Game.Screens.Multi.Components
new Container new Container
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding(selection_border_width), Padding = new MarginPadding(SELECTION_BORDER_WIDTH),
Child = new Container Child = new Container
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
@ -230,7 +254,7 @@ namespace osu.Game.Screens.Multi.Components
status.Text = s.Message; status.Text = s.Message;
foreach (Drawable d in new Drawable[] { selectionBox, sideStrip, status }) foreach (Drawable d in new Drawable[] { selectionBox, sideStrip, status })
d.FadeColour(s.GetAppropriateColour(colours), 100); d.FadeColour(s.GetAppropriateColour(colours), transition_duration);
}; };
beatmapBind.ValueChanged += b => beatmapBind.ValueChanged += b =>
@ -272,5 +296,22 @@ namespace osu.Game.Screens.Multi.Components
beatmapBind.BindTo(Room.Beatmap); beatmapBind.BindTo(Room.Beatmap);
participantsBind.BindTo(Room.Participants); participantsBind.BindTo(Room.Participants);
} }
protected override void LoadComplete()
{
base.LoadComplete();
this.FadeInFromZero(transition_duration);
}
protected override bool OnClick(InputState state)
{
if (Enabled.Value)
{
Action?.Invoke(this);
State = SelectionState.Selected;
}
return true;
}
} }
} }

View File

@ -10,6 +10,7 @@ using osu.Game.Graphics;
using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
using osu.Game.Overlays.SearchableList; using osu.Game.Overlays.SearchableList;
using osu.Game.Screens.Multi.Screens;
using OpenTK; using OpenTK;
using OpenTK.Graphics; using OpenTK.Graphics;
@ -85,7 +86,7 @@ namespace osu.Game.Screens.Multi
}, },
}; };
breadcrumbs.Current.ValueChanged += s => screenTitle.Text = s.ToString(); breadcrumbs.Current.ValueChanged += s => screenTitle.Text = ((MultiplayerScreen)s).Title;
breadcrumbs.Current.TriggerChange(); breadcrumbs.Current.TriggerChange();
} }

View File

@ -8,7 +8,8 @@ using osu.Framework.Screens;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.Backgrounds; using osu.Game.Graphics.Backgrounds;
using osu.Game.Graphics.Containers; using osu.Game.Graphics.Containers;
using osu.Game.Screens.Multi.Screens; using osu.Game.Screens.Menu;
using osu.Game.Screens.Multi.Screens.Lounge;
namespace osu.Game.Screens.Multi namespace osu.Game.Screens.Multi
{ {
@ -25,7 +26,7 @@ namespace osu.Game.Screens.Multi
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
}; };
Lobby lobby; Lounge lounge;
Children = new Drawable[] Children = new Drawable[]
{ {
new Container new Container
@ -52,12 +53,12 @@ namespace osu.Game.Screens.Multi
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding { Top = Header.HEIGHT }, Padding = new MarginPadding { Top = Header.HEIGHT },
Child = lobby = new Lobby(), Child = lounge = new Lounge(),
}, },
new Header(lobby), new Header(lounge),
}; };
lobby.Exited += s => Exit(); lounge.Exited += s => Exit();
} }
protected override void OnEntering(Screen last) protected override void OnEntering(Screen last)
@ -84,6 +85,13 @@ namespace osu.Game.Screens.Multi
waves.Hide(); waves.Hide();
} }
protected override void LogoExiting(OsuLogo logo)
{
// the wave overlay transition takes longer than expected to run.
logo.Delay(WaveContainer.DISAPPEAR_DURATION / 2).FadeOut();
base.LogoExiting(logo);
}
private class MultiplayerWaveContainer : WaveContainer private class MultiplayerWaveContainer : WaveContainer
{ {
protected override bool StartHidden => true; protected override bool StartHidden => true;

View File

@ -1,16 +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 System;
using System.Collections.Generic;
namespace osu.Game.Screens.Multi.Screens
{
public class Lobby : ScreenWhiteBox
{
protected override IEnumerable<Type> PossibleChildren => new[] {
typeof(MatchCreate),
typeof(Match)
};
}
}

View File

@ -0,0 +1,27 @@
// 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.Graphics;
using osu.Game.Online.Multiplayer;
using osu.Game.Overlays.SearchableList;
using OpenTK.Graphics;
namespace osu.Game.Screens.Multi.Screens.Lounge
{
public class FilterControl : SearchableListFilterControl<LoungeTab, LoungeTab>
{
protected override Color4 BackgroundColour => OsuColour.FromHex(@"362e42");
protected override LoungeTab DefaultTab => LoungeTab.Public;
public FilterControl()
{
DisplayStyleControl.Hide();
}
}
public enum LoungeTab
{
Public = RoomAvailability.Public,
Private = RoomAvailability.FriendsOnly,
}
}

View File

@ -0,0 +1,191 @@
// 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.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Input;
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 OpenTK;
namespace osu.Game.Screens.Multi.Screens.Lounge
{
public class Lounge : MultiplayerScreen
{
private readonly Container content;
private readonly SearchContainer search;
protected readonly FilterControl Filter;
protected readonly FillFlowContainer<DrawableRoom> RoomsContainer;
protected readonly RoomInspector Inspector;
public override string Title => "lounge";
protected override Container<Drawable> TransitionContent => content;
private IEnumerable<Room> rooms;
public IEnumerable<Room> Rooms
{
get { return rooms; }
set
{
if (Equals(value, rooms)) return;
rooms = value;
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(),
content = new Container
{
RelativeSizeAxes = Axes.Both,
Children = new Drawable[]
{
new ScrollContainer
{
RelativeSizeAxes = Axes.Both,
Width = 0.55f,
Padding = new MarginPadding
{
Vertical = 35 - DrawableRoom.SELECTION_BORDER_WIDTH,
Right = 20 - DrawableRoom.SELECTION_BORDER_WIDTH
},
Child = search = new SearchContainer
{
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),
},
},
},
Inspector = new RoomInspector
{
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
RelativeSizeAxes = Axes.Both,
Width = 0.45f,
},
},
},
};
Filter.Search.Current.ValueChanged += s => filterRooms();
Filter.Tabs.Current.ValueChanged += t => filterRooms();
Filter.Search.Exit += Exit;
}
protected override void UpdateAfterChildren()
{
base.UpdateAfterChildren();
content.Padding = new MarginPadding
{
Top = Filter.DrawHeight,
Left = SearchableListOverlay.WIDTH_PADDING - DrawableRoom.SELECTION_BORDER_WIDTH,
Right = SearchableListOverlay.WIDTH_PADDING,
};
}
protected override void OnFocus(InputState state)
{
GetContainingInputManager().ChangeFocus(Filter.Search);
}
protected override void OnEntering(Screen last)
{
base.OnEntering(last);
Filter.Search.HoldFocus = true;
}
protected override bool OnExiting(Screen next)
{
Filter.Search.HoldFocus = false;
return base.OnExiting(next);
}
protected override void OnResuming(Screen last)
{
base.OnResuming(last);
Filter.Search.HoldFocus = true;
}
protected override void OnSuspending(Screen next)
{
base.OnSuspending(next);
Filter.Search.HoldFocus = false;
}
private void filterRooms()
{
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;
}
}
private void didSelect(DrawableRoom room)
{
RoomsContainer.Children.ForEach(c =>
{
if (c != room)
c.State = SelectionState.NotSelected;
});
Inspector.Room = room.Room;
// open the room if its selected and is clicked again
if (room.State == SelectionState.Selected)
Push(new Match());
}
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;
}
}
}
}

View File

@ -0,0 +1,52 @@
// 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.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Screens;
using osu.Game.Graphics.Containers;
namespace osu.Game.Screens.Multi.Screens
{
public abstract class MultiplayerScreen : OsuScreen
{
private const Easing in_easing = Easing.OutQuint;
private const Easing out_easing = Easing.InSine;
protected virtual Container<Drawable> TransitionContent => Content;
protected override void OnEntering(Screen last)
{
base.OnEntering(last);
TransitionContent.MoveToX(200);
TransitionContent.FadeInFromZero(WaveContainer.APPEAR_DURATION, in_easing);
TransitionContent.MoveToX(0, WaveContainer.APPEAR_DURATION, in_easing);
}
protected override bool OnExiting(Screen next)
{
Content.FadeOut(WaveContainer.DISAPPEAR_DURATION, out_easing);
TransitionContent.MoveToX(200, WaveContainer.DISAPPEAR_DURATION, out_easing);
return base.OnExiting(next);
}
protected override void OnResuming(Screen last)
{
base.OnResuming(last);
Content.FadeIn(WaveContainer.APPEAR_DURATION, in_easing);
TransitionContent.MoveToX(0, WaveContainer.APPEAR_DURATION, in_easing);
}
protected override void OnSuspending(Screen next)
{
base.OnSuspending(next);
Content.FadeOut(WaveContainer.DISAPPEAR_DURATION, out_easing);
TransitionContent.MoveToX(-200, WaveContainer.DISAPPEAR_DURATION, out_easing);
}
}
}

View File

@ -1,6 +1,7 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using Microsoft.EntityFrameworkCore.Internal;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Audio; using osu.Framework.Audio;
using osu.Framework.Audio.Sample; using osu.Framework.Audio.Sample;
@ -19,10 +20,17 @@ using OpenTK.Input;
namespace osu.Game.Screens namespace osu.Game.Screens
{ {
public abstract class OsuScreen : Screen, IKeyBindingHandler<GlobalAction> public abstract class OsuScreen : Screen, IKeyBindingHandler<GlobalAction>, IHasDescription
{ {
public BackgroundScreen Background { get; private set; } public BackgroundScreen Background { get; private set; }
/// <summary>
/// A user-facing title for this screen.
/// </summary>
public virtual string Title => GetType().ShortDisplayName();
public string Description => Title;
protected virtual bool AllowBackButton => true; protected virtual bool AllowBackButton => true;
/// <summary> /// <summary>

View File

@ -70,7 +70,7 @@ namespace osu.Game.Screens.Play
private SampleChannel sampleRestart; private SampleChannel sampleRestart;
private ScoreProcessor scoreProcessor; protected ScoreProcessor ScoreProcessor;
protected RulesetContainer RulesetContainer; protected RulesetContainer RulesetContainer;
private HUDOverlay hudOverlay; private HUDOverlay hudOverlay;
@ -149,7 +149,7 @@ namespace osu.Game.Screens.Play
userAudioOffset.ValueChanged += v => offsetClock.Offset = v; userAudioOffset.ValueChanged += v => offsetClock.Offset = v;
userAudioOffset.TriggerChange(); userAudioOffset.TriggerChange();
scoreProcessor = RulesetContainer.CreateScoreProcessor(); ScoreProcessor = RulesetContainer.CreateScoreProcessor();
Children = new Drawable[] Children = new Drawable[]
{ {
@ -176,7 +176,7 @@ namespace osu.Game.Screens.Play
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Child = RulesetContainer Child = RulesetContainer
}, },
new BreakOverlay(beatmap.BeatmapInfo.LetterboxInBreaks, scoreProcessor) new BreakOverlay(beatmap.BeatmapInfo.LetterboxInBreaks, ScoreProcessor)
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
@ -184,7 +184,7 @@ namespace osu.Game.Screens.Play
Breaks = beatmap.Breaks Breaks = beatmap.Breaks
}, },
RulesetContainer.Cursor?.CreateProxy() ?? new Container(), RulesetContainer.Cursor?.CreateProxy() ?? new Container(),
hudOverlay = new HUDOverlay(scoreProcessor, RulesetContainer, working, offsetClock, adjustableClock) hudOverlay = new HUDOverlay(ScoreProcessor, RulesetContainer, working, offsetClock, adjustableClock)
{ {
Clock = Clock, // hud overlay doesn't want to use the audio clock directly Clock = Clock, // hud overlay doesn't want to use the audio clock directly
ProcessCustomClock = false, ProcessCustomClock = false,
@ -225,11 +225,11 @@ namespace osu.Game.Screens.Play
initializeStoryboard(false); initializeStoryboard(false);
// Bind ScoreProcessor to ourselves // Bind ScoreProcessor to ourselves
scoreProcessor.AllJudged += onCompletion; ScoreProcessor.AllJudged += onCompletion;
scoreProcessor.Failed += onFail; ScoreProcessor.Failed += onFail;
foreach (var mod in Beatmap.Value.Mods.Value.OfType<IApplicableToScoreProcessor>()) foreach (var mod in Beatmap.Value.Mods.Value.OfType<IApplicableToScoreProcessor>())
mod.ApplyToScoreProcessor(scoreProcessor); mod.ApplyToScoreProcessor(ScoreProcessor);
} }
private void applyRateFromMods() private void applyRateFromMods()
@ -254,7 +254,7 @@ namespace osu.Game.Screens.Play
private void onCompletion() private void onCompletion()
{ {
// Only show the completion screen if the player hasn't failed // Only show the completion screen if the player hasn't failed
if (scoreProcessor.HasFailed || onCompletionEvent != null) if (ScoreProcessor.HasFailed || onCompletionEvent != null)
return; return;
ValidForResume = false; ValidForResume = false;
@ -272,7 +272,7 @@ namespace osu.Game.Screens.Play
Beatmap = Beatmap.Value.BeatmapInfo, Beatmap = Beatmap.Value.BeatmapInfo,
Ruleset = ruleset Ruleset = ruleset
}; };
scoreProcessor.PopulateScore(score); ScoreProcessor.PopulateScore(score);
score.User = RulesetContainer.Replay?.User ?? api.LocalUser.Value; score.User = RulesetContainer.Replay?.User ?? api.LocalUser.Value;
Push(new Results(score)); Push(new Results(score));
}); });

View File

@ -7,15 +7,15 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Framework.Input; using osu.Framework.Input;
using osu.Framework.Localisation;
using osu.Framework.Screens; using osu.Framework.Screens;
using osu.Framework.Threading;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Sprites;
using OpenTK;
using osu.Framework.Localisation;
using osu.Framework.Threading;
using osu.Game.Screens.Menu; using osu.Game.Screens.Menu;
using osu.Game.Screens.Play.PlayerSettings; using osu.Game.Screens.Play.PlayerSettings;
using OpenTK;
namespace osu.Game.Screens.Play namespace osu.Game.Screens.Play
{ {
@ -51,11 +51,19 @@ namespace osu.Game.Screens.Play
Origin = Anchor.Centre, Origin = Anchor.Centre,
}); });
Add(new VisualSettings Add(new FillFlowContainer<PlayerSettingsGroup>
{ {
Anchor = Anchor.TopRight, Anchor = Anchor.TopRight,
Origin = Anchor.TopRight, Origin = Anchor.TopRight,
Margin = new MarginPadding(25) AutoSizeAxes = Axes.Both,
Direction = FillDirection.Vertical,
Spacing = new Vector2(0, 20),
Margin = new MarginPadding(25),
Children = new PlayerSettingsGroup[]
{
new VisualSettings(),
new InputSettings()
}
}); });
loadTask = LoadComponentAsync(player); loadTask = LoadComponentAsync(player);

View File

@ -0,0 +1,30 @@
// 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.Graphics;
using osu.Game.Configuration;
namespace osu.Game.Screens.Play.PlayerSettings
{
public class InputSettings : PlayerSettingsGroup
{
protected override string Title => "Input settings";
private readonly PlayerCheckbox mouseButtonsCheckbox;
public InputSettings()
{
Children = new Drawable[]
{
mouseButtonsCheckbox = new PlayerCheckbox
{
LabelText = "Disable mouse buttons"
}
};
}
[BackgroundDependencyLoader]
private void load(OsuConfigManager config) => mouseButtonsCheckbox.Bindable = config.GetBindable<bool>(OsuSetting.MouseDisableButtons);
}
}

View File

@ -27,7 +27,7 @@ namespace osu.Game.Tests.Visual
protected EditorClockTestCase() protected EditorClockTestCase()
{ {
Clock = new EditorClock(new ControlPointInfo(), BeatDivisor) { IsCoupled = false }; Clock = new EditorClock(new ControlPointInfo(), 5000, BeatDivisor) { IsCoupled = false };
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]

View File

@ -42,7 +42,7 @@ namespace osu.Game.Tests.Visual
{ {
Player p = null; Player p = null;
AddStep(ruleset.RulesetInfo.Name, () => p = loadPlayerFor(ruleset)); AddStep(ruleset.RulesetInfo.Name, () => p = loadPlayerFor(ruleset));
AddUntilStep(() => p.IsLoaded); AddUntilStep(() => ContinueCondition(p));
} }
else else
{ {
@ -50,11 +50,13 @@ namespace osu.Game.Tests.Visual
{ {
Player p = null; Player p = null;
AddStep(r.Name, () => p = loadPlayerFor(r)); AddStep(r.Name, () => p = loadPlayerFor(r));
AddUntilStep(() => p.IsLoaded); AddUntilStep(() => ContinueCondition(p));
} }
} }
} }
protected virtual bool ContinueCondition(Player player) => player.IsLoaded;
protected virtual IBeatmap CreateBeatmap(Ruleset ruleset) => new TestBeatmap(ruleset.RulesetInfo); protected virtual IBeatmap CreateBeatmap(Ruleset ruleset) => new TestBeatmap(ruleset.RulesetInfo);
private Player loadPlayerFor(RulesetInfo ri) => loadPlayerFor(ri.CreateInstance()); private Player loadPlayerFor(RulesetInfo ri) => loadPlayerFor(ri.CreateInstance());