Merge branch 'master' into fix-changelog-crash

This commit is contained in:
Dean Herbert 2020-07-07 21:32:59 +09:00 committed by GitHub
commit bfcf2f1d92
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 474 additions and 292 deletions

View File

@ -9,7 +9,7 @@ using osu.Framework.Android;
namespace osu.Android
{
[Activity(Theme = "@android:style/Theme.NoTitleBar", MainLauncher = true, ScreenOrientation = ScreenOrientation.FullSensor, SupportsPictureInPicture = false, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize, HardwareAccelerated = true)]
[Activity(Theme = "@android:style/Theme.NoTitleBar", MainLauncher = true, ScreenOrientation = ScreenOrientation.FullSensor, SupportsPictureInPicture = false, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize, HardwareAccelerated = false)]
public class OsuGameActivity : AndroidGameActivity
{
protected override Framework.Game CreateGame() => new OsuGameAndroid();

View File

@ -9,4 +9,6 @@ Hit50: mania/hit50
Hit100: mania/hit100
Hit200: mania/hit200
Hit300: mania/hit300
Hit300g: mania/hit300g
Hit300g: mania/hit300g
StageLeft: mania/stage-left
StageRight: mania/stage-right

View File

@ -14,6 +14,7 @@ using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Utils;
using osu.Game.Rulesets.Scoring;
using osu.Game.Screens.Ranking;
@ -193,9 +194,10 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
SpmCounter.SetRotation(Disc.RotationAbsolute);
float relativeCircleScale = Spinner.Scale * circle.DrawHeight / mainContainer.DrawHeight;
Disc.ScaleTo(relativeCircleScale + (1 - relativeCircleScale) * Progress, 200, Easing.OutQuint);
float targetScale = relativeCircleScale + (1 - relativeCircleScale) * Progress;
Disc.Scale = new Vector2((float)Interpolation.Lerp(Disc.Scale.X, targetScale, Math.Clamp(Math.Abs(Time.Elapsed) / 100, 0, 1)));
symbol.RotateTo(Disc.Rotation / 2, 500, Easing.OutQuint);
symbol.Rotation = (float)Interpolation.Lerp(symbol.Rotation, Disc.RotationAbsolute / 2, Math.Clamp(Math.Abs(Time.Elapsed) / 40, 0, 1));
}
protected override void UpdateInitialTransforms()

View File

@ -1,32 +0,0 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Screens.Multi.Match.Components;
using osuTK;
namespace osu.Game.Tests.Visual.Multiplayer
{
public class TestSceneMatchLeaderboardChatDisplay : MultiplayerTestScene
{
protected override bool UseOnlineAPI => true;
public TestSceneMatchLeaderboardChatDisplay()
{
Room.RoomID.Value = 7;
Add(new Container
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Size = new Vector2(500),
Child = new LeaderboardChatDisplay
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
}
});
}
}
}

View File

@ -58,6 +58,23 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddUntilStep("wait for load", () => match.IsCurrentScreen());
}
[Test]
public void TestLoadSimpleMatch()
{
AddStep("set room properties", () =>
{
Room.RoomID.Value = 1;
Room.Name.Value = "my awesome room";
Room.Host.Value = new User { Id = 2, Username = "peppy" };
Room.RecentParticipants.Add(Room.Host.Value);
Room.Playlist.Add(new PlaylistItem
{
Beatmap = { Value = new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo },
Ruleset = { Value = new OsuRuleset().RulesetInfo }
});
});
}
[Test]
public void TestPlaylistItemSelectedOnCreate()
{

View File

@ -2,9 +2,11 @@
// See the LICENCE file in the repository root for full licence text.
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
using JetBrains.Annotations;
using osu.Framework.Logging;
using osu.Framework.Platform;
using osu.Game.Configuration;
@ -13,12 +15,30 @@ namespace osu.Game.IO
{
public class OsuStorage : WrappedStorage
{
/// <summary>
/// Indicates the error (if any) that occurred when initialising the custom storage during initial startup.
/// </summary>
public readonly OsuStorageError Error;
/// <summary>
/// The custom storage path as selected by the user.
/// </summary>
[CanBeNull]
public string CustomStoragePath => storageConfig.Get<string>(StorageConfig.FullPath);
/// <summary>
/// The default storage path to be used if a custom storage path hasn't been selected or is not accessible.
/// </summary>
[NotNull]
public string DefaultStoragePath => defaultStorage.GetFullPath(".");
private readonly GameHost host;
private readonly StorageConfigManager storageConfig;
private readonly Storage defaultStorage;
internal static readonly string[] IGNORE_DIRECTORIES = { "cache" };
public static readonly string[] IGNORE_DIRECTORIES = { "cache" };
internal static readonly string[] IGNORE_FILES =
public static readonly string[] IGNORE_FILES =
{
"framework.ini",
"storage.ini"
@ -28,13 +48,53 @@ namespace osu.Game.IO
: base(defaultStorage, string.Empty)
{
this.host = host;
this.defaultStorage = defaultStorage;
storageConfig = new StorageConfigManager(defaultStorage);
var customStoragePath = storageConfig.Get<string>(StorageConfig.FullPath);
if (!string.IsNullOrEmpty(CustomStoragePath))
TryChangeToCustomStorage(out Error);
}
if (!string.IsNullOrEmpty(customStoragePath))
ChangeTargetStorage(host.GetStorage(customStoragePath));
/// <summary>
/// Resets the custom storage path, changing the target storage to the default location.
/// </summary>
public void ResetCustomStoragePath()
{
storageConfig.Set(StorageConfig.FullPath, string.Empty);
storageConfig.Save();
ChangeTargetStorage(defaultStorage);
}
/// <summary>
/// Attempts to change to the user's custom storage path.
/// </summary>
/// <param name="error">The error that occurred.</param>
/// <returns>Whether the custom storage path was used successfully. If not, <paramref name="error"/> will be populated with the reason.</returns>
public bool TryChangeToCustomStorage(out OsuStorageError error)
{
Debug.Assert(!string.IsNullOrEmpty(CustomStoragePath));
error = OsuStorageError.None;
Storage lastStorage = UnderlyingStorage;
try
{
Storage userStorage = host.GetStorage(CustomStoragePath);
if (!userStorage.ExistsDirectory(".") || !userStorage.GetFiles(".").Any())
error = OsuStorageError.AccessibleButEmpty;
ChangeTargetStorage(userStorage);
}
catch
{
error = OsuStorageError.NotAccessible;
ChangeTargetStorage(lastStorage);
}
return error == OsuStorageError.None;
}
protected override void ChangeTargetStorage(Storage newStorage)
@ -145,4 +205,23 @@ namespace osu.Game.IO
}
}
}
public enum OsuStorageError
{
/// <summary>
/// No error.
/// </summary>
None,
/// <summary>
/// Occurs when the target storage directory is accessible but does not already contain game files.
/// Only happens when the user changes the storage directory and then moves the files manually or mounts a different device to the same path.
/// </summary>
AccessibleButEmpty,
/// <summary>
/// Occurs when the target storage directory cannot be accessed at all.
/// </summary>
NotAccessible,
}
}

View File

@ -42,25 +42,34 @@ namespace osu.Game.Overlays.Dialog
set => icon.Icon = value;
}
private string text;
private string headerText;
public string HeaderText
{
get => text;
get => headerText;
set
{
if (text == value)
if (headerText == value)
return;
text = value;
headerText = value;
header.Text = value;
}
}
private string bodyText;
public string BodyText
{
set => body.Text = value;
get => bodyText;
set
{
if (bodyText == value)
return;
bodyText = value;
body.Text = value;
}
}
public IEnumerable<PopupDialogButton> Buttons

View File

@ -47,9 +47,25 @@ namespace osu.Game.Rulesets.Mods
public void ApplyToScoreProcessor(ScoreProcessor scoreProcessor)
{
Combo.BindTo(scoreProcessor.Combo);
// Default value of ScoreProcessor's Rank in Flashlight Mod should be SS+
scoreProcessor.Rank.Value = ScoreRank.XH;
}
public ScoreRank AdjustRank(ScoreRank rank, double accuracy) => rank;
public ScoreRank AdjustRank(ScoreRank rank, double accuracy)
{
switch (rank)
{
case ScoreRank.X:
return ScoreRank.XH;
case ScoreRank.S:
return ScoreRank.SH;
default:
return rank;
}
}
public virtual void ApplyToDrawableRuleset(DrawableRuleset<T> drawableRuleset)
{

View File

@ -0,0 +1,34 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System;
using osu.Framework.Graphics.Sprites;
using osu.Game.Overlays.Dialog;
namespace osu.Game.Screens.Menu
{
public class ConfirmExitDialog : PopupDialog
{
public ConfirmExitDialog(Action confirm, Action cancel)
{
HeaderText = "Are you sure you want to exit?";
BodyText = "Last chance to back out.";
Icon = FontAwesome.Solid.ExclamationTriangle;
Buttons = new PopupDialogButton[]
{
new PopupDialogOkButton
{
Text = @"Goodbye",
Action = confirm
},
new PopupDialogCancelButton
{
Text = @"Just a little more",
Action = cancel
},
};
}
}
}

View File

@ -1,7 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System;
using System.Linq;
using osuTK;
using osuTK.Graphics;
@ -9,15 +8,14 @@ using osu.Framework.Allocation;
using osu.Framework.Audio.Track;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Platform;
using osu.Framework.Screens;
using osu.Game.Configuration;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.IO;
using osu.Game.Online.API;
using osu.Game.Overlays;
using osu.Game.Overlays.Dialog;
using osu.Game.Screens.Backgrounds;
using osu.Game.Screens.Edit;
using osu.Game.Screens.Multi;
@ -171,6 +169,9 @@ namespace osu.Game.Screens.Menu
return s;
}
[Resolved]
private Storage storage { get; set; }
public override void OnEntering(IScreen last)
{
base.OnEntering(last);
@ -187,6 +188,9 @@ namespace osu.Game.Screens.Menu
Track.Start();
}
}
if (storage is OsuStorage osuStorage && osuStorage.Error != OsuStorageError.None)
dialogOverlay?.Push(new StorageErrorDialog(osuStorage, osuStorage.Error));
}
private bool exitConfirmed;
@ -283,30 +287,5 @@ namespace osu.Game.Screens.Menu
this.FadeOut(3000);
return base.OnExiting(next);
}
private class ConfirmExitDialog : PopupDialog
{
public ConfirmExitDialog(Action confirm, Action cancel)
{
HeaderText = "Are you sure you want to exit?";
BodyText = "Last chance to back out.";
Icon = FontAwesome.Solid.ExclamationTriangle;
Buttons = new PopupDialogButton[]
{
new PopupDialogOkButton
{
Text = @"Goodbye",
Action = confirm
},
new PopupDialogCancelButton
{
Text = @"Just a little more",
Action = cancel
},
};
}
}
}
}

View File

@ -0,0 +1,79 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic;
using osu.Framework.Allocation;
using osu.Framework.Graphics.Sprites;
using osu.Game.IO;
using osu.Game.Overlays;
using osu.Game.Overlays.Dialog;
namespace osu.Game.Screens.Menu
{
public class StorageErrorDialog : PopupDialog
{
[Resolved]
private DialogOverlay dialogOverlay { get; set; }
[Resolved]
private OsuGameBase osuGame { get; set; }
public StorageErrorDialog(OsuStorage storage, OsuStorageError error)
{
HeaderText = "osu! storage error";
Icon = FontAwesome.Solid.ExclamationTriangle;
var buttons = new List<PopupDialogButton>();
switch (error)
{
case OsuStorageError.NotAccessible:
BodyText = $"The specified osu! data location (\"{storage.CustomStoragePath}\") is not accessible. If it is on external storage, please reconnect the device and try again.";
buttons.AddRange(new PopupDialogButton[]
{
new PopupDialogCancelButton
{
Text = "Try again",
Action = () =>
{
if (!storage.TryChangeToCustomStorage(out var nextError))
dialogOverlay.Push(new StorageErrorDialog(storage, nextError));
}
},
new PopupDialogCancelButton
{
Text = "Use default location until restart",
},
new PopupDialogOkButton
{
Text = "Reset to default location",
Action = storage.ResetCustomStoragePath
},
});
break;
case OsuStorageError.AccessibleButEmpty:
BodyText = $"The specified osu! data location (\"{storage.CustomStoragePath}\") is empty. If you have moved the files, please close osu! and move them back.";
// Todo: Provide the option to search for the files similar to migration.
buttons.AddRange(new PopupDialogButton[]
{
new PopupDialogCancelButton
{
Text = "Start fresh at specified location"
},
new PopupDialogOkButton
{
Text = "Reset to default location",
Action = storage.ResetCustomStoragePath
},
});
break;
}
Buttons = buttons;
}
}
}

View File

@ -35,6 +35,18 @@ namespace osu.Game.Screens.Multi.Components
}
}
private bool showLine = true;
public bool ShowLine
{
get => showLine;
set
{
showLine = value;
line.Alpha = value ? 1 : 0;
}
}
protected string Details
{
set => details.Text = value;
@ -72,9 +84,12 @@ namespace osu.Game.Screens.Multi.Components
new OsuSpriteText
{
Text = title,
Font = OsuFont.GetFont(size: 14)
Font = OsuFont.GetFont(size: 14, weight: FontWeight.SemiBold)
},
details = new OsuSpriteText
{
Font = OsuFont.GetFont(size: 14, weight: FontWeight.SemiBold)
},
details = new OsuSpriteText { Font = OsuFont.GetFont(size: 14) },
}
},
},

View File

@ -79,7 +79,7 @@ namespace osu.Game.Screens.Multi.Components
Direction = Direction,
AutoSizeAxes = AutoSizeAxes,
RelativeSizeAxes = RelativeSizeAxes,
Spacing = new Vector2(10)
Spacing = Vector2.One
};
for (int i = 0; i < RecentParticipants.Count; i++)

View File

@ -1,12 +1,13 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using Humanizer;
using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Screens;
using osu.Game.Graphics;
using osu.Game.Graphics.UserInterface;
@ -19,41 +20,41 @@ namespace osu.Game.Screens.Multi
{
public class Header : Container
{
public const float HEIGHT = 121;
private readonly HeaderBreadcrumbControl breadcrumbs;
public const float HEIGHT = 80;
public Header(ScreenStack stack)
{
MultiHeaderTitle title;
RelativeSizeAxes = Axes.X;
Height = HEIGHT;
HeaderBreadcrumbControl breadcrumbs;
MultiHeaderTitle title;
Children = new Drawable[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = Color4Extensions.FromHex(@"2f2043"),
Colour = Color4Extensions.FromHex(@"#1f1921"),
},
new Container
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding { Horizontal = SearchableListOverlay.WIDTH_PADDING + OsuScreen.HORIZONTAL_OVERFLOW_PADDING },
Padding = new MarginPadding { Left = SearchableListOverlay.WIDTH_PADDING + OsuScreen.HORIZONTAL_OVERFLOW_PADDING },
Children = new Drawable[]
{
title = new MultiHeaderTitle
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.BottomLeft,
X = -MultiHeaderTitle.ICON_WIDTH,
},
breadcrumbs = new HeaderBreadcrumbControl(stack)
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
RelativeSizeAxes = Axes.X,
},
Origin = Anchor.BottomLeft
}
},
},
};
@ -67,32 +68,16 @@ namespace osu.Game.Screens.Multi
breadcrumbs.Current.TriggerChange();
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
private class MultiHeaderTitle : CompositeDrawable
{
breadcrumbs.StripColour = colours.Green;
}
private class MultiHeaderTitle : CompositeDrawable, IHasAccentColour
{
public const float ICON_WIDTH = icon_size + spacing;
private const float icon_size = 25;
private const float spacing = 6;
private const int text_offset = 2;
private readonly SpriteIcon iconSprite;
private readonly OsuSpriteText title, pageText;
private readonly OsuSpriteText dot;
private readonly OsuSpriteText pageTitle;
public IMultiplayerSubScreen Screen
{
set => pageText.Text = value.ShortTitle.ToLowerInvariant();
}
public Color4 AccentColour
{
get => pageText.Colour;
set => pageText.Colour = value;
set => pageTitle.Text = value.ShortTitle.Titleize();
}
public MultiHeaderTitle()
@ -108,32 +93,26 @@ namespace osu.Game.Screens.Multi
Direction = FillDirection.Horizontal,
Children = new Drawable[]
{
iconSprite = new SpriteIcon
{
Size = new Vector2(icon_size),
Anchor = Anchor.Centre,
Origin = Anchor.Centre
},
title = new OsuSpriteText
new OsuSpriteText
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Font = OsuFont.GetFont(size: 20, weight: FontWeight.Bold),
Margin = new MarginPadding { Bottom = text_offset }
Font = OsuFont.GetFont(size: 24),
Text = "Multiplayer"
},
new Circle
dot = new OsuSpriteText
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Size = new Vector2(4),
Colour = Color4.Gray,
Font = OsuFont.GetFont(size: 24),
Text = "·"
},
pageText = new OsuSpriteText
pageTitle = new OsuSpriteText
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Font = OsuFont.GetFont(size: 20),
Margin = new MarginPadding { Bottom = text_offset }
Font = OsuFont.GetFont(size: 24),
Text = "Lounge"
}
}
},
@ -143,9 +122,7 @@ namespace osu.Game.Screens.Multi
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
title.Text = "multi";
iconSprite.Icon = OsuIcon.Multi;
AccentColour = colours.Yellow;
pageTitle.Colour = dot.Colour = colours.Yellow;
}
}
@ -154,12 +131,28 @@ namespace osu.Game.Screens.Multi
public HeaderBreadcrumbControl(ScreenStack stack)
: base(stack)
{
RelativeSizeAxes = Axes.X;
StripColour = Color4.Transparent;
}
protected override void LoadComplete()
{
base.LoadComplete();
AccentColour = Color4.White;
AccentColour = Color4Extensions.FromHex("#e35c99");
}
protected override TabItem<IScreen> CreateTabItem(IScreen value) => new HeaderBreadcrumbTabItem(value)
{
AccentColour = AccentColour
};
private class HeaderBreadcrumbTabItem : BreadcrumbTabItem
{
public HeaderBreadcrumbTabItem(IScreen value)
: base(value)
{
Bar.Colour = Color4.Transparent;
}
}
}
}

View File

@ -16,7 +16,7 @@ namespace osu.Game.Screens.Multi.Match.Components
{
public class Footer : CompositeDrawable
{
public const float HEIGHT = 100;
public const float HEIGHT = 50;
public Action OnStart;
public readonly Bindable<PlaylistItem> SelectedItem = new Bindable<PlaylistItem>();

View File

@ -52,7 +52,7 @@ namespace osu.Game.Screens.Multi.Match.Components
Font = OsuFont.GetFont(size: 30),
Current = { BindTarget = RoomName }
},
hostText = new LinkFlowContainer(s => s.Font = OsuFont.GetFont(size: 20, weight: FontWeight.SemiBold))
hostText = new LinkFlowContainer(s => s.Font = OsuFont.GetFont(size: 20))
{
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Horizontal,
@ -71,7 +71,7 @@ namespace osu.Game.Screens.Multi.Match.Components
if (host.NewValue != null)
{
hostText.AddText("hosted by ");
hostText.AddUserLink(host.NewValue);
hostText.AddUserLink(host.NewValue, s => s.Font = s.Font.With(weight: FontWeight.SemiBold));
}
}, true);
}

View File

@ -1,100 +0,0 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.UserInterface;
using osu.Game.Graphics;
using osu.Game.Graphics.UserInterface;
namespace osu.Game.Screens.Multi.Match.Components
{
public class LeaderboardChatDisplay : MultiplayerComposite
{
private const double fade_duration = 100;
private readonly OsuTabControl<DisplayMode> tabControl;
private readonly MatchLeaderboard leaderboard;
private readonly MatchChatDisplay chat;
public LeaderboardChatDisplay()
{
RelativeSizeAxes = Axes.Both;
InternalChild = new GridContainer
{
RelativeSizeAxes = Axes.Both,
Content = new[]
{
new Drawable[]
{
tabControl = new DisplayModeTabControl
{
RelativeSizeAxes = Axes.X,
Height = 24,
}
},
new Drawable[]
{
new Container
{
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding { Top = 10 },
Children = new Drawable[]
{
leaderboard = new MatchLeaderboard { RelativeSizeAxes = Axes.Both },
chat = new MatchChatDisplay
{
RelativeSizeAxes = Axes.Both,
Alpha = 0
}
}
}
},
},
RowDimensions = new[]
{
new Dimension(GridSizeMode.AutoSize),
}
};
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
tabControl.AccentColour = colours.Yellow;
}
protected override void LoadComplete()
{
base.LoadComplete();
tabControl.Current.BindValueChanged(changeTab);
}
public void RefreshScores() => leaderboard.RefreshScores();
private void changeTab(ValueChangedEvent<DisplayMode> mode)
{
chat.FadeTo(mode.NewValue == DisplayMode.Chat ? 1 : 0, fade_duration);
leaderboard.FadeTo(mode.NewValue == DisplayMode.Leaderboard ? 1 : 0, fade_duration);
}
private class DisplayModeTabControl : OsuTabControl<DisplayMode>
{
protected override TabItem<DisplayMode> CreateTabItem(DisplayMode value) => base.CreateTabItem(value).With(d =>
{
d.Anchor = Anchor.Centre;
d.Origin = Anchor.Centre;
});
}
private enum DisplayMode
{
Leaderboard,
Chat,
}
}
}

View File

@ -0,0 +1,20 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Graphics;
using osu.Game.Screens.Multi.Components;
namespace osu.Game.Screens.Multi.Match.Components
{
public class OverlinedChatDisplay : OverlinedDisplay
{
public OverlinedChatDisplay()
: base("Chat")
{
Content.Add(new MatchChatDisplay
{
RelativeSizeAxes = Axes.Both
});
}
}
}

View File

@ -0,0 +1,24 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Graphics;
using osu.Game.Screens.Multi.Components;
namespace osu.Game.Screens.Multi.Match.Components
{
public class OverlinedLeaderboard : OverlinedDisplay
{
private readonly MatchLeaderboard leaderboard;
public OverlinedLeaderboard()
: base("Leaderboard")
{
Content.Add(leaderboard = new MatchLeaderboard
{
RelativeSizeAxes = Axes.Both
});
}
public void RefreshScores() => leaderboard.RefreshScores();
}
}

View File

@ -52,8 +52,8 @@ namespace osu.Game.Screens.Multi.Match
protected readonly Bindable<PlaylistItem> SelectedItem = new Bindable<PlaylistItem>();
private LeaderboardChatDisplay leaderboardChatDisplay;
private MatchSettingsOverlay settingsOverlay;
private OverlinedLeaderboard leaderboard;
private IBindable<WeakReference<BeatmapSetInfo>> managerUpdated;
@ -87,82 +87,107 @@ namespace osu.Game.Screens.Multi.Match
RelativeSizeAxes = Axes.Both,
Content = new[]
{
new Drawable[] { new Components.Header() },
new Drawable[]
{
new Components.Header()
},
new Drawable[]
{
new Container
{
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding { Top = 65 },
Child = new GridContainer
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Margin = new MarginPadding { Top = 10 },
Child = new OverlinedParticipants(Direction.Horizontal)
{
ColumnDimensions = new[]
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
ShowLine = false
}
}
},
new Drawable[]
{
new GridContainer
{
RelativeSizeAxes = Axes.Both,
Content = new[]
{
new Drawable[]
{
new Dimension(minSize: 160),
new Dimension(minSize: 360),
new Dimension(minSize: 400),
},
RelativeSizeAxes = Axes.Both,
Content = new[]
{
new Drawable[]
new Container
{
new Container
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding { Right = 5 },
Child = new GridContainer
{
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding { Right = 5 },
Child = new OverlinedParticipants(Direction.Vertical) { RelativeSizeAxes = Axes.Both }
},
new Container
{
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding { Horizontal = 5 },
Child = new GridContainer
Content = new[]
{
RelativeSizeAxes = Axes.Both,
Content = new[]
new Drawable[]
{
new Drawable[]
new OverlinedPlaylist(true) // Temporarily always allow selection
{
new OverlinedPlaylist(true) // Temporarily always allow selection
{
RelativeSizeAxes = Axes.Both,
SelectedItem = { BindTarget = SelectedItem }
}
},
null,
new Drawable[]
{
new TriangleButton
{
RelativeSizeAxes = Axes.X,
Text = "Show beatmap results",
Action = showBeatmapResults
}
RelativeSizeAxes = Axes.Both,
SelectedItem = { BindTarget = SelectedItem }
}
},
RowDimensions = new[]
null,
new Drawable[]
{
new Dimension(),
new Dimension(GridSizeMode.Absolute, 5),
new Dimension(GridSizeMode.AutoSize)
new TriangleButton
{
RelativeSizeAxes = Axes.X,
Text = "Show beatmap results",
Action = showBeatmapResults
}
}
},
RowDimensions = new[]
{
new Dimension(),
new Dimension(GridSizeMode.Absolute, 5),
new Dimension(GridSizeMode.AutoSize)
}
},
new Container
{
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding { Left = 5 },
Child = leaderboardChatDisplay = new LeaderboardChatDisplay()
}
},
}
null,
new GridContainer
{
RelativeSizeAxes = Axes.Both,
Content = new[]
{
new Drawable[]
{
leaderboard = new OverlinedLeaderboard { RelativeSizeAxes = Axes.Both },
},
new Drawable[]
{
new OverlinedChatDisplay { RelativeSizeAxes = Axes.Both }
}
},
RowDimensions = new[]
{
new Dimension(),
new Dimension(GridSizeMode.Relative, size: 0.4f, minSize: 240),
}
},
null
},
},
ColumnDimensions = new[]
{
new Dimension(GridSizeMode.Relative, size: 0.5f, maxSize: 400),
new Dimension(),
new Dimension(GridSizeMode.Relative, size: 0.5f, maxSize: 600),
new Dimension(),
}
}
}
},
RowDimensions = new[]
{
new Dimension(GridSizeMode.AutoSize),
new Dimension(GridSizeMode.AutoSize),
new Dimension(),
}
@ -261,7 +286,7 @@ namespace osu.Game.Screens.Multi.Match
case GameTypeTimeshift _:
multiplayer?.Push(new PlayerLoader(() => new TimeshiftPlayer(SelectedItem.Value)
{
Exited = () => leaderboardChatDisplay.RefreshScores()
Exited = () => leaderboard.RefreshScores()
}));
break;
}

View File

@ -117,7 +117,7 @@ namespace osu.Game.Screens.Multi
Child = new Box
{
RelativeSizeAxes = Axes.Both,
Colour = ColourInfo.GradientVertical(backgroundColour.Opacity(0.7f), backgroundColour)
Colour = ColourInfo.GradientVertical(backgroundColour.Opacity(0.5f), backgroundColour)
},
}
}

View File

@ -2,6 +2,7 @@
// See the LICENCE file in the repository root for full licence text.
using System;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
@ -9,6 +10,7 @@ using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers;
using osu.Framework.Utils;
using osu.Game.Graphics;
using osu.Game.Rulesets.Mods;
using osu.Game.Scoring;
using osuTK;
@ -191,18 +193,26 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy
Padding = new MarginPadding { Vertical = -15, Horizontal = -20 },
Children = new[]
{
new RankBadge(1f, ScoreRank.X),
new RankBadge(0.95f, ScoreRank.S),
new RankBadge(0.9f, ScoreRank.A),
new RankBadge(0.8f, ScoreRank.B),
new RankBadge(0.7f, ScoreRank.C),
new RankBadge(0.35f, ScoreRank.D),
new RankBadge(1f, getRank(ScoreRank.X)),
new RankBadge(0.95f, getRank(ScoreRank.S)),
new RankBadge(0.9f, getRank(ScoreRank.A)),
new RankBadge(0.8f, getRank(ScoreRank.B)),
new RankBadge(0.7f, getRank(ScoreRank.C)),
new RankBadge(0.35f, getRank(ScoreRank.D)),
}
},
rankText = new RankText(score.Rank)
};
}
private ScoreRank getRank(ScoreRank rank)
{
foreach (var mod in score.Mods.OfType<IApplicableToScoreProcessor>())
rank = mod.AdjustRank(rank, score.Accuracy);
return rank;
}
protected override void LoadComplete()
{
base.LoadComplete();

View File

@ -115,6 +115,7 @@ namespace osu.Game.Skinning
case string _ when pair.Key.StartsWith("NoteImage"):
case string _ when pair.Key.StartsWith("KeyImage"):
case string _ when pair.Key.StartsWith("Hit"):
case string _ when pair.Key.StartsWith("Stage"):
currentConfig.ImageLookups[pair.Key] = pair.Value;
break;
}

View File

@ -250,6 +250,15 @@ namespace osu.Game.Skinning
case LegacyManiaSkinConfigurationLookups.RightStageImage:
return SkinUtils.As<TValue>(getManiaImage(existing, "StageRight"));
case LegacyManiaSkinConfigurationLookups.BottomStageImage:
return SkinUtils.As<TValue>(getManiaImage(existing, "StageBottom"));
case LegacyManiaSkinConfigurationLookups.LightImage:
return SkinUtils.As<TValue>(getManiaImage(existing, "StageLight"));
case LegacyManiaSkinConfigurationLookups.HitTargetImage:
return SkinUtils.As<TValue>(getManiaImage(existing, "StageHint"));
case LegacyManiaSkinConfigurationLookups.LeftLineWidth:
Debug.Assert(maniaLookup.TargetColumn != null);
return SkinUtils.As<TValue>(new Bindable<float>(existing.ColumnLineWidth[maniaLookup.TargetColumn.Value]));