Merge branch 'master' into multi-polling-request-refactor

This commit is contained in:
smoogipoo
2021-08-17 08:44:56 +09:00
98 changed files with 1528 additions and 320 deletions

View File

@ -169,7 +169,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
protected override Track GetBeatmapTrack() => throw new NotImplementedException(); protected override Track GetBeatmapTrack() => throw new NotImplementedException();
protected override ISkin GetSkin() => throw new NotImplementedException(); protected internal override ISkin GetSkin() => throw new NotImplementedException();
public override Stream GetStream(string storagePath) => throw new NotImplementedException(); public override Stream GetStream(string storagePath) => throw new NotImplementedException();
} }

View File

@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // 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. // See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic;
using System.Linq; using System.Linq;
using NUnit.Framework; using NUnit.Framework;
using osu.Framework.Allocation; using osu.Framework.Allocation;
@ -19,6 +20,7 @@ namespace osu.Game.Tests.Chat
{ {
private ChannelManager channelManager; private ChannelManager channelManager;
private int currentMessageId; private int currentMessageId;
private List<Message> sentMessages;
[SetUp] [SetUp]
public void Setup() => Schedule(() => public void Setup() => Schedule(() =>
@ -34,6 +36,7 @@ namespace osu.Game.Tests.Chat
AddStep("register request handling", () => AddStep("register request handling", () =>
{ {
currentMessageId = 0; currentMessageId = 0;
sentMessages = new List<Message>();
((DummyAPIAccess)API).HandleRequest = req => ((DummyAPIAccess)API).HandleRequest = req =>
{ {
@ -44,16 +47,11 @@ namespace osu.Game.Tests.Chat
return true; return true;
case PostMessageRequest postMessage: case PostMessageRequest postMessage:
postMessage.TriggerSuccess(new Message(++currentMessageId) handlePostMessageRequest(postMessage);
{ return true;
IsAction = postMessage.Message.IsAction,
ChannelId = postMessage.Message.ChannelId,
Content = postMessage.Message.Content,
Links = postMessage.Message.Links,
Timestamp = postMessage.Message.Timestamp,
Sender = postMessage.Message.Sender
});
case MarkChannelAsReadRequest markRead:
handleMarkChannelAsReadRequest(markRead);
return true; return true;
} }
@ -83,12 +81,65 @@ namespace osu.Game.Tests.Chat
AddAssert("/np command received by channel 2", () => channel2.Messages.Last().Content.Contains("is listening to")); AddAssert("/np command received by channel 2", () => channel2.Messages.Last().Content.Contains("is listening to"));
} }
[Test]
public void TestMarkAsReadIgnoringLocalMessages()
{
Channel channel = null;
AddStep("join channel and select it", () =>
{
channelManager.JoinChannel(channel = createChannel(1, ChannelType.Public));
channelManager.CurrentChannel.Value = channel;
});
AddStep("post message", () => channelManager.PostMessage("Something interesting"));
AddStep("post /help command", () => channelManager.PostCommand("help", channel));
AddStep("post /me command with no action", () => channelManager.PostCommand("me", channel));
AddStep("post /join command with no channel", () => channelManager.PostCommand("join", channel));
AddStep("post /join command with non-existent channel", () => channelManager.PostCommand("join i-dont-exist", channel));
AddStep("post non-existent command", () => channelManager.PostCommand("non-existent-cmd arg", channel));
AddStep("mark channel as read", () => channelManager.MarkChannelAsRead(channel));
AddAssert("channel's last read ID is set to the latest message", () => channel.LastReadId == sentMessages.Last().Id);
}
private void handlePostMessageRequest(PostMessageRequest request)
{
var message = new Message(++currentMessageId)
{
IsAction = request.Message.IsAction,
ChannelId = request.Message.ChannelId,
Content = request.Message.Content,
Links = request.Message.Links,
Timestamp = request.Message.Timestamp,
Sender = request.Message.Sender
};
sentMessages.Add(message);
request.TriggerSuccess(message);
}
private void handleMarkChannelAsReadRequest(MarkChannelAsReadRequest request)
{
// only accept messages that were sent through the API
if (sentMessages.Contains(request.Message))
{
request.TriggerSuccess();
}
else
{
request.TriggerFailure(new APIException("unknown message!", null));
}
}
private Channel createChannel(int id, ChannelType type) => new Channel(new User()) private Channel createChannel(int id, ChannelType type) => new Channel(new User())
{ {
Id = id, Id = id,
Name = $"Channel {id}", Name = $"Channel {id}",
Topic = $"Topic of channel {id} with type {type}", Topic = $"Topic of channel {id} with type {type}",
Type = type, Type = type,
LastMessageId = 0,
}; };
private class ChannelManagerContainer : CompositeDrawable private class ChannelManagerContainer : CompositeDrawable

View File

@ -204,7 +204,7 @@ namespace osu.Game.Tests.Gameplay
this.resources = resources; this.resources = resources;
} }
protected override ISkin GetSkin() => new TestSkin("test-sample", resources); protected internal override ISkin GetSkin() => new TestSkin("test-sample", resources);
} }
private class TestDrawableStoryboardSample : DrawableStoryboardSample private class TestDrawableStoryboardSample : DrawableStoryboardSample

View File

@ -133,11 +133,12 @@ namespace osu.Game.Tests.Skins
[Test] [Test]
public void TestEmptyComboColoursNoFallback() public void TestEmptyComboColoursNoFallback()
{ {
AddStep("Add custom combo colours to user skin", () => userSource.Configuration.AddComboColours( AddStep("Add custom combo colours to user skin", () => userSource.Configuration.CustomComboColours = new List<Color4>
{
new Color4(100, 150, 200, 255), new Color4(100, 150, 200, 255),
new Color4(55, 110, 166, 255), new Color4(55, 110, 166, 255),
new Color4(75, 125, 175, 255) new Color4(75, 125, 175, 255)
)); });
AddStep("Disallow default colours fallback in beatmap skin", () => beatmapSource.Configuration.AllowDefaultComboColoursFallback = false); AddStep("Disallow default colours fallback in beatmap skin", () => beatmapSource.Configuration.AllowDefaultComboColoursFallback = false);

View File

@ -111,7 +111,7 @@ namespace osu.Game.Tests.Visual.Gameplay
this.beatmapSkin = beatmapSkin; this.beatmapSkin = beatmapSkin;
} }
protected override ISkin GetSkin() => beatmapSkin; protected internal override ISkin GetSkin() => beatmapSkin;
} }
private class TestOsuRuleset : OsuRuleset private class TestOsuRuleset : OsuRuleset

View File

@ -12,6 +12,7 @@ using osu.Game.Configuration;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
using osu.Game.Screens.Play; using osu.Game.Screens.Play;
using osu.Game.Skinning;
using osuTK.Input; using osuTK.Input;
namespace osu.Game.Tests.Visual.Gameplay namespace osu.Game.Tests.Visual.Gameplay
@ -142,6 +143,22 @@ namespace osu.Game.Tests.Visual.Gameplay
AddStep("return value", () => config.SetValue(OsuSetting.KeyOverlay, keyCounterVisibleValue)); AddStep("return value", () => config.SetValue(OsuSetting.KeyOverlay, keyCounterVisibleValue));
} }
[Test]
public void TestHiddenHUDDoesntBlockSkinnableComponentsLoad()
{
HUDVisibilityMode originalConfigValue = default;
AddStep("get original config value", () => originalConfigValue = config.Get<HUDVisibilityMode>(OsuSetting.HUDVisibilityMode));
AddStep("set hud to never show", () => config.SetValue(OsuSetting.HUDVisibilityMode, HUDVisibilityMode.Never));
createNew();
AddUntilStep("wait for hud load", () => hudOverlay.IsLoaded);
AddUntilStep("skinnable components loaded", () => hudOverlay.ChildrenOfType<SkinnableTargetContainer>().Single().ComponentsLoaded);
AddStep("set original config value", () => config.SetValue(OsuSetting.HUDVisibilityMode, originalConfigValue));
}
private void createNew(Action<HUDOverlay> action = null) private void createNew(Action<HUDOverlay> action = null)
{ {
AddStep("create overlay", () => AddStep("create overlay", () =>

View File

@ -0,0 +1,55 @@
// 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.Linq;
using NUnit.Framework;
using osu.Framework.Graphics.Containers;
using osu.Framework.Testing;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Screens.Play;
namespace osu.Game.Tests.Visual.Mods
{
public class TestSceneModFailCondition : ModTestScene
{
private bool restartRequested;
protected override Ruleset CreatePlayerRuleset() => new OsuRuleset();
protected override TestPlayer CreateModPlayer(Ruleset ruleset)
{
var player = base.CreateModPlayer(ruleset);
player.RestartRequested = () => restartRequested = true;
return player;
}
protected override bool AllowFail => true;
[SetUpSteps]
public void SetUp()
{
AddStep("reset flag", () => restartRequested = false);
}
[Test]
public void TestRestartOnFailDisabled() => CreateModTest(new ModTestData
{
Autoplay = false,
Mod = new OsuModSuddenDeath(),
PassCondition = () => !restartRequested && Player.ChildrenOfType<FailOverlay>().Single().State.Value == Visibility.Visible
});
[Test]
public void TestRestartOnFailEnabled() => CreateModTest(new ModTestData
{
Autoplay = false,
Mod = new OsuModSuddenDeath
{
Restart = { Value = true }
},
PassCondition = () => restartRequested && Player.ChildrenOfType<FailOverlay>().Single().State.Value == Visibility.Hidden
});
}
}

View File

@ -4,6 +4,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using NUnit.Framework; using NUnit.Framework;
using osu.Framework.Extensions.ObjectExtensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Framework.Testing; using osu.Framework.Testing;
@ -48,9 +49,15 @@ namespace osu.Game.Tests.Visual.Multiplayer
{ {
AddAssert("one unique panel", () => this.ChildrenOfType<ParticipantPanel>().Select(p => p.User).Distinct().Count() == 1); AddAssert("one unique panel", () => this.ChildrenOfType<ParticipantPanel>().Select(p => p.User).Distinct().Count() == 1);
AddStep("add non-resolvable user", () => Client.AddNullUser(-3)); AddStep("add non-resolvable user", () => Client.AddNullUser());
AddAssert("null user added", () => Client.Room.AsNonNull().Users.Count(u => u.User == null) == 1);
AddUntilStep("two unique panels", () => this.ChildrenOfType<ParticipantPanel>().Select(p => p.User).Distinct().Count() == 2); AddUntilStep("two unique panels", () => this.ChildrenOfType<ParticipantPanel>().Select(p => p.User).Distinct().Count() == 2);
AddStep("kick null user", () => this.ChildrenOfType<ParticipantPanel>().Single(p => p.User.User == null)
.ChildrenOfType<ParticipantPanel.KickButton>().Single().TriggerClick());
AddAssert("null user kicked", () => Client.Room.AsNonNull().Users.Count == 1);
} }
[Test] [Test]

View File

@ -1,8 +1,10 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // 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. // See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic;
using System.Linq; using System.Linq;
using NUnit.Framework; using NUnit.Framework;
using osu.Framework.Extensions.IEnumerableExtensions;
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;
@ -174,6 +176,60 @@ namespace osu.Game.Tests.Visual.UserInterface
checkBindableAtValue("Circle Size", null); checkBindableAtValue("Circle Size", null);
} }
[Test]
public void TestModSettingChangeTracker()
{
ModSettingChangeTracker tracker = null;
Queue<Mod> settingsChangedQueue = null;
setBeatmapWithDifficultyParameters(5);
AddStep("add mod settings change tracker", () =>
{
settingsChangedQueue = new Queue<Mod>();
tracker = new ModSettingChangeTracker(modDifficultyAdjust.Yield())
{
SettingChanged = settingsChangedQueue.Enqueue
};
});
AddAssert("no settings changed", () => settingsChangedQueue.Count == 0);
setSliderValue("Circle Size", 3);
settingsChangedFired();
setSliderValue("Circle Size", 5);
checkBindableAtValue("Circle Size", 5);
settingsChangedFired();
AddStep("reset mod settings", () => modDifficultyAdjust.CircleSize.SetDefault());
checkBindableAtValue("Circle Size", null);
settingsChangedFired();
setExtendedLimits(true);
settingsChangedFired();
AddStep("dispose tracker", () =>
{
tracker.Dispose();
tracker = null;
});
void settingsChangedFired()
{
AddAssert("setting changed event fired", () =>
{
settingsChangedQueue.Dequeue();
return settingsChangedQueue.Count == 0;
});
}
}
private void resetToDefault(string name) private void resetToDefault(string name)
{ {
AddStep($"Reset {name} to default", () => AddStep($"Reset {name} to default", () =>

View File

@ -53,7 +53,7 @@ namespace osu.Game.Tests
protected override Waveform GetWaveform() => new Waveform(trackStore.GetStream(firstAudioFile)); protected override Waveform GetWaveform() => new Waveform(trackStore.GetStream(firstAudioFile));
protected override ISkin GetSkin() => null; protected internal override ISkin GetSkin() => null;
public override Stream GetStream(string storagePath) => null; public override Stream GetStream(string storagePath) => null;

View File

@ -534,7 +534,7 @@ namespace osu.Game.Beatmaps
protected override IBeatmap GetBeatmap() => beatmap; protected override IBeatmap GetBeatmap() => beatmap;
protected override Texture GetBackground() => null; protected override Texture GetBackground() => null;
protected override Track GetBeatmapTrack() => null; protected override Track GetBeatmapTrack() => null;
protected override ISkin GetSkin() => null; protected internal override ISkin GetSkin() => null;
public override Stream GetStream(string storagePath) => null; public override Stream GetStream(string storagePath) => null;
} }
} }

View File

@ -128,7 +128,7 @@ namespace osu.Game.Beatmaps
return storyboard; return storyboard;
} }
protected override ISkin GetSkin() protected internal override ISkin GetSkin()
{ {
try try
{ {

View File

@ -50,7 +50,7 @@ namespace osu.Game.Beatmaps
protected override Track GetBeatmapTrack() => GetVirtualTrack(); protected override Track GetBeatmapTrack() => GetVirtualTrack();
protected override ISkin GetSkin() => null; protected internal override ISkin GetSkin() => null;
public override Stream GetStream(string storagePath) => null; public override Stream GetStream(string storagePath) => null;

View File

@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // 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. // See the LICENCE file in the repository root for full licence text.
using System;
using System.Collections.Generic; using System.Collections.Generic;
using osuTK.Graphics; using osuTK.Graphics;
@ -13,9 +14,17 @@ namespace osu.Game.Beatmaps.Formats
/// </summary> /// </summary>
IReadOnlyList<Color4> ComboColours { get; } IReadOnlyList<Color4> ComboColours { get; }
/// <summary>
/// The list of custom combo colours.
/// If non-empty, <see cref="ComboColours"/> will return these colours;
/// if empty, <see cref="ComboColours"/> will fall back to default combo colours.
/// </summary>
List<Color4> CustomComboColours { get; }
/// <summary> /// <summary>
/// Adds combo colours to the list. /// Adds combo colours to the list.
/// </summary> /// </summary>
[Obsolete("Use CustomComboColours directly.")] // can be removed 20220215
void AddComboColours(params Color4[] colours); void AddComboColours(params Color4[] colours);
} }
} }

View File

@ -123,7 +123,7 @@ namespace osu.Game.Beatmaps.Formats
{ {
if (!(output is IHasComboColours tHasComboColours)) return; if (!(output is IHasComboColours tHasComboColours)) return;
tHasComboColours.AddComboColours(colour); tHasComboColours.CustomComboColours.Add(colour);
} }
else else
{ {

View File

@ -327,7 +327,15 @@ namespace osu.Game.Beatmaps
public bool SkinLoaded => skin.IsResultAvailable; public bool SkinLoaded => skin.IsResultAvailable;
public ISkin Skin => skin.Value; public ISkin Skin => skin.Value;
protected abstract ISkin GetSkin(); /// <summary>
/// Creates a new skin instance for this beatmap.
/// </summary>
/// <remarks>
/// This should only be called externally in scenarios where it is explicitly desired to get a new instance of a skin
/// (e.g. for editing purposes, to avoid state pollution).
/// For standard reading purposes, <see cref="Skin"/> should always be used directly.
/// </remarks>
protected internal abstract ISkin GetSkin();
private readonly RecyclableLazy<ISkin> skin; private readonly RecyclableLazy<ISkin> skin;

View File

@ -101,7 +101,7 @@ namespace osu.Game.Configuration
SetDefault(OsuSetting.HitLighting, true); SetDefault(OsuSetting.HitLighting, true);
SetDefault(OsuSetting.HUDVisibilityMode, HUDVisibilityMode.Always); SetDefault(OsuSetting.HUDVisibilityMode, HUDVisibilityMode.Always);
SetDefault(OsuSetting.ShowDifficultyGraph, true); SetDefault(OsuSetting.ShowProgressGraph, true);
SetDefault(OsuSetting.ShowHealthDisplayWhenCantFail, true); SetDefault(OsuSetting.ShowHealthDisplayWhenCantFail, true);
SetDefault(OsuSetting.FadePlayfieldWhenHealthLow, true); SetDefault(OsuSetting.FadePlayfieldWhenHealthLow, true);
SetDefault(OsuSetting.KeyOverlay, false); SetDefault(OsuSetting.KeyOverlay, false);
@ -201,6 +201,8 @@ namespace osu.Game.Configuration
public Func<GlobalAction, string> LookupKeyBindings { get; set; } public Func<GlobalAction, string> LookupKeyBindings { get; set; }
} }
// IMPORTANT: These are used in user configuration files.
// The naming of these keys should not be changed once they are deployed in a release, unless migration logic is also added.
public enum OsuSetting public enum OsuSetting
{ {
Ruleset, Ruleset,
@ -217,7 +219,7 @@ namespace osu.Game.Configuration
AlwaysPlayFirstComboBreak, AlwaysPlayFirstComboBreak,
FloatingComments, FloatingComments,
HUDVisibilityMode, HUDVisibilityMode,
ShowDifficultyGraph, ShowProgressGraph,
ShowHealthDisplayWhenCantFail, ShowHealthDisplayWhenCantFail,
FadePlayfieldWhenHealthLow, FadePlayfieldWhenHealthLow,
MouseDisableButtons, MouseDisableButtons,

View File

@ -0,0 +1,64 @@
// 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.Localisation;
namespace osu.Game.Localisation
{
public static class AudioSettingsStrings
{
private const string prefix = @"osu.Game.Resources.Localisation.AudioSettings";
/// <summary>
/// "Audio"
/// </summary>
public static LocalisableString AudioSectionHeader => new TranslatableString(getKey(@"audio_section_header"), @"Audio");
/// <summary>
/// "Devices"
/// </summary>
public static LocalisableString AudioDevicesHeader => new TranslatableString(getKey(@"audio_devices_header"), @"Devices");
/// <summary>
/// "Volume"
/// </summary>
public static LocalisableString VolumeHeader => new TranslatableString(getKey(@"volume_header"), @"Volume");
/// <summary>
/// "Master"
/// </summary>
public static LocalisableString MasterVolume => new TranslatableString(getKey(@"master_volume"), @"Master");
/// <summary>
/// "Master (window inactive)"
/// </summary>
public static LocalisableString MasterVolumeInactive => new TranslatableString(getKey(@"master_volume_inactive"), @"Master (window inactive)");
/// <summary>
/// "Effect"
/// </summary>
public static LocalisableString EffectVolume => new TranslatableString(getKey(@"effect_volume"), @"Effect");
/// <summary>
/// "Music"
/// </summary>
public static LocalisableString MusicVolume => new TranslatableString(getKey(@"music_volume"), @"Music");
/// <summary>
/// "Offset Adjustment"
/// </summary>
public static LocalisableString OffsetHeader => new TranslatableString(getKey(@"offset_header"), @"Offset Adjustment");
/// <summary>
/// "Audio offset"
/// </summary>
public static LocalisableString AudioOffset => new TranslatableString(getKey(@"audio_offset"), @"Audio offset");
/// <summary>
/// "Offset wizard"
/// </summary>
public static LocalisableString OffsetWizard => new TranslatableString(getKey(@"offset_wizard"), @"Offset wizard");
private static string getKey(string key) => $"{prefix}:{key}";
}
}

View File

@ -14,11 +14,21 @@ namespace osu.Game.Localisation
/// </summary> /// </summary>
public static LocalisableString Cancel => new TranslatableString(getKey(@"cancel"), @"Cancel"); public static LocalisableString Cancel => new TranslatableString(getKey(@"cancel"), @"Cancel");
/// <summary>
/// "Clear"
/// </summary>
public static LocalisableString Clear => new TranslatableString(getKey(@"clear"), @"Clear");
/// <summary> /// <summary>
/// "Enabled" /// "Enabled"
/// </summary> /// </summary>
public static LocalisableString Enabled => new TranslatableString(getKey(@"enabled"), @"Enabled"); public static LocalisableString Enabled => new TranslatableString(getKey(@"enabled"), @"Enabled");
/// <summary>
/// "Default"
/// </summary>
public static LocalisableString Default => new TranslatableString(getKey(@"default"), @"Default");
/// <summary> /// <summary>
/// "Width" /// "Width"
/// </summary> /// </summary>
@ -31,4 +41,4 @@ namespace osu.Game.Localisation
private static string getKey(string key) => $@"{prefix}:{key}"; private static string getKey(string key) => $@"{prefix}:{key}";
} }
} }

View File

@ -0,0 +1,49 @@
// 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.Localisation;
namespace osu.Game.Localisation
{
public static class DebugSettingsStrings
{
private const string prefix = @"osu.Game.Resources.Localisation.DebugSettings";
/// <summary>
/// "Debug"
/// </summary>
public static LocalisableString DebugSectionHeader => new TranslatableString(getKey(@"debug_section_header"), @"Debug");
/// <summary>
/// "General"
/// </summary>
public static LocalisableString GeneralHeader => new TranslatableString(getKey(@"general_header"), @"General");
/// <summary>
/// "Show log overlay"
/// </summary>
public static LocalisableString ShowLogOverlay => new TranslatableString(getKey(@"show_log_overlay"), @"Show log overlay");
/// <summary>
/// "Bypass front-to-back render pass"
/// </summary>
public static LocalisableString BypassFrontToBackPass => new TranslatableString(getKey(@"bypass_front_to_back_pass"), @"Bypass front-to-back render pass");
/// <summary>
/// "Import files"
/// </summary>
public static LocalisableString ImportFiles => new TranslatableString(getKey(@"import_files"), @"Import files");
/// <summary>
/// "Memory"
/// </summary>
public static LocalisableString MemoryHeader => new TranslatableString(getKey(@"memory_header"), @"Memory");
/// <summary>
/// "Clear all caches"
/// </summary>
public static LocalisableString ClearAllCaches => new TranslatableString(getKey(@"clear_all_caches"), @"Clear all caches");
private static string getKey(string key) => $"{prefix}:{key}";
}
}

View File

@ -0,0 +1,94 @@
// 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.Localisation;
namespace osu.Game.Localisation
{
public static class GameplaySettingsStrings
{
private const string prefix = @"osu.Game.Resources.Localisation.GameplaySettings";
/// <summary>
/// "Gameplay"
/// </summary>
public static LocalisableString GameplaySectionHeader => new TranslatableString(getKey(@"gameplay_section_header"), @"Gameplay");
/// <summary>
/// "General"
/// </summary>
public static LocalisableString GeneralHeader => new TranslatableString(getKey(@"general_header"), @"General");
/// <summary>
/// "Background dim"
/// </summary>
public static LocalisableString BackgroundDim => new TranslatableString(getKey(@"dim"), @"Background dim");
/// <summary>
/// "Background blur"
/// </summary>
public static LocalisableString BackgroundBlur => new TranslatableString(getKey(@"blur"), @"Background blur");
/// <summary>
/// "Lighten playfield during breaks"
/// </summary>
public static LocalisableString LightenDuringBreaks => new TranslatableString(getKey(@"lighten_during_breaks"), @"Lighten playfield during breaks");
/// <summary>
/// "HUD overlay visibility mode"
/// </summary>
public static LocalisableString HUDVisibilityMode => new TranslatableString(getKey(@"hud_visibility_mode"), @"HUD overlay visibility mode");
/// <summary>
/// "Show difficulty graph on progress bar"
/// </summary>
public static LocalisableString ShowDifficultyGraph => new TranslatableString(getKey(@"show_difficulty_graph"), @"Show difficulty graph on progress bar");
/// <summary>
/// "Show health display even when you can't fail"
/// </summary>
public static LocalisableString ShowHealthDisplayWhenCantFail => new TranslatableString(getKey(@"show_health_display_when_cant_fail"), @"Show health display even when you can't fail");
/// <summary>
/// "Fade playfield to red when health is low"
/// </summary>
public static LocalisableString FadePlayfieldWhenHealthLow => new TranslatableString(getKey(@"fade_playfield_when_health_low"), @"Fade playfield to red when health is low");
/// <summary>
/// "Always show key overlay"
/// </summary>
public static LocalisableString AlwaysShowKeyOverlay => new TranslatableString(getKey(@"key_overlay"), @"Always show key overlay");
/// <summary>
/// "Positional hitsounds"
/// </summary>
public static LocalisableString PositionalHitsounds => new TranslatableString(getKey(@"positional_hitsounds"), @"Positional hitsounds");
/// <summary>
/// "Always play first combo break sound"
/// </summary>
public static LocalisableString AlwaysPlayFirstComboBreak => new TranslatableString(getKey(@"always_play_first_combo_break"), @"Always play first combo break sound");
/// <summary>
/// "Score display mode"
/// </summary>
public static LocalisableString ScoreDisplayMode => new TranslatableString(getKey(@"score_display_mode"), @"Score display mode");
/// <summary>
/// "Disable Windows key during gameplay"
/// </summary>
public static LocalisableString DisableWinKey => new TranslatableString(getKey(@"disable_win_key"), @"Disable Windows key during gameplay");
/// <summary>
/// "Mods"
/// </summary>
public static LocalisableString ModsHeader => new TranslatableString(getKey(@"mods_header"), @"Mods");
/// <summary>
/// "Increase visibility of first object when visual impairment mods are enabled"
/// </summary>
public static LocalisableString IncreaseFirstObjectVisibility => new TranslatableString(getKey(@"increase_first_object_visibility"), @"Increase visibility of first object when visual impairment mods are enabled");
private static string getKey(string key) => $"{prefix}:{key}";
}
}

View File

@ -0,0 +1,59 @@
// 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.Localisation;
namespace osu.Game.Localisation
{
public static class GeneralSettingsStrings
{
private const string prefix = @"osu.Game.Resources.Localisation.GeneralSettings";
/// <summary>
/// "General"
/// </summary>
public static LocalisableString GeneralSectionHeader => new TranslatableString(getKey(@"general_section_header"), @"General");
/// <summary>
/// "Language"
/// </summary>
public static LocalisableString LanguageHeader => new TranslatableString(getKey(@"language_header"), @"Language");
/// <summary>
/// "Language"
/// </summary>
public static LocalisableString LanguageDropdown => new TranslatableString(getKey(@"language_dropdown"), @"Language");
/// <summary>
/// "Prefer metadata in original language"
/// </summary>
public static LocalisableString PreferOriginalMetadataLanguage => new TranslatableString(getKey(@"prefer_original"), @"Prefer metadata in original language");
/// <summary>
/// "Updates"
/// </summary>
public static LocalisableString UpdateHeader => new TranslatableString(getKey(@"update_header"), @"Updates");
/// <summary>
/// "Release stream"
/// </summary>
public static LocalisableString ReleaseStream => new TranslatableString(getKey(@"release_stream"), @"Release stream");
/// <summary>
/// "Check for updates"
/// </summary>
public static LocalisableString CheckUpdate => new TranslatableString(getKey(@"check_update"), @"Check for updates");
/// <summary>
/// "Open osu! folder"
/// </summary>
public static LocalisableString OpenOsuFolder => new TranslatableString(getKey(@"open_osu_folder"), @"Open osu! folder");
/// <summary>
/// "Change folder location..."
/// </summary>
public static LocalisableString ChangeFolderLocation => new TranslatableString(getKey(@"change_folder_location"), @"Change folder location...");
private static string getKey(string key) => $"{prefix}:{key}";
}
}

View File

@ -0,0 +1,119 @@
// 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.Localisation;
namespace osu.Game.Localisation
{
public static class GraphicsSettingsStrings
{
private const string prefix = @"osu.Game.Resources.Localisation.GraphicsSettings";
/// <summary>
/// "Graphics"
/// </summary>
public static LocalisableString GraphicsSectionHeader => new TranslatableString(getKey(@"graphics_section_header"), @"Graphics");
/// <summary>
/// "Renderer"
/// </summary>
public static LocalisableString RendererHeader => new TranslatableString(getKey(@"renderer_header"), @"Renderer");
/// <summary>
/// "Frame limiter"
/// </summary>
public static LocalisableString FrameLimiter => new TranslatableString(getKey(@"frame_limiter"), @"Frame limiter");
/// <summary>
/// "Threading mode"
/// </summary>
public static LocalisableString ThreadingMode => new TranslatableString(getKey(@"threading_mode"), @"Threading mode");
/// <summary>
/// "Show FPS"
/// </summary>
public static LocalisableString ShowFPS => new TranslatableString(getKey(@"show_fps"), @"Show FPS");
/// <summary>
/// "Using unlimited frame limiter can lead to stutters, bad performance and overheating. It will not improve perceived latency. "2x refresh rate" is recommended."
/// </summary>
public static LocalisableString UnlimitedFramesNote => new TranslatableString(getKey(@"unlimited_frames_note"), @"Using unlimited frame limiter can lead to stutters, bad performance and overheating. It will not improve perceived latency. ""2x refresh rate"" is recommended.");
/// <summary>
/// "Layout"
/// </summary>
public static LocalisableString LayoutHeader => new TranslatableString(getKey(@"layout_header"), @"Layout");
/// <summary>
/// "Screen mode"
/// </summary>
public static LocalisableString ScreenMode => new TranslatableString(getKey(@"screen_mode"), @"Screen mode");
/// <summary>
/// "Resolution"
/// </summary>
public static LocalisableString Resolution => new TranslatableString(getKey(@"resolution"), @"Resolution");
/// <summary>
/// "UI scaling"
/// </summary>
public static LocalisableString UIScaling => new TranslatableString(getKey(@"ui_scaling"), @"UI scaling");
/// <summary>
/// "Screen scaling"
/// </summary>
public static LocalisableString ScreenScaling => new TranslatableString(getKey(@"screen_scaling"), @"Screen scaling");
/// <summary>
/// "Horizontal position"
/// </summary>
public static LocalisableString HorizontalPosition => new TranslatableString(getKey(@"horizontal_position"), @"Horizontal position");
/// <summary>
/// "Vertical position"
/// </summary>
public static LocalisableString VerticalPosition => new TranslatableString(getKey(@"vertical_position"), @"Vertical position");
/// <summary>
/// "Horizontal scale"
/// </summary>
public static LocalisableString HorizontalScale => new TranslatableString(getKey(@"horizontal_scale"), @"Horizontal scale");
/// <summary>
/// "Vertical scale"
/// </summary>
public static LocalisableString VerticalScale => new TranslatableString(getKey(@"vertical_scale"), @"Vertical scale");
/// <summary>
/// "Running without fullscreen mode will increase your input latency!"
/// </summary>
public static LocalisableString NotFullscreenNote => new TranslatableString(getKey(@"not_fullscreen_note"), @"Running without fullscreen mode will increase your input latency!");
/// <summary>
/// "Detail Settings"
/// </summary>
public static LocalisableString DetailSettingsHeader => new TranslatableString(getKey(@"detail_settings_header"), @"Detail Settings");
/// <summary>
/// "Storyboard / video"
/// </summary>
public static LocalisableString StoryboardVideo => new TranslatableString(getKey(@"storyboard_video"), @"Storyboard / video");
/// <summary>
/// "Hit lighting"
/// </summary>
public static LocalisableString HitLighting => new TranslatableString(getKey(@"hit_lighting"), @"Hit lighting");
/// <summary>
/// "Screenshot format"
/// </summary>
public static LocalisableString ScreenshotFormat => new TranslatableString(getKey(@"screenshot_format"), @"Screenshot format");
/// <summary>
/// "Show menu cursor in screenshots"
/// </summary>
public static LocalisableString ShowCursorInScreenshots => new TranslatableString(getKey(@"show_cursor_in_screenshots"), @"Show menu cursor in screenshots");
private static string getKey(string key) => $"{prefix}:{key}";
}
}

View File

@ -0,0 +1,59 @@
// 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.Localisation;
namespace osu.Game.Localisation
{
public static class InputSettingsStrings
{
private const string prefix = @"osu.Game.Resources.Localisation.InputSettings";
/// <summary>
/// "Input"
/// </summary>
public static LocalisableString InputSectionHeader => new TranslatableString(getKey(@"input_section_header"), @"Input");
/// <summary>
/// "Global"
/// </summary>
public static LocalisableString GlobalKeyBindingHeader => new TranslatableString(getKey(@"global_key_binding_header"), @"Global");
/// <summary>
/// "Song Select"
/// </summary>
public static LocalisableString SongSelectSection => new TranslatableString(getKey(@"song_select_section"), @"Song Select");
/// <summary>
/// "In Game"
/// </summary>
public static LocalisableString InGameSection => new TranslatableString(getKey(@"in_game_section"), @"In Game");
/// <summary>
/// "Audio"
/// </summary>
public static LocalisableString AudioSection => new TranslatableString(getKey(@"audio_section"), @"Audio");
/// <summary>
/// "Editor"
/// </summary>
public static LocalisableString EditorSection => new TranslatableString(getKey(@"editor_section"), @"Editor");
/// <summary>
/// "Reset all bindings in section"
/// </summary>
public static LocalisableString ResetSectionButton => new TranslatableString(getKey(@"reset_section_button"), @"Reset all bindings in section");
/// <summary>
/// "key configuration"
/// </summary>
public static LocalisableString KeyBindingPanelHeader => new TranslatableString(getKey(@"key_binding_panel_header"), @"key configuration");
/// <summary>
/// "Customise your keys!"
/// </summary>
public static LocalisableString KeyBindingPanelDescription => new TranslatableString(getKey(@"key_binding_panel_description"), @"Customise your keys!");
private static string getKey(string key) => $"{prefix}:{key}";
}
}

View File

@ -0,0 +1,74 @@
// 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.Localisation;
namespace osu.Game.Localisation
{
public static class MaintenanceSettingsStrings
{
private const string prefix = @"osu.Game.Resources.Localisation.MaintenanceSettings";
/// <summary>
/// "Maintenance"
/// </summary>
public static LocalisableString MaintenanceSectionHeader => new TranslatableString(getKey(@"maintenance_section_header"), @"Maintenance");
/// <summary>
/// "Select directory"
/// </summary>
public static LocalisableString SelectDirectory => new TranslatableString(getKey(@"select_directory"), @"Select directory");
/// <summary>
/// "Import beatmaps from stable"
/// </summary>
public static LocalisableString ImportBeatmapsFromStable => new TranslatableString(getKey(@"import_beatmaps_from_stable"), @"Import beatmaps from stable");
/// <summary>
/// "Delete ALL beatmaps"
/// </summary>
public static LocalisableString DeleteAllBeatmaps => new TranslatableString(getKey(@"delete_all_beatmaps"), @"Delete ALL beatmaps");
/// <summary>
/// "Import scores from stable"
/// </summary>
public static LocalisableString ImportScoresFromStable => new TranslatableString(getKey(@"import_scores_from_stable"), @"Import scores from stable");
/// <summary>
/// "Delete ALL scores"
/// </summary>
public static LocalisableString DeleteAllScores => new TranslatableString(getKey(@"delete_all_scores"), @"Delete ALL scores");
/// <summary>
/// "Import skins from stable"
/// </summary>
public static LocalisableString ImportSkinsFromStable => new TranslatableString(getKey(@"import_skins_from_stable"), @"Import skins from stable");
/// <summary>
/// "Delete ALL skins"
/// </summary>
public static LocalisableString DeleteAllSkins => new TranslatableString(getKey(@"delete_all_skins"), @"Delete ALL skins");
/// <summary>
/// "Import collections from stable"
/// </summary>
public static LocalisableString ImportCollectionsFromStable => new TranslatableString(getKey(@"import_collections_from_stable"), @"Import collections from stable");
/// <summary>
/// "Delete ALL collections"
/// </summary>
public static LocalisableString DeleteAllCollections => new TranslatableString(getKey(@"delete_all_collections"), @"Delete ALL collections");
/// <summary>
/// "Restore all hidden difficulties"
/// </summary>
public static LocalisableString RestoreAllHiddenDifficulties => new TranslatableString(getKey(@"restore_all_hidden_difficulties"), @"Restore all hidden difficulties");
/// <summary>
/// "Restore all recently deleted beatmaps"
/// </summary>
public static LocalisableString RestoreAllRecentlyDeletedBeatmaps => new TranslatableString(getKey(@"restore_all_recently_deleted_beatmaps"), @"Restore all recently deleted beatmaps");
private static string getKey(string key) => $"{prefix}:{key}";
}
}

View File

@ -0,0 +1,69 @@
// 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.Localisation;
namespace osu.Game.Localisation
{
public static class OnlineSettingsStrings
{
private const string prefix = @"osu.Game.Resources.Localisation.OnlineSettings";
/// <summary>
/// "Online"
/// </summary>
public static LocalisableString OnlineSectionHeader => new TranslatableString(getKey(@"online_section_header"), @"Online");
/// <summary>
/// "Alerts and Privacy"
/// </summary>
public static LocalisableString AlertsAndPrivacyHeader => new TranslatableString(getKey(@"alerts_and_privacy_header"), @"Alerts and Privacy");
/// <summary>
/// "Show a notification when someone mentions your name"
/// </summary>
public static LocalisableString NotifyOnMentioned => new TranslatableString(getKey(@"notify_on_mentioned"), @"Show a notification when someone mentions your name");
/// <summary>
/// "Show a notification when you receive a private message"
/// </summary>
public static LocalisableString NotifyOnPrivateMessage => new TranslatableString(getKey(@"notify_on_private_message"), @"Show a notification when you receive a private message");
/// <summary>
/// "Integrations"
/// </summary>
public static LocalisableString IntegrationsHeader => new TranslatableString(getKey(@"integrations_header"), @"Integrations");
/// <summary>
/// "Discord Rich Presence"
/// </summary>
public static LocalisableString DiscordRichPresence => new TranslatableString(getKey(@"discord_rich_presence"), @"Discord Rich Presence");
/// <summary>
/// "Web"
/// </summary>
public static LocalisableString WebHeader => new TranslatableString(getKey(@"web_header"), @"Web");
/// <summary>
/// "Warn about opening external links"
/// </summary>
public static LocalisableString ExternalLinkWarning => new TranslatableString(getKey(@"external_link_warning"), @"Warn about opening external links");
/// <summary>
/// "Prefer downloads without video"
/// </summary>
public static LocalisableString PreferNoVideo => new TranslatableString(getKey(@"prefer_no_video"), @"Prefer downloads without video");
/// <summary>
/// "Automatically download beatmaps when spectating"
/// </summary>
public static LocalisableString AutomaticallyDownloadWhenSpectating => new TranslatableString(getKey(@"automatically_download_when_spectating"), @"Automatically download beatmaps when spectating");
/// <summary>
/// "Show explicit content in search results"
/// </summary>
public static LocalisableString ShowExplicitContent => new TranslatableString(getKey(@"show_explicit_content"), @"Show explicit content in search results");
private static string getKey(string key) => $"{prefix}:{key}";
}
}

View File

@ -0,0 +1,54 @@
// 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.Localisation;
namespace osu.Game.Localisation
{
public static class SkinSettingsStrings
{
private const string prefix = @"osu.Game.Resources.Localisation.SkinSettings";
/// <summary>
/// "Skin"
/// </summary>
public static LocalisableString SkinSectionHeader => new TranslatableString(getKey(@"skin_section_header"), @"Skin");
/// <summary>
/// "Skin layout editor"
/// </summary>
public static LocalisableString SkinLayoutEditor => new TranslatableString(getKey(@"skin_layout_editor"), @"Skin layout editor");
/// <summary>
/// "Gameplay cursor size"
/// </summary>
public static LocalisableString GameplayCursorSize => new TranslatableString(getKey(@"gameplay_cursor_size"), @"Gameplay cursor size");
/// <summary>
/// "Adjust gameplay cursor size based on current beatmap"
/// </summary>
public static LocalisableString AutoCursorSize => new TranslatableString(getKey(@"auto_cursor_size"), @"Adjust gameplay cursor size based on current beatmap");
/// <summary>
/// "Beatmap skins"
/// </summary>
public static LocalisableString BeatmapSkins => new TranslatableString(getKey(@"beatmap_skins"), @"Beatmap skins");
/// <summary>
/// "Beatmap colours"
/// </summary>
public static LocalisableString BeatmapColours => new TranslatableString(getKey(@"beatmap_colours"), @"Beatmap colours");
/// <summary>
/// "Beatmap hitsounds"
/// </summary>
public static LocalisableString BeatmapHitsounds => new TranslatableString(getKey(@"beatmap_hitsounds"), @"Beatmap hitsounds");
/// <summary>
/// "Export selected skin"
/// </summary>
public static LocalisableString ExportSkinButton => new TranslatableString(getKey(@"export_skin_button"), @"Export selected skin");
private static string getKey(string key) => $"{prefix}:{key}";
}
}

View File

@ -0,0 +1,114 @@
// 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.Localisation;
namespace osu.Game.Localisation
{
public static class UserInterfaceStrings
{
private const string prefix = @"osu.Game.Resources.Localisation.UserInterface";
/// <summary>
/// "User Interface"
/// </summary>
public static LocalisableString UserInterfaceSectionHeader => new TranslatableString(getKey(@"user_interface_section_header"), @"User Interface");
/// <summary>
/// "General"
/// </summary>
public static LocalisableString GeneralHeader => new TranslatableString(getKey(@"general_header"), @"General");
/// <summary>
/// "Rotate cursor when dragging"
/// </summary>
public static LocalisableString CursorRotation => new TranslatableString(getKey(@"cursor_rotation"), @"Rotate cursor when dragging");
/// <summary>
/// "Menu cursor size"
/// </summary>
public static LocalisableString MenuCursorSize => new TranslatableString(getKey(@"menu_cursor_size"), @"Menu cursor size");
/// <summary>
/// "Parallax"
/// </summary>
public static LocalisableString Parallax => new TranslatableString(getKey(@"parallax"), @"Parallax");
/// <summary>
/// "Hold-to-confirm activation time"
/// </summary>
public static LocalisableString HoldToConfirmActivationTime => new TranslatableString(getKey(@"hold_to_confirm_activation_time"), @"Hold-to-confirm activation time");
/// <summary>
/// "Main Menu"
/// </summary>
public static LocalisableString MainMenuHeader => new TranslatableString(getKey(@"main_menu_header"), @"Main Menu");
/// <summary>
/// "Interface voices"
/// </summary>
public static LocalisableString InterfaceVoices => new TranslatableString(getKey(@"interface_voices"), @"Interface voices");
/// <summary>
/// "osu! music theme"
/// </summary>
public static LocalisableString OsuMusicTheme => new TranslatableString(getKey(@"osu_music_theme"), @"osu! music theme");
/// <summary>
/// "Intro sequence"
/// </summary>
public static LocalisableString IntroSequence => new TranslatableString(getKey(@"intro_sequence"), @"Intro sequence");
/// <summary>
/// "Background source"
/// </summary>
public static LocalisableString BackgroundSource => new TranslatableString(getKey(@"background_source"), @"Background source");
/// <summary>
/// "Seasonal backgrounds"
/// </summary>
public static LocalisableString SeasonalBackgrounds => new TranslatableString(getKey(@"seasonal_backgrounds"), @"Seasonal backgrounds");
/// <summary>
/// "Changes to this setting will only apply with an active osu!supporter tag."
/// </summary>
public static LocalisableString NotSupporterNote => new TranslatableString(getKey(@"not_supporter_note"), @"Changes to this setting will only apply with an active osu!supporter tag.");
/// <summary>
/// "Song Select"
/// </summary>
public static LocalisableString SongSelectHeader => new TranslatableString(getKey(@"song_select_header"), @"Song Select");
/// <summary>
/// "Right mouse drag to absolute scroll"
/// </summary>
public static LocalisableString RightMouseScroll => new TranslatableString(getKey(@"right_mouse_scroll"), @"Right mouse drag to absolute scroll");
/// <summary>
/// "Show converted beatmaps"
/// </summary>
public static LocalisableString ShowConvertedBeatmaps => new TranslatableString(getKey(@"show_converted_beatmaps"), @"Show converted beatmaps");
/// <summary>
/// "Display beatmaps from"
/// </summary>
public static LocalisableString StarsMinimum => new TranslatableString(getKey(@"stars_minimum"), @"Display beatmaps from");
/// <summary>
/// "up to"
/// </summary>
public static LocalisableString StarsMaximum => new TranslatableString(getKey(@"stars_maximum"), @"up to");
/// <summary>
/// "Random selection algorithm"
/// </summary>
public static LocalisableString RandomSelectionAlgorithm => new TranslatableString(getKey(@"random_selection_algorithm"), @"Random selection algorithm");
/// <summary>
/// "no limit"
/// </summary>
public static LocalisableString NoLimit => new TranslatableString(getKey(@"no_limit"), @"no limit");
private static string getKey(string key) => $"{prefix}:{key}";
}
}

View File

@ -9,16 +9,16 @@ namespace osu.Game.Online.API.Requests
{ {
public class MarkChannelAsReadRequest : APIRequest public class MarkChannelAsReadRequest : APIRequest
{ {
private readonly Channel channel; public readonly Channel Channel;
private readonly Message message; public readonly Message Message;
public MarkChannelAsReadRequest(Channel channel, Message message) public MarkChannelAsReadRequest(Channel channel, Message message)
{ {
this.channel = channel; Channel = channel;
this.message = message; Message = message;
} }
protected override string Target => $"chat/channels/{channel.Id}/mark-as-read/{message.Id}"; protected override string Target => $"chat/channels/{Channel.Id}/mark-as-read/{Message.Id}";
protected override WebRequest CreateWebRequest() protected override WebRequest CreateWebRequest()
{ {

View File

@ -553,7 +553,7 @@ namespace osu.Game.Online.Chat
if (channel.LastMessageId == channel.LastReadId) if (channel.LastMessageId == channel.LastReadId)
return; return;
var message = channel.Messages.LastOrDefault(); var message = channel.Messages.FindLast(msg => !(msg is LocalMessage));
if (message == null) if (message == null)
return; return;

View File

@ -139,19 +139,24 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
LoadComponentAsync(Preview = previewTrackManager.Get(beatmapSet), preview => LoadComponentAsync(Preview = previewTrackManager.Get(beatmapSet), preview =>
{ {
// beatmapset may have changed. // Make sure that we schedule to after the next audio frame to fix crashes in single-threaded execution.
if (Preview != preview) // See: https://github.com/ppy/osu-framework/issues/4692
return; Schedule(() =>
{
// beatmapset may have changed.
if (Preview != preview)
return;
AddInternal(preview); AddInternal(preview);
loading = false; loading = false;
// make sure that the update of value of Playing (and the ensuing value change callbacks) // make sure that the update of value of Playing (and the ensuing value change callbacks)
// are marshaled back to the update thread. // are marshaled back to the update thread.
preview.Stopped += () => Schedule(() => playing.Value = false); preview.Stopped += () => Schedule(() => playing.Value = false);
// user may have changed their mind. // user may have changed their mind.
if (playing.Value) if (playing.Value)
attemptStart(); attemptStart();
});
}); });
} }
else else

View File

@ -24,6 +24,7 @@ namespace osu.Game.Overlays.Changelog
public class ChangelogSupporterPromo : CompositeDrawable public class ChangelogSupporterPromo : CompositeDrawable
{ {
private const float image_container_width = 164; private const float image_container_width = 164;
private const float heart_size = 75;
private readonly FillFlowContainer textContainer; private readonly FillFlowContainer textContainer;
private readonly Container imageContainer; private readonly Container imageContainer;
@ -134,18 +135,30 @@ namespace osu.Game.Overlays.Changelog
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
Margin = new MarginPadding { Bottom = 28 },
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
FillMode = FillMode.Fill, FillMode = FillMode.Fill,
Texture = textures.Get(@"Online/supporter-pippi"), Texture = textures.Get(@"Online/supporter-pippi"),
}, },
new Sprite new Container
{ {
Anchor = Anchor.TopCentre, Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre, Origin = Anchor.TopCentre,
Width = 75, Size = new Vector2(heart_size),
Height = 75,
Margin = new MarginPadding { Top = 70 }, Margin = new MarginPadding { Top = 70 },
Texture = textures.Get(@"Online/supporter-heart"), Masking = true,
EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Shadow,
Colour = colour.Pink,
Radius = 10,
Roundness = heart_size / 2,
},
Child = new Sprite
{
Size = new Vector2(heart_size),
Texture = textures.Get(@"Online/supporter-heart"),
},
}, },
}; };
} }

View File

@ -8,12 +8,13 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using osu.Framework.Localisation; using osu.Framework.Localisation;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
using osu.Game.Localisation;
namespace osu.Game.Overlays.Settings.Sections.Audio namespace osu.Game.Overlays.Settings.Sections.Audio
{ {
public class AudioDevicesSettings : SettingsSubsection public class AudioDevicesSettings : SettingsSubsection
{ {
protected override LocalisableString Header => "Devices"; protected override LocalisableString Header => AudioSettingsStrings.AudioDevicesHeader;
[Resolved] [Resolved]
private AudioManager audio { get; set; } private AudioManager audio { get; set; }
@ -78,7 +79,7 @@ namespace osu.Game.Overlays.Settings.Sections.Audio
private class AudioDeviceDropdownControl : DropdownControl private class AudioDeviceDropdownControl : DropdownControl
{ {
protected override LocalisableString GenerateItemText(string item) protected override LocalisableString GenerateItemText(string item)
=> string.IsNullOrEmpty(item) ? "Default" : base.GenerateItemText(item); => string.IsNullOrEmpty(item) ? CommonStrings.Default : base.GenerateItemText(item);
} }
} }
} }

View File

@ -1,17 +1,22 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // 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. // See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Localisation; using osu.Framework.Localisation;
using osu.Game.Configuration; using osu.Game.Configuration;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
using osu.Game.Localisation;
namespace osu.Game.Overlays.Settings.Sections.Audio namespace osu.Game.Overlays.Settings.Sections.Audio
{ {
public class OffsetSettings : SettingsSubsection public class OffsetSettings : SettingsSubsection
{ {
protected override LocalisableString Header => "Offset Adjustment"; protected override LocalisableString Header => AudioSettingsStrings.OffsetHeader;
public override IEnumerable<string> FilterTerms => base.FilterTerms.Concat(new[] { "universal", "uo", "timing" });
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuConfigManager config) private void load(OsuConfigManager config)
@ -20,13 +25,13 @@ namespace osu.Game.Overlays.Settings.Sections.Audio
{ {
new SettingsSlider<double, OffsetSlider> new SettingsSlider<double, OffsetSlider>
{ {
LabelText = "Audio offset", LabelText = AudioSettingsStrings.AudioOffset,
Current = config.GetBindable<double>(OsuSetting.AudioOffset), Current = config.GetBindable<double>(OsuSetting.AudioOffset),
KeyboardStep = 1f KeyboardStep = 1f
}, },
new SettingsButton new SettingsButton
{ {
Text = "Offset wizard" Text = AudioSettingsStrings.OffsetWizard
} }
}; };
} }

View File

@ -6,12 +6,13 @@ using osu.Framework.Audio;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Localisation; using osu.Framework.Localisation;
using osu.Game.Configuration; using osu.Game.Configuration;
using osu.Game.Localisation;
namespace osu.Game.Overlays.Settings.Sections.Audio namespace osu.Game.Overlays.Settings.Sections.Audio
{ {
public class VolumeSettings : SettingsSubsection public class VolumeSettings : SettingsSubsection
{ {
protected override LocalisableString Header => "Volume"; protected override LocalisableString Header => AudioSettingsStrings.VolumeHeader;
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(AudioManager audio, OsuConfigManager config) private void load(AudioManager audio, OsuConfigManager config)
@ -20,28 +21,28 @@ namespace osu.Game.Overlays.Settings.Sections.Audio
{ {
new SettingsSlider<double> new SettingsSlider<double>
{ {
LabelText = "Master", LabelText = AudioSettingsStrings.MasterVolume,
Current = audio.Volume, Current = audio.Volume,
KeyboardStep = 0.01f, KeyboardStep = 0.01f,
DisplayAsPercentage = true DisplayAsPercentage = true
}, },
new SettingsSlider<double> new SettingsSlider<double>
{ {
LabelText = "Master (window inactive)", LabelText = AudioSettingsStrings.MasterVolumeInactive,
Current = config.GetBindable<double>(OsuSetting.VolumeInactive), Current = config.GetBindable<double>(OsuSetting.VolumeInactive),
KeyboardStep = 0.01f, KeyboardStep = 0.01f,
DisplayAsPercentage = true DisplayAsPercentage = true
}, },
new SettingsSlider<double> new SettingsSlider<double>
{ {
LabelText = "Effect", LabelText = AudioSettingsStrings.EffectVolume,
Current = audio.VolumeSample, Current = audio.VolumeSample,
KeyboardStep = 0.01f, KeyboardStep = 0.01f,
DisplayAsPercentage = true DisplayAsPercentage = true
}, },
new SettingsSlider<double> new SettingsSlider<double>
{ {
LabelText = "Music", LabelText = AudioSettingsStrings.MusicVolume,
Current = audio.VolumeTrack, Current = audio.VolumeTrack,
KeyboardStep = 0.01f, KeyboardStep = 0.01f,
DisplayAsPercentage = true DisplayAsPercentage = true

View File

@ -3,15 +3,17 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using osu.Framework.Localisation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Game.Localisation;
using osu.Game.Overlays.Settings.Sections.Audio; using osu.Game.Overlays.Settings.Sections.Audio;
namespace osu.Game.Overlays.Settings.Sections namespace osu.Game.Overlays.Settings.Sections
{ {
public class AudioSection : SettingsSection public class AudioSection : SettingsSection
{ {
public override string Header => "Audio"; public override LocalisableString Header => AudioSettingsStrings.AudioSectionHeader;
public override Drawable CreateIcon() => new SpriteIcon public override Drawable CreateIcon() => new SpriteIcon
{ {

View File

@ -6,13 +6,14 @@ using osu.Framework.Configuration;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Localisation; using osu.Framework.Localisation;
using osu.Framework.Screens; using osu.Framework.Screens;
using osu.Game.Localisation;
using osu.Game.Screens.Import; using osu.Game.Screens.Import;
namespace osu.Game.Overlays.Settings.Sections.Debug namespace osu.Game.Overlays.Settings.Sections.Debug
{ {
public class GeneralSettings : SettingsSubsection public class GeneralSettings : SettingsSubsection
{ {
protected override LocalisableString Header => "General"; protected override LocalisableString Header => DebugSettingsStrings.GeneralHeader;
[BackgroundDependencyLoader(true)] [BackgroundDependencyLoader(true)]
private void load(FrameworkDebugConfigManager config, FrameworkConfigManager frameworkConfig, OsuGame game) private void load(FrameworkDebugConfigManager config, FrameworkConfigManager frameworkConfig, OsuGame game)
@ -21,18 +22,18 @@ namespace osu.Game.Overlays.Settings.Sections.Debug
{ {
new SettingsCheckbox new SettingsCheckbox
{ {
LabelText = "Show log overlay", LabelText = DebugSettingsStrings.ShowLogOverlay,
Current = frameworkConfig.GetBindable<bool>(FrameworkSetting.ShowLogOverlay) Current = frameworkConfig.GetBindable<bool>(FrameworkSetting.ShowLogOverlay)
}, },
new SettingsCheckbox new SettingsCheckbox
{ {
LabelText = "Bypass front-to-back render pass", LabelText = DebugSettingsStrings.BypassFrontToBackPass,
Current = config.GetBindable<bool>(DebugSetting.BypassFrontToBackPass) Current = config.GetBindable<bool>(DebugSetting.BypassFrontToBackPass)
} }
}; };
Add(new SettingsButton Add(new SettingsButton
{ {
Text = "Import files", Text = DebugSettingsStrings.ImportFiles,
Action = () => game?.PerformFromScreen(menu => menu.Push(new FileImportScreen())) Action = () => game?.PerformFromScreen(menu => menu.Push(new FileImportScreen()))
}); });
} }

View File

@ -6,12 +6,13 @@ using osu.Framework.Configuration;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Localisation; using osu.Framework.Localisation;
using osu.Framework.Platform; using osu.Framework.Platform;
using osu.Game.Localisation;
namespace osu.Game.Overlays.Settings.Sections.Debug namespace osu.Game.Overlays.Settings.Sections.Debug
{ {
public class MemorySettings : SettingsSubsection public class MemorySettings : SettingsSubsection
{ {
protected override LocalisableString Header => "Memory"; protected override LocalisableString Header => DebugSettingsStrings.MemoryHeader;
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(FrameworkDebugConfigManager config, GameHost host) private void load(FrameworkDebugConfigManager config, GameHost host)
@ -20,7 +21,7 @@ namespace osu.Game.Overlays.Settings.Sections.Debug
{ {
new SettingsButton new SettingsButton
{ {
Text = "Clear all caches", Text = DebugSettingsStrings.ClearAllCaches,
Action = host.Collect Action = host.Collect
}, },
}; };

View File

@ -3,13 +3,15 @@
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Game.Localisation;
using osu.Game.Overlays.Settings.Sections.Debug; using osu.Game.Overlays.Settings.Sections.Debug;
namespace osu.Game.Overlays.Settings.Sections namespace osu.Game.Overlays.Settings.Sections
{ {
public class DebugSection : SettingsSection public class DebugSection : SettingsSection
{ {
public override string Header => "Debug"; public override LocalisableString Header => DebugSettingsStrings.DebugSectionHeader;
public override Drawable CreateIcon() => new SpriteIcon public override Drawable CreateIcon() => new SpriteIcon
{ {

View File

@ -6,13 +6,14 @@ using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Localisation; using osu.Framework.Localisation;
using osu.Game.Configuration; using osu.Game.Configuration;
using osu.Game.Localisation;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
namespace osu.Game.Overlays.Settings.Sections.Gameplay namespace osu.Game.Overlays.Settings.Sections.Gameplay
{ {
public class GeneralSettings : SettingsSubsection public class GeneralSettings : SettingsSubsection
{ {
protected override LocalisableString Header => "General"; protected override LocalisableString Header => GameplaySettingsStrings.GeneralHeader;
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuConfigManager config) private void load(OsuConfigManager config)
@ -21,62 +22,62 @@ namespace osu.Game.Overlays.Settings.Sections.Gameplay
{ {
new SettingsSlider<double> new SettingsSlider<double>
{ {
LabelText = "Background dim", LabelText = GameplaySettingsStrings.BackgroundDim,
Current = config.GetBindable<double>(OsuSetting.DimLevel), Current = config.GetBindable<double>(OsuSetting.DimLevel),
KeyboardStep = 0.01f, KeyboardStep = 0.01f,
DisplayAsPercentage = true DisplayAsPercentage = true
}, },
new SettingsSlider<double> new SettingsSlider<double>
{ {
LabelText = "Background blur", LabelText = GameplaySettingsStrings.BackgroundBlur,
Current = config.GetBindable<double>(OsuSetting.BlurLevel), Current = config.GetBindable<double>(OsuSetting.BlurLevel),
KeyboardStep = 0.01f, KeyboardStep = 0.01f,
DisplayAsPercentage = true DisplayAsPercentage = true
}, },
new SettingsCheckbox new SettingsCheckbox
{ {
LabelText = "Lighten playfield during breaks", LabelText = GameplaySettingsStrings.LightenDuringBreaks,
Current = config.GetBindable<bool>(OsuSetting.LightenDuringBreaks) Current = config.GetBindable<bool>(OsuSetting.LightenDuringBreaks)
}, },
new SettingsEnumDropdown<HUDVisibilityMode> new SettingsEnumDropdown<HUDVisibilityMode>
{ {
LabelText = "HUD overlay visibility mode", LabelText = GameplaySettingsStrings.HUDVisibilityMode,
Current = config.GetBindable<HUDVisibilityMode>(OsuSetting.HUDVisibilityMode) Current = config.GetBindable<HUDVisibilityMode>(OsuSetting.HUDVisibilityMode)
}, },
new SettingsCheckbox new SettingsCheckbox
{ {
LabelText = "Show difficulty graph on progress bar", LabelText = GameplaySettingsStrings.ShowDifficultyGraph,
Current = config.GetBindable<bool>(OsuSetting.ShowDifficultyGraph) Current = config.GetBindable<bool>(OsuSetting.ShowProgressGraph)
}, },
new SettingsCheckbox new SettingsCheckbox
{ {
LabelText = "Show health display even when you can't fail", LabelText = GameplaySettingsStrings.ShowHealthDisplayWhenCantFail,
Current = config.GetBindable<bool>(OsuSetting.ShowHealthDisplayWhenCantFail), Current = config.GetBindable<bool>(OsuSetting.ShowHealthDisplayWhenCantFail),
Keywords = new[] { "hp", "bar" } Keywords = new[] { "hp", "bar" }
}, },
new SettingsCheckbox new SettingsCheckbox
{ {
LabelText = "Fade playfield to red when health is low", LabelText = GameplaySettingsStrings.FadePlayfieldWhenHealthLow,
Current = config.GetBindable<bool>(OsuSetting.FadePlayfieldWhenHealthLow), Current = config.GetBindable<bool>(OsuSetting.FadePlayfieldWhenHealthLow),
}, },
new SettingsCheckbox new SettingsCheckbox
{ {
LabelText = "Always show key overlay", LabelText = GameplaySettingsStrings.AlwaysShowKeyOverlay,
Current = config.GetBindable<bool>(OsuSetting.KeyOverlay) Current = config.GetBindable<bool>(OsuSetting.KeyOverlay)
}, },
new SettingsCheckbox new SettingsCheckbox
{ {
LabelText = "Positional hitsounds", LabelText = GameplaySettingsStrings.PositionalHitsounds,
Current = config.GetBindable<bool>(OsuSetting.PositionalHitSounds) Current = config.GetBindable<bool>(OsuSetting.PositionalHitSounds)
}, },
new SettingsCheckbox new SettingsCheckbox
{ {
LabelText = "Always play first combo break sound", LabelText = GameplaySettingsStrings.AlwaysPlayFirstComboBreak,
Current = config.GetBindable<bool>(OsuSetting.AlwaysPlayFirstComboBreak) Current = config.GetBindable<bool>(OsuSetting.AlwaysPlayFirstComboBreak)
}, },
new SettingsEnumDropdown<ScoringMode> new SettingsEnumDropdown<ScoringMode>
{ {
LabelText = "Score display mode", LabelText = GameplaySettingsStrings.ScoreDisplayMode,
Current = config.GetBindable<ScoringMode>(OsuSetting.ScoreDisplayMode), Current = config.GetBindable<ScoringMode>(OsuSetting.ScoreDisplayMode),
Keywords = new[] { "scoring" } Keywords = new[] { "scoring" }
}, },
@ -86,7 +87,7 @@ namespace osu.Game.Overlays.Settings.Sections.Gameplay
{ {
Add(new SettingsCheckbox Add(new SettingsCheckbox
{ {
LabelText = "Disable Windows key during gameplay", LabelText = GameplaySettingsStrings.DisableWinKey,
Current = config.GetBindable<bool>(OsuSetting.GameplayDisableWinKey) Current = config.GetBindable<bool>(OsuSetting.GameplayDisableWinKey)
}); });
} }

View File

@ -6,12 +6,13 @@ using System.Linq;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Localisation; using osu.Framework.Localisation;
using osu.Game.Configuration; using osu.Game.Configuration;
using osu.Game.Localisation;
namespace osu.Game.Overlays.Settings.Sections.Gameplay namespace osu.Game.Overlays.Settings.Sections.Gameplay
{ {
public class ModsSettings : SettingsSubsection public class ModsSettings : SettingsSubsection
{ {
protected override LocalisableString Header => "Mods"; protected override LocalisableString Header => GameplaySettingsStrings.ModsHeader;
public override IEnumerable<string> FilterTerms => base.FilterTerms.Concat(new[] { "mod" }); public override IEnumerable<string> FilterTerms => base.FilterTerms.Concat(new[] { "mod" });
@ -22,7 +23,7 @@ namespace osu.Game.Overlays.Settings.Sections.Gameplay
{ {
new SettingsCheckbox new SettingsCheckbox
{ {
LabelText = "Increase visibility of first object when visual impairment mods are enabled", LabelText = GameplaySettingsStrings.IncreaseFirstObjectVisibility,
Current = config.GetBindable<bool>(OsuSetting.IncreaseFirstObjectVisibility), Current = config.GetBindable<bool>(OsuSetting.IncreaseFirstObjectVisibility),
}, },
}; };

View File

@ -9,12 +9,14 @@ using osu.Game.Rulesets;
using System.Linq; using System.Linq;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Framework.Logging; using osu.Framework.Logging;
using osu.Framework.Localisation;
using osu.Game.Localisation;
namespace osu.Game.Overlays.Settings.Sections namespace osu.Game.Overlays.Settings.Sections
{ {
public class GameplaySection : SettingsSection public class GameplaySection : SettingsSection
{ {
public override string Header => "Gameplay"; public override LocalisableString Header => GameplaySettingsStrings.GameplaySectionHeader;
public override Drawable CreateIcon() => new SpriteIcon public override Drawable CreateIcon() => new SpriteIcon
{ {

View File

@ -16,7 +16,7 @@ namespace osu.Game.Overlays.Settings.Sections.General
private SettingsDropdown<Language> languageSelection; private SettingsDropdown<Language> languageSelection;
private Bindable<string> frameworkLocale; private Bindable<string> frameworkLocale;
protected override LocalisableString Header => "Language"; protected override LocalisableString Header => GeneralSettingsStrings.LanguageHeader;
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(FrameworkConfigManager frameworkConfig) private void load(FrameworkConfigManager frameworkConfig)
@ -27,11 +27,11 @@ namespace osu.Game.Overlays.Settings.Sections.General
{ {
languageSelection = new SettingsEnumDropdown<Language> languageSelection = new SettingsEnumDropdown<Language>
{ {
LabelText = "Language", LabelText = GeneralSettingsStrings.LanguageDropdown,
}, },
new SettingsCheckbox new SettingsCheckbox
{ {
LabelText = "Prefer metadata in original language", LabelText = GeneralSettingsStrings.PreferOriginalMetadataLanguage,
Current = frameworkConfig.GetBindable<bool>(FrameworkSetting.ShowUnicode) Current = frameworkConfig.GetBindable<bool>(FrameworkSetting.ShowUnicode)
}, },
}; };

View File

@ -9,6 +9,7 @@ using osu.Framework.Localisation;
using osu.Framework.Platform; using osu.Framework.Platform;
using osu.Framework.Screens; using osu.Framework.Screens;
using osu.Game.Configuration; using osu.Game.Configuration;
using osu.Game.Localisation;
using osu.Game.Overlays.Notifications; using osu.Game.Overlays.Notifications;
using osu.Game.Overlays.Settings.Sections.Maintenance; using osu.Game.Overlays.Settings.Sections.Maintenance;
using osu.Game.Updater; using osu.Game.Updater;
@ -20,7 +21,7 @@ namespace osu.Game.Overlays.Settings.Sections.General
[Resolved(CanBeNull = true)] [Resolved(CanBeNull = true)]
private UpdateManager updateManager { get; set; } private UpdateManager updateManager { get; set; }
protected override LocalisableString Header => "Updates"; protected override LocalisableString Header => GeneralSettingsStrings.UpdateHeader;
private SettingsButton checkForUpdatesButton; private SettingsButton checkForUpdatesButton;
@ -32,7 +33,7 @@ namespace osu.Game.Overlays.Settings.Sections.General
{ {
Add(new SettingsEnumDropdown<ReleaseStream> Add(new SettingsEnumDropdown<ReleaseStream>
{ {
LabelText = "Release stream", LabelText = GeneralSettingsStrings.ReleaseStream,
Current = config.GetBindable<ReleaseStream>(OsuSetting.ReleaseStream), Current = config.GetBindable<ReleaseStream>(OsuSetting.ReleaseStream),
}); });
@ -40,7 +41,7 @@ namespace osu.Game.Overlays.Settings.Sections.General
{ {
Add(checkForUpdatesButton = new SettingsButton Add(checkForUpdatesButton = new SettingsButton
{ {
Text = "Check for updates", Text = GeneralSettingsStrings.CheckUpdate,
Action = () => Action = () =>
{ {
checkForUpdatesButton.Enabled.Value = false; checkForUpdatesButton.Enabled.Value = false;
@ -65,13 +66,13 @@ namespace osu.Game.Overlays.Settings.Sections.General
{ {
Add(new SettingsButton Add(new SettingsButton
{ {
Text = "Open osu! folder", Text = GeneralSettingsStrings.OpenOsuFolder,
Action = storage.OpenInNativeExplorer, Action = storage.OpenInNativeExplorer,
}); });
Add(new SettingsButton Add(new SettingsButton
{ {
Text = "Change folder location...", Text = GeneralSettingsStrings.ChangeFolderLocation,
Action = () => game?.PerformFromScreen(menu => menu.Push(new MigrationSelectScreen())) Action = () => game?.PerformFromScreen(menu => menu.Push(new MigrationSelectScreen()))
}); });
} }

View File

@ -3,13 +3,15 @@
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Game.Localisation;
using osu.Game.Overlays.Settings.Sections.General; using osu.Game.Overlays.Settings.Sections.General;
namespace osu.Game.Overlays.Settings.Sections namespace osu.Game.Overlays.Settings.Sections
{ {
public class GeneralSection : SettingsSection public class GeneralSection : SettingsSection
{ {
public override string Header => "General"; public override LocalisableString Header => GeneralSettingsStrings.GeneralSectionHeader;
public override Drawable CreateIcon() => new SpriteIcon public override Drawable CreateIcon() => new SpriteIcon
{ {

View File

@ -5,12 +5,13 @@ using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Localisation; using osu.Framework.Localisation;
using osu.Game.Configuration; using osu.Game.Configuration;
using osu.Game.Localisation;
namespace osu.Game.Overlays.Settings.Sections.Graphics namespace osu.Game.Overlays.Settings.Sections.Graphics
{ {
public class DetailSettings : SettingsSubsection public class DetailSettings : SettingsSubsection
{ {
protected override LocalisableString Header => "Detail Settings"; protected override LocalisableString Header => GraphicsSettingsStrings.DetailSettingsHeader;
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuConfigManager config) private void load(OsuConfigManager config)
@ -19,22 +20,22 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
{ {
new SettingsCheckbox new SettingsCheckbox
{ {
LabelText = "Storyboard / Video", LabelText = GraphicsSettingsStrings.StoryboardVideo,
Current = config.GetBindable<bool>(OsuSetting.ShowStoryboard) Current = config.GetBindable<bool>(OsuSetting.ShowStoryboard)
}, },
new SettingsCheckbox new SettingsCheckbox
{ {
LabelText = "Hit Lighting", LabelText = GraphicsSettingsStrings.HitLighting,
Current = config.GetBindable<bool>(OsuSetting.HitLighting) Current = config.GetBindable<bool>(OsuSetting.HitLighting)
}, },
new SettingsEnumDropdown<ScreenshotFormat> new SettingsEnumDropdown<ScreenshotFormat>
{ {
LabelText = "Screenshot format", LabelText = GraphicsSettingsStrings.ScreenshotFormat,
Current = config.GetBindable<ScreenshotFormat>(OsuSetting.ScreenshotFormat) Current = config.GetBindable<ScreenshotFormat>(OsuSetting.ScreenshotFormat)
}, },
new SettingsCheckbox new SettingsCheckbox
{ {
LabelText = "Show menu cursor in screenshots", LabelText = GraphicsSettingsStrings.ShowCursorInScreenshots,
Current = config.GetBindable<bool>(OsuSetting.ScreenshotCaptureMenuCursor) Current = config.GetBindable<bool>(OsuSetting.ScreenshotCaptureMenuCursor)
} }
}; };

View File

@ -16,13 +16,14 @@ using osu.Framework.Platform;
using osu.Game.Configuration; using osu.Game.Configuration;
using osu.Game.Graphics.Containers; using osu.Game.Graphics.Containers;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
using osu.Game.Localisation;
using osuTK.Graphics; using osuTK.Graphics;
namespace osu.Game.Overlays.Settings.Sections.Graphics namespace osu.Game.Overlays.Settings.Sections.Graphics
{ {
public class LayoutSettings : SettingsSubsection public class LayoutSettings : SettingsSubsection
{ {
protected override LocalisableString Header => "Layout"; protected override LocalisableString Header => GraphicsSettingsStrings.LayoutHeader;
private FillFlowContainer<SettingsSlider<float>> scalingSettings; private FillFlowContainer<SettingsSlider<float>> scalingSettings;
@ -67,20 +68,20 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
{ {
windowModeDropdown = new SettingsDropdown<WindowMode> windowModeDropdown = new SettingsDropdown<WindowMode>
{ {
LabelText = "Screen mode", LabelText = GraphicsSettingsStrings.ScreenMode,
ItemSource = windowModes, ItemSource = windowModes,
Current = config.GetBindable<WindowMode>(FrameworkSetting.WindowMode), Current = config.GetBindable<WindowMode>(FrameworkSetting.WindowMode),
}, },
resolutionDropdown = new ResolutionSettingsDropdown resolutionDropdown = new ResolutionSettingsDropdown
{ {
LabelText = "Resolution", LabelText = GraphicsSettingsStrings.Resolution,
ShowsDefaultIndicator = false, ShowsDefaultIndicator = false,
ItemSource = resolutions, ItemSource = resolutions,
Current = sizeFullscreen Current = sizeFullscreen
}, },
new SettingsSlider<float, UIScaleSlider> new SettingsSlider<float, UIScaleSlider>
{ {
LabelText = "UI Scaling", LabelText = GraphicsSettingsStrings.UIScaling,
TransferValueOnCommit = true, TransferValueOnCommit = true,
Current = osuConfig.GetBindable<float>(OsuSetting.UIScale), Current = osuConfig.GetBindable<float>(OsuSetting.UIScale),
KeyboardStep = 0.01f, KeyboardStep = 0.01f,
@ -88,7 +89,7 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
}, },
new SettingsEnumDropdown<ScalingMode> new SettingsEnumDropdown<ScalingMode>
{ {
LabelText = "Screen Scaling", LabelText = GraphicsSettingsStrings.ScreenScaling,
Current = osuConfig.GetBindable<ScalingMode>(OsuSetting.Scaling), Current = osuConfig.GetBindable<ScalingMode>(OsuSetting.Scaling),
Keywords = new[] { "scale", "letterbox" }, Keywords = new[] { "scale", "letterbox" },
}, },
@ -104,28 +105,28 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
{ {
new SettingsSlider<float> new SettingsSlider<float>
{ {
LabelText = "Horizontal position", LabelText = GraphicsSettingsStrings.HorizontalPosition,
Current = scalingPositionX, Current = scalingPositionX,
KeyboardStep = 0.01f, KeyboardStep = 0.01f,
DisplayAsPercentage = true DisplayAsPercentage = true
}, },
new SettingsSlider<float> new SettingsSlider<float>
{ {
LabelText = "Vertical position", LabelText = GraphicsSettingsStrings.VerticalPosition,
Current = scalingPositionY, Current = scalingPositionY,
KeyboardStep = 0.01f, KeyboardStep = 0.01f,
DisplayAsPercentage = true DisplayAsPercentage = true
}, },
new SettingsSlider<float> new SettingsSlider<float>
{ {
LabelText = "Horizontal scale", LabelText = GraphicsSettingsStrings.HorizontalScale,
Current = scalingSizeX, Current = scalingSizeX,
KeyboardStep = 0.01f, KeyboardStep = 0.01f,
DisplayAsPercentage = true DisplayAsPercentage = true
}, },
new SettingsSlider<float> new SettingsSlider<float>
{ {
LabelText = "Vertical scale", LabelText = GraphicsSettingsStrings.VerticalScale,
Current = scalingSizeY, Current = scalingSizeY,
KeyboardStep = 0.01f, KeyboardStep = 0.01f,
DisplayAsPercentage = true DisplayAsPercentage = true
@ -145,9 +146,7 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
{ {
updateResolutionDropdown(); updateResolutionDropdown();
const string not_fullscreen_note = "Running without fullscreen mode will increase your input latency!"; windowModeDropdown.WarningText = mode.NewValue != WindowMode.Fullscreen ? GraphicsSettingsStrings.NotFullscreenNote : default;
windowModeDropdown.WarningText = mode.NewValue != WindowMode.Fullscreen ? not_fullscreen_note : string.Empty;
}, true); }, true);
windowModes.BindCollectionChanged((sender, args) => windowModes.BindCollectionChanged((sender, args) =>
@ -245,7 +244,7 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
protected override LocalisableString GenerateItemText(Size item) protected override LocalisableString GenerateItemText(Size item)
{ {
if (item == new Size(9999, 9999)) if (item == new Size(9999, 9999))
return "Default"; return CommonStrings.Default;
return $"{item.Width}x{item.Height}"; return $"{item.Width}x{item.Height}";
} }

View File

@ -7,12 +7,13 @@ using osu.Framework.Graphics;
using osu.Framework.Localisation; using osu.Framework.Localisation;
using osu.Framework.Platform; using osu.Framework.Platform;
using osu.Game.Configuration; using osu.Game.Configuration;
using osu.Game.Localisation;
namespace osu.Game.Overlays.Settings.Sections.Graphics namespace osu.Game.Overlays.Settings.Sections.Graphics
{ {
public class RendererSettings : SettingsSubsection public class RendererSettings : SettingsSubsection
{ {
protected override LocalisableString Header => "Renderer"; protected override LocalisableString Header => GraphicsSettingsStrings.RendererHeader;
private SettingsEnumDropdown<FrameSync> frameLimiterDropdown; private SettingsEnumDropdown<FrameSync> frameLimiterDropdown;
@ -25,17 +26,17 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
// TODO: this needs to be a custom dropdown at some point // TODO: this needs to be a custom dropdown at some point
frameLimiterDropdown = new SettingsEnumDropdown<FrameSync> frameLimiterDropdown = new SettingsEnumDropdown<FrameSync>
{ {
LabelText = "Frame limiter", LabelText = GraphicsSettingsStrings.FrameLimiter,
Current = config.GetBindable<FrameSync>(FrameworkSetting.FrameSync) Current = config.GetBindable<FrameSync>(FrameworkSetting.FrameSync)
}, },
new SettingsEnumDropdown<ExecutionMode> new SettingsEnumDropdown<ExecutionMode>
{ {
LabelText = "Threading mode", LabelText = GraphicsSettingsStrings.ThreadingMode,
Current = config.GetBindable<ExecutionMode>(FrameworkSetting.ExecutionMode) Current = config.GetBindable<ExecutionMode>(FrameworkSetting.ExecutionMode)
}, },
new SettingsCheckbox new SettingsCheckbox
{ {
LabelText = "Show FPS", LabelText = GraphicsSettingsStrings.ShowFPS,
Current = osuConfig.GetBindable<bool>(OsuSetting.ShowFpsDisplay) Current = osuConfig.GetBindable<bool>(OsuSetting.ShowFpsDisplay)
}, },
}; };
@ -47,9 +48,7 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
frameLimiterDropdown.Current.BindValueChanged(limit => frameLimiterDropdown.Current.BindValueChanged(limit =>
{ {
const string unlimited_frames_note = "Using unlimited frame limiter can lead to stutters, bad performance and overheating. It will not improve perceived latency. \"2x refresh rate\" is recommended."; frameLimiterDropdown.WarningText = limit.NewValue == FrameSync.Unlimited ? GraphicsSettingsStrings.UnlimitedFramesNote : default;
frameLimiterDropdown.WarningText = limit.NewValue == FrameSync.Unlimited ? unlimited_frames_note : string.Empty;
}, true); }, true);
} }
} }

View File

@ -3,13 +3,15 @@
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Game.Localisation;
using osu.Game.Overlays.Settings.Sections.Graphics; using osu.Game.Overlays.Settings.Sections.Graphics;
namespace osu.Game.Overlays.Settings.Sections namespace osu.Game.Overlays.Settings.Sections
{ {
public class GraphicsSection : SettingsSection public class GraphicsSection : SettingsSection
{ {
public override string Header => "Graphics"; public override LocalisableString Header => GraphicsSettingsStrings.GraphicsSectionHeader;
public override Drawable CreateIcon() => new SpriteIcon public override Drawable CreateIcon() => new SpriteIcon
{ {

View File

@ -5,6 +5,7 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation; using osu.Framework.Localisation;
using osu.Game.Input.Bindings; using osu.Game.Input.Bindings;
using osu.Game.Localisation;
namespace osu.Game.Overlays.Settings.Sections.Input namespace osu.Game.Overlays.Settings.Sections.Input
{ {
@ -15,7 +16,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input
Icon = FontAwesome.Solid.Globe Icon = FontAwesome.Solid.Globe
}; };
public override string Header => "Global"; public override LocalisableString Header => InputSettingsStrings.GlobalKeyBindingHeader;
public GlobalKeyBindingsSection(GlobalActionContainer manager) public GlobalKeyBindingsSection(GlobalActionContainer manager)
{ {
@ -39,7 +40,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input
private class SongSelectKeyBindingSubsection : KeyBindingsSubsection private class SongSelectKeyBindingSubsection : KeyBindingsSubsection
{ {
protected override LocalisableString Header => "Song Select"; protected override LocalisableString Header => InputSettingsStrings.SongSelectSection;
public SongSelectKeyBindingSubsection(GlobalActionContainer manager) public SongSelectKeyBindingSubsection(GlobalActionContainer manager)
: base(null) : base(null)
@ -50,7 +51,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input
private class InGameKeyBindingsSubsection : KeyBindingsSubsection private class InGameKeyBindingsSubsection : KeyBindingsSubsection
{ {
protected override LocalisableString Header => "In Game"; protected override LocalisableString Header => InputSettingsStrings.InGameSection;
public InGameKeyBindingsSubsection(GlobalActionContainer manager) public InGameKeyBindingsSubsection(GlobalActionContainer manager)
: base(null) : base(null)
@ -61,7 +62,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input
private class AudioControlKeyBindingsSubsection : KeyBindingsSubsection private class AudioControlKeyBindingsSubsection : KeyBindingsSubsection
{ {
protected override LocalisableString Header => "Audio"; protected override LocalisableString Header => InputSettingsStrings.AudioSection;
public AudioControlKeyBindingsSubsection(GlobalActionContainer manager) public AudioControlKeyBindingsSubsection(GlobalActionContainer manager)
: base(null) : base(null)
@ -72,7 +73,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input
private class EditorKeyBindingsSubsection : KeyBindingsSubsection private class EditorKeyBindingsSubsection : KeyBindingsSubsection
{ {
protected override LocalisableString Header => "Editor"; protected override LocalisableString Header => InputSettingsStrings.EditorSection;
public EditorKeyBindingsSubsection(GlobalActionContainer manager) public EditorKeyBindingsSubsection(GlobalActionContainer manager)
: base(null) : base(null)

View File

@ -4,13 +4,14 @@
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Game.Input.Bindings; using osu.Game.Input.Bindings;
using osu.Game.Localisation;
using osu.Game.Rulesets; using osu.Game.Rulesets;
namespace osu.Game.Overlays.Settings.Sections.Input namespace osu.Game.Overlays.Settings.Sections.Input
{ {
public class KeyBindingPanel : SettingsSubPanel public class KeyBindingPanel : SettingsSubPanel
{ {
protected override Drawable CreateHeader() => new SettingsHeader("key configuration", "Customise your keys!"); protected override Drawable CreateHeader() => new SettingsHeader(InputSettingsStrings.KeyBindingPanelHeader, InputSettingsStrings.KeyBindingPanelDescription);
[BackgroundDependencyLoader(permitNulls: true)] [BackgroundDependencyLoader(permitNulls: true)]
private void load(RulesetStore rulesets, GlobalActionContainer global) private void load(RulesetStore rulesets, GlobalActionContainer global)

View File

@ -20,6 +20,7 @@ using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
using osu.Game.Input; using osu.Game.Input;
using osu.Game.Input.Bindings; using osu.Game.Input.Bindings;
using osu.Game.Localisation;
using osuTK; using osuTK;
using osuTK.Graphics; using osuTK.Graphics;
using osuTK.Input; using osuTK.Input;
@ -385,7 +386,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input
{ {
public CancelButton() public CancelButton()
{ {
Text = "Cancel"; Text = CommonStrings.Cancel;
Size = new Vector2(80, 20); Size = new Vector2(80, 20);
} }
} }
@ -394,7 +395,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input
{ {
public ClearButton() public ClearButton()
{ {
Text = "Clear"; Text = CommonStrings.Clear;
Size = new Vector2(80, 20); Size = new Vector2(80, 20);
} }
} }

View File

@ -10,6 +10,7 @@ using osu.Game.Database;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
using osu.Game.Input.Bindings; using osu.Game.Input.Bindings;
using osu.Game.Rulesets; using osu.Game.Rulesets;
using osu.Game.Localisation;
using osuTK; using osuTK;
namespace osu.Game.Overlays.Settings.Sections.Input namespace osu.Game.Overlays.Settings.Sections.Input
@ -64,7 +65,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load()
{ {
Text = "Reset all bindings in section"; Text = InputSettingsStrings.ResetSectionButton;
RelativeSizeAxes = Axes.X; RelativeSizeAxes = Axes.X;
Width = 0.5f; Width = 0.5f;
Anchor = Anchor.TopCentre; Anchor = Anchor.TopCentre;

View File

@ -3,6 +3,7 @@
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Rulesets; using osu.Game.Rulesets;
@ -15,7 +16,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input
Icon = OsuIcon.Hot Icon = OsuIcon.Hot
}; };
public override string Header => ruleset.Name; public override LocalisableString Header => ruleset.Name;
private readonly RulesetInfo ruleset; private readonly RulesetInfo ruleset;

View File

@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // 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. // See the LICENCE file in the repository root for full licence text.
using osu.Framework;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Graphics; using osu.Framework.Graphics;
@ -9,9 +10,11 @@ using osu.Framework.Input.Handlers.Tablet;
using osu.Framework.Localisation; using osu.Framework.Localisation;
using osu.Framework.Platform; using osu.Framework.Platform;
using osu.Framework.Threading; using osu.Framework.Threading;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Sprites;
using osuTK; using osuTK;
using osu.Game.Localisation; using osu.Game.Localisation;
using osu.Game.Online.Chat;
namespace osu.Game.Overlays.Settings.Sections.Input namespace osu.Game.Overlays.Settings.Sections.Input
{ {
@ -19,6 +22,8 @@ namespace osu.Game.Overlays.Settings.Sections.Input
{ {
private readonly ITabletHandler tabletHandler; private readonly ITabletHandler tabletHandler;
private readonly Bindable<bool> enabled = new BindableBool(true);
private readonly Bindable<Vector2> areaOffset = new Bindable<Vector2>(); private readonly Bindable<Vector2> areaOffset = new Bindable<Vector2>();
private readonly Bindable<Vector2> areaSize = new Bindable<Vector2>(); private readonly Bindable<Vector2> areaSize = new Bindable<Vector2>();
private readonly IBindable<TabletInfo> tablet = new Bindable<TabletInfo>(); private readonly IBindable<TabletInfo> tablet = new Bindable<TabletInfo>();
@ -52,7 +57,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input
private FillFlowContainer mainSettings; private FillFlowContainer mainSettings;
private OsuSpriteText noTabletMessage; private FillFlowContainer noTabletMessage;
protected override LocalisableString Header => TabletSettingsStrings.Tablet; protected override LocalisableString Header => TabletSettingsStrings.Tablet;
@ -62,7 +67,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load(OsuColour colours)
{ {
Children = new Drawable[] Children = new Drawable[]
{ {
@ -71,14 +76,41 @@ namespace osu.Game.Overlays.Settings.Sections.Input
LabelText = CommonStrings.Enabled, LabelText = CommonStrings.Enabled,
Anchor = Anchor.TopCentre, Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre, Origin = Anchor.TopCentre,
Current = tabletHandler.Enabled Current = enabled,
}, },
noTabletMessage = new OsuSpriteText noTabletMessage = new FillFlowContainer
{ {
Text = TabletSettingsStrings.NoTabletDetected, RelativeSizeAxes = Axes.X,
Anchor = Anchor.TopCentre, AutoSizeAxes = Axes.Y,
Origin = Anchor.TopCentre, Direction = FillDirection.Vertical,
Padding = new MarginPadding { Horizontal = SettingsPanel.CONTENT_MARGINS } Padding = new MarginPadding { Horizontal = SettingsPanel.CONTENT_MARGINS },
Spacing = new Vector2(5f),
Children = new Drawable[]
{
new OsuSpriteText
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Text = TabletSettingsStrings.NoTabletDetected,
},
new SettingsNoticeText(colours)
{
TextAnchor = Anchor.TopCentre,
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
}.With(t =>
{
if (RuntimeInfo.OS == RuntimeInfo.Platform.Windows || RuntimeInfo.OS == RuntimeInfo.Platform.Linux)
{
t.NewLine();
t.AddText("If your tablet is not detected, please read ");
t.AddLink("this FAQ", LinkAction.External, RuntimeInfo.OS == RuntimeInfo.Platform.Windows
? @"https://github.com/OpenTabletDriver/OpenTabletDriver/wiki/Windows-FAQ"
: @"https://github.com/OpenTabletDriver/OpenTabletDriver/wiki/Linux-FAQ");
t.AddText(" for troubleshooting steps.");
}
}),
}
}, },
mainSettings = new FillFlowContainer mainSettings = new FillFlowContainer
{ {
@ -164,6 +196,9 @@ namespace osu.Game.Overlays.Settings.Sections.Input
{ {
base.LoadComplete(); base.LoadComplete();
enabled.BindTo(tabletHandler.Enabled);
enabled.BindValueChanged(_ => Scheduler.AddOnce(updateVisibility));
rotation.BindTo(tabletHandler.Rotation); rotation.BindTo(tabletHandler.Rotation);
areaOffset.BindTo(tabletHandler.AreaOffset); areaOffset.BindTo(tabletHandler.AreaOffset);
@ -209,7 +244,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input
tablet.BindTo(tabletHandler.Tablet); tablet.BindTo(tabletHandler.Tablet);
tablet.BindValueChanged(val => tablet.BindValueChanged(val =>
{ {
Scheduler.AddOnce(toggleVisibility); Scheduler.AddOnce(updateVisibility);
var tab = val.NewValue; var tab = val.NewValue;
@ -229,19 +264,18 @@ namespace osu.Game.Overlays.Settings.Sections.Input
}, true); }, true);
} }
private void toggleVisibility() private void updateVisibility()
{ {
bool tabletFound = tablet.Value != null; mainSettings.Hide();
if (!tabletFound)
{
mainSettings.Hide();
noTabletMessage.Show();
return;
}
mainSettings.Show();
noTabletMessage.Hide(); noTabletMessage.Hide();
if (!tabletHandler.Enabled.Value)
return;
if (tablet.Value != null)
mainSettings.Show();
else
noTabletMessage.Show();
} }
private void applyAspectRatio(BindableNumber<float> sizeChanged) private void applyAspectRatio(BindableNumber<float> sizeChanged)

View File

@ -11,6 +11,7 @@ using osu.Framework.Input.Handlers.Mouse;
using osu.Framework.Input.Handlers.Tablet; using osu.Framework.Input.Handlers.Tablet;
using osu.Framework.Localisation; using osu.Framework.Localisation;
using osu.Framework.Platform; using osu.Framework.Platform;
using osu.Game.Localisation;
using osu.Game.Overlays.Settings.Sections.Input; using osu.Game.Overlays.Settings.Sections.Input;
namespace osu.Game.Overlays.Settings.Sections namespace osu.Game.Overlays.Settings.Sections
@ -19,7 +20,7 @@ namespace osu.Game.Overlays.Settings.Sections
{ {
private readonly KeyBindingPanel keyConfig; private readonly KeyBindingPanel keyConfig;
public override string Header => "Input"; public override LocalisableString Header => InputSettingsStrings.InputSectionHeader;
[Resolved] [Resolved]
private GameHost host { get; set; } private GameHost host { get; set; }
@ -95,7 +96,7 @@ namespace osu.Game.Overlays.Settings.Sections
{ {
new SettingsCheckbox new SettingsCheckbox
{ {
LabelText = "Enabled", LabelText = CommonStrings.Enabled,
Current = handler.Enabled Current = handler.Enabled
}, },
}; };

View File

@ -14,6 +14,7 @@ using osu.Framework.Localisation;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
using osu.Framework.Screens; using osu.Framework.Screens;
using osu.Game.Graphics.Containers; using osu.Game.Graphics.Containers;
using osu.Game.Localisation;
namespace osu.Game.Overlays.Settings.Sections.Maintenance namespace osu.Game.Overlays.Settings.Sections.Maintenance
{ {
@ -104,7 +105,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance
Origin = Anchor.Centre, Origin = Anchor.Centre,
Width = 300, Width = 300,
Margin = new MarginPadding(10), Margin = new MarginPadding(10),
Text = "Select directory", Text = MaintenanceSettingsStrings.SelectDirectory,
Action = () => OnSelection(directorySelector.CurrentPath.Value) Action = () => OnSelection(directorySelector.CurrentPath.Value)
}, },
} }

View File

@ -11,6 +11,7 @@ using osu.Game.Beatmaps;
using osu.Game.Collections; using osu.Game.Collections;
using osu.Game.Database; using osu.Game.Database;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
using osu.Game.Localisation;
using osu.Game.Scoring; using osu.Game.Scoring;
using osu.Game.Skinning; using osu.Game.Skinning;
@ -37,7 +38,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance
{ {
Add(importBeatmapsButton = new SettingsButton Add(importBeatmapsButton = new SettingsButton
{ {
Text = "Import beatmaps from stable", Text = MaintenanceSettingsStrings.ImportBeatmapsFromStable,
Action = () => Action = () =>
{ {
importBeatmapsButton.Enabled.Value = false; importBeatmapsButton.Enabled.Value = false;
@ -48,7 +49,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance
Add(deleteBeatmapsButton = new DangerousSettingsButton Add(deleteBeatmapsButton = new DangerousSettingsButton
{ {
Text = "Delete ALL beatmaps", Text = MaintenanceSettingsStrings.DeleteAllBeatmaps,
Action = () => Action = () =>
{ {
dialogOverlay?.Push(new DeleteAllBeatmapsDialog(() => dialogOverlay?.Push(new DeleteAllBeatmapsDialog(() =>
@ -63,7 +64,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance
{ {
Add(importScoresButton = new SettingsButton Add(importScoresButton = new SettingsButton
{ {
Text = "Import scores from stable", Text = MaintenanceSettingsStrings.ImportScoresFromStable,
Action = () => Action = () =>
{ {
importScoresButton.Enabled.Value = false; importScoresButton.Enabled.Value = false;
@ -74,7 +75,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance
Add(deleteScoresButton = new DangerousSettingsButton Add(deleteScoresButton = new DangerousSettingsButton
{ {
Text = "Delete ALL scores", Text = MaintenanceSettingsStrings.DeleteAllScores,
Action = () => Action = () =>
{ {
dialogOverlay?.Push(new DeleteAllBeatmapsDialog(() => dialogOverlay?.Push(new DeleteAllBeatmapsDialog(() =>
@ -89,7 +90,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance
{ {
Add(importSkinsButton = new SettingsButton Add(importSkinsButton = new SettingsButton
{ {
Text = "Import skins from stable", Text = MaintenanceSettingsStrings.ImportSkinsFromStable,
Action = () => Action = () =>
{ {
importSkinsButton.Enabled.Value = false; importSkinsButton.Enabled.Value = false;
@ -100,7 +101,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance
Add(deleteSkinsButton = new DangerousSettingsButton Add(deleteSkinsButton = new DangerousSettingsButton
{ {
Text = "Delete ALL skins", Text = MaintenanceSettingsStrings.DeleteAllSkins,
Action = () => Action = () =>
{ {
dialogOverlay?.Push(new DeleteAllBeatmapsDialog(() => dialogOverlay?.Push(new DeleteAllBeatmapsDialog(() =>
@ -117,7 +118,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance
{ {
Add(importCollectionsButton = new SettingsButton Add(importCollectionsButton = new SettingsButton
{ {
Text = "Import collections from stable", Text = MaintenanceSettingsStrings.ImportCollectionsFromStable,
Action = () => Action = () =>
{ {
importCollectionsButton.Enabled.Value = false; importCollectionsButton.Enabled.Value = false;
@ -128,7 +129,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance
Add(new DangerousSettingsButton Add(new DangerousSettingsButton
{ {
Text = "Delete ALL collections", Text = MaintenanceSettingsStrings.DeleteAllCollections,
Action = () => Action = () =>
{ {
dialogOverlay?.Push(new DeleteAllBeatmapsDialog(collectionManager.DeleteAll)); dialogOverlay?.Push(new DeleteAllBeatmapsDialog(collectionManager.DeleteAll));
@ -140,7 +141,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance
{ {
restoreButton = new SettingsButton restoreButton = new SettingsButton
{ {
Text = "Restore all hidden difficulties", Text = MaintenanceSettingsStrings.RestoreAllHiddenDifficulties,
Action = () => Action = () =>
{ {
restoreButton.Enabled.Value = false; restoreButton.Enabled.Value = false;
@ -153,7 +154,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance
}, },
undeleteButton = new SettingsButton undeleteButton = new SettingsButton
{ {
Text = "Restore all recently deleted beatmaps", Text = MaintenanceSettingsStrings.RestoreAllRecentlyDeletedBeatmaps,
Action = () => Action = () =>
{ {
undeleteButton.Enabled.Value = false; undeleteButton.Enabled.Value = false;

View File

@ -3,6 +3,8 @@
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Game.Localisation;
using osu.Game.Overlays.Settings.Sections.Maintenance; using osu.Game.Overlays.Settings.Sections.Maintenance;
using osuTK; using osuTK;
@ -10,7 +12,7 @@ namespace osu.Game.Overlays.Settings.Sections
{ {
public class MaintenanceSection : SettingsSection public class MaintenanceSection : SettingsSection
{ {
public override string Header => "Maintenance"; public override LocalisableString Header => MaintenanceSettingsStrings.MaintenanceSectionHeader;
public override Drawable CreateIcon() => new SpriteIcon public override Drawable CreateIcon() => new SpriteIcon
{ {

View File

@ -5,12 +5,13 @@ using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Localisation; using osu.Framework.Localisation;
using osu.Game.Configuration; using osu.Game.Configuration;
using osu.Game.Localisation;
namespace osu.Game.Overlays.Settings.Sections.Online namespace osu.Game.Overlays.Settings.Sections.Online
{ {
public class AlertsAndPrivacySettings : SettingsSubsection public class AlertsAndPrivacySettings : SettingsSubsection
{ {
protected override LocalisableString Header => "Alerts and Privacy"; protected override LocalisableString Header => OnlineSettingsStrings.AlertsAndPrivacyHeader;
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuConfigManager config) private void load(OsuConfigManager config)
@ -19,12 +20,12 @@ namespace osu.Game.Overlays.Settings.Sections.Online
{ {
new SettingsCheckbox new SettingsCheckbox
{ {
LabelText = "Show a notification when someone mentions your name", LabelText = OnlineSettingsStrings.NotifyOnMentioned,
Current = config.GetBindable<bool>(OsuSetting.NotifyOnUsernameMentioned) Current = config.GetBindable<bool>(OsuSetting.NotifyOnUsernameMentioned)
}, },
new SettingsCheckbox new SettingsCheckbox
{ {
LabelText = "Show a notification when you receive a private message", LabelText = OnlineSettingsStrings.NotifyOnPrivateMessage,
Current = config.GetBindable<bool>(OsuSetting.NotifyOnPrivateMessage) Current = config.GetBindable<bool>(OsuSetting.NotifyOnPrivateMessage)
}, },
}; };

View File

@ -5,12 +5,13 @@ using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Localisation; using osu.Framework.Localisation;
using osu.Game.Configuration; using osu.Game.Configuration;
using osu.Game.Localisation;
namespace osu.Game.Overlays.Settings.Sections.Online namespace osu.Game.Overlays.Settings.Sections.Online
{ {
public class IntegrationSettings : SettingsSubsection public class IntegrationSettings : SettingsSubsection
{ {
protected override LocalisableString Header => "Integrations"; protected override LocalisableString Header => OnlineSettingsStrings.IntegrationsHeader;
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuConfigManager config) private void load(OsuConfigManager config)
@ -19,7 +20,7 @@ namespace osu.Game.Overlays.Settings.Sections.Online
{ {
new SettingsEnumDropdown<DiscordRichPresenceMode> new SettingsEnumDropdown<DiscordRichPresenceMode>
{ {
LabelText = "Discord Rich Presence", LabelText = OnlineSettingsStrings.DiscordRichPresence,
Current = config.GetBindable<DiscordRichPresenceMode>(OsuSetting.DiscordRichPresence) Current = config.GetBindable<DiscordRichPresenceMode>(OsuSetting.DiscordRichPresence)
} }
}; };

View File

@ -5,12 +5,13 @@ using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Localisation; using osu.Framework.Localisation;
using osu.Game.Configuration; using osu.Game.Configuration;
using osu.Game.Localisation;
namespace osu.Game.Overlays.Settings.Sections.Online namespace osu.Game.Overlays.Settings.Sections.Online
{ {
public class WebSettings : SettingsSubsection public class WebSettings : SettingsSubsection
{ {
protected override LocalisableString Header => "Web"; protected override LocalisableString Header => OnlineSettingsStrings.WebHeader;
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuConfigManager config) private void load(OsuConfigManager config)
@ -19,24 +20,24 @@ namespace osu.Game.Overlays.Settings.Sections.Online
{ {
new SettingsCheckbox new SettingsCheckbox
{ {
LabelText = "Warn about opening external links", LabelText = OnlineSettingsStrings.ExternalLinkWarning,
Current = config.GetBindable<bool>(OsuSetting.ExternalLinkWarning) Current = config.GetBindable<bool>(OsuSetting.ExternalLinkWarning)
}, },
new SettingsCheckbox new SettingsCheckbox
{ {
LabelText = "Prefer downloads without video", LabelText = OnlineSettingsStrings.PreferNoVideo,
Keywords = new[] { "no-video" }, Keywords = new[] { "no-video" },
Current = config.GetBindable<bool>(OsuSetting.PreferNoVideo) Current = config.GetBindable<bool>(OsuSetting.PreferNoVideo)
}, },
new SettingsCheckbox new SettingsCheckbox
{ {
LabelText = "Automatically download beatmaps when spectating", LabelText = OnlineSettingsStrings.AutomaticallyDownloadWhenSpectating,
Keywords = new[] { "spectator" }, Keywords = new[] { "spectator" },
Current = config.GetBindable<bool>(OsuSetting.AutomaticallyDownloadWhenSpectating), Current = config.GetBindable<bool>(OsuSetting.AutomaticallyDownloadWhenSpectating),
}, },
new SettingsCheckbox new SettingsCheckbox
{ {
LabelText = "Show explicit content in search results", LabelText = OnlineSettingsStrings.ShowExplicitContent,
Keywords = new[] { "nsfw", "18+", "offensive" }, Keywords = new[] { "nsfw", "18+", "offensive" },
Current = config.GetBindable<bool>(OsuSetting.ShowOnlineExplicitContent), Current = config.GetBindable<bool>(OsuSetting.ShowOnlineExplicitContent),
} }

View File

@ -3,13 +3,15 @@
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Game.Localisation;
using osu.Game.Overlays.Settings.Sections.Online; using osu.Game.Overlays.Settings.Sections.Online;
namespace osu.Game.Overlays.Settings.Sections namespace osu.Game.Overlays.Settings.Sections
{ {
public class OnlineSection : SettingsSection public class OnlineSection : SettingsSection
{ {
public override string Header => "Online"; public override LocalisableString Header => OnlineSettingsStrings.OnlineSectionHeader;
public override Drawable CreateIcon() => new SpriteIcon public override Drawable CreateIcon() => new SpriteIcon
{ {

View File

@ -13,6 +13,7 @@ using osu.Framework.Localisation;
using osu.Framework.Logging; using osu.Framework.Logging;
using osu.Game.Configuration; using osu.Game.Configuration;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
using osu.Game.Localisation;
using osu.Game.Skinning; using osu.Game.Skinning;
using osu.Game.Skinning.Editor; using osu.Game.Skinning.Editor;
using osuTK; using osuTK;
@ -23,7 +24,7 @@ namespace osu.Game.Overlays.Settings.Sections
{ {
private SkinSettingsDropdown skinDropdown; private SkinSettingsDropdown skinDropdown;
public override string Header => "Skin"; public override LocalisableString Header => SkinSettingsStrings.SkinSectionHeader;
public override Drawable CreateIcon() => new SpriteIcon public override Drawable CreateIcon() => new SpriteIcon
{ {
@ -69,34 +70,34 @@ namespace osu.Game.Overlays.Settings.Sections
skinDropdown = new SkinSettingsDropdown(), skinDropdown = new SkinSettingsDropdown(),
new SettingsButton new SettingsButton
{ {
Text = "Skin layout editor", Text = SkinSettingsStrings.SkinLayoutEditor,
Action = () => skinEditor?.Toggle(), Action = () => skinEditor?.Toggle(),
}, },
new ExportSkinButton(), new ExportSkinButton(),
new SettingsSlider<float, SizeSlider> new SettingsSlider<float, SizeSlider>
{ {
LabelText = "Gameplay cursor size", LabelText = SkinSettingsStrings.GameplayCursorSize,
Current = config.GetBindable<float>(OsuSetting.GameplayCursorSize), Current = config.GetBindable<float>(OsuSetting.GameplayCursorSize),
KeyboardStep = 0.01f KeyboardStep = 0.01f
}, },
new SettingsCheckbox new SettingsCheckbox
{ {
LabelText = "Adjust gameplay cursor size based on current beatmap", LabelText = SkinSettingsStrings.AutoCursorSize,
Current = config.GetBindable<bool>(OsuSetting.AutoCursorSize) Current = config.GetBindable<bool>(OsuSetting.AutoCursorSize)
}, },
new SettingsCheckbox new SettingsCheckbox
{ {
LabelText = "Beatmap skins", LabelText = SkinSettingsStrings.BeatmapSkins,
Current = config.GetBindable<bool>(OsuSetting.BeatmapSkins) Current = config.GetBindable<bool>(OsuSetting.BeatmapSkins)
}, },
new SettingsCheckbox new SettingsCheckbox
{ {
LabelText = "Beatmap colours", LabelText = SkinSettingsStrings.BeatmapColours,
Current = config.GetBindable<bool>(OsuSetting.BeatmapColours) Current = config.GetBindable<bool>(OsuSetting.BeatmapColours)
}, },
new SettingsCheckbox new SettingsCheckbox
{ {
LabelText = "Beatmap hitsounds", LabelText = SkinSettingsStrings.BeatmapHitsounds,
Current = config.GetBindable<bool>(OsuSetting.BeatmapHitsounds) Current = config.GetBindable<bool>(OsuSetting.BeatmapHitsounds)
}, },
}; };
@ -200,7 +201,7 @@ namespace osu.Game.Overlays.Settings.Sections
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load()
{ {
Text = "Export selected skin"; Text = SkinSettingsStrings.ExportSkinButton;
Action = export; Action = export;
currentSkin = skins.CurrentSkin.GetBoundCopy(); currentSkin = skins.CurrentSkin.GetBoundCopy();

View File

@ -6,12 +6,13 @@ using osu.Framework.Graphics;
using osu.Framework.Localisation; using osu.Framework.Localisation;
using osu.Game.Configuration; using osu.Game.Configuration;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
using osu.Game.Localisation;
namespace osu.Game.Overlays.Settings.Sections.UserInterface namespace osu.Game.Overlays.Settings.Sections.UserInterface
{ {
public class GeneralSettings : SettingsSubsection public class GeneralSettings : SettingsSubsection
{ {
protected override LocalisableString Header => "General"; protected override LocalisableString Header => UserInterfaceStrings.GeneralHeader;
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuConfigManager config) private void load(OsuConfigManager config)
@ -20,23 +21,23 @@ namespace osu.Game.Overlays.Settings.Sections.UserInterface
{ {
new SettingsCheckbox new SettingsCheckbox
{ {
LabelText = "Rotate cursor when dragging", LabelText = UserInterfaceStrings.CursorRotation,
Current = config.GetBindable<bool>(OsuSetting.CursorRotation) Current = config.GetBindable<bool>(OsuSetting.CursorRotation)
}, },
new SettingsSlider<float, SizeSlider> new SettingsSlider<float, SizeSlider>
{ {
LabelText = "Menu cursor size", LabelText = UserInterfaceStrings.MenuCursorSize,
Current = config.GetBindable<float>(OsuSetting.MenuCursorSize), Current = config.GetBindable<float>(OsuSetting.MenuCursorSize),
KeyboardStep = 0.01f KeyboardStep = 0.01f
}, },
new SettingsCheckbox new SettingsCheckbox
{ {
LabelText = "Parallax", LabelText = UserInterfaceStrings.Parallax,
Current = config.GetBindable<bool>(OsuSetting.MenuParallax) Current = config.GetBindable<bool>(OsuSetting.MenuParallax)
}, },
new SettingsSlider<float, TimeSlider> new SettingsSlider<float, TimeSlider>
{ {
LabelText = "Hold-to-confirm activation time", LabelText = UserInterfaceStrings.HoldToConfirmActivationTime,
Current = config.GetBindable<float>(OsuSetting.UIHoldActivationDelay), Current = config.GetBindable<float>(OsuSetting.UIHoldActivationDelay),
KeyboardStep = 50 KeyboardStep = 50
}, },

View File

@ -6,6 +6,7 @@ using osu.Framework.Bindables;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Localisation; using osu.Framework.Localisation;
using osu.Game.Configuration; using osu.Game.Configuration;
using osu.Game.Localisation;
using osu.Game.Online.API; using osu.Game.Online.API;
using osu.Game.Users; using osu.Game.Users;
@ -13,7 +14,7 @@ namespace osu.Game.Overlays.Settings.Sections.UserInterface
{ {
public class MainMenuSettings : SettingsSubsection public class MainMenuSettings : SettingsSubsection
{ {
protected override LocalisableString Header => "Main Menu"; protected override LocalisableString Header => UserInterfaceStrings.MainMenuHeader;
private IBindable<User> user; private IBindable<User> user;
@ -28,27 +29,27 @@ namespace osu.Game.Overlays.Settings.Sections.UserInterface
{ {
new SettingsCheckbox new SettingsCheckbox
{ {
LabelText = "Interface voices", LabelText = UserInterfaceStrings.InterfaceVoices,
Current = config.GetBindable<bool>(OsuSetting.MenuVoice) Current = config.GetBindable<bool>(OsuSetting.MenuVoice)
}, },
new SettingsCheckbox new SettingsCheckbox
{ {
LabelText = "osu! music theme", LabelText = UserInterfaceStrings.OsuMusicTheme,
Current = config.GetBindable<bool>(OsuSetting.MenuMusic) Current = config.GetBindable<bool>(OsuSetting.MenuMusic)
}, },
new SettingsEnumDropdown<IntroSequence> new SettingsEnumDropdown<IntroSequence>
{ {
LabelText = "Intro sequence", LabelText = UserInterfaceStrings.IntroSequence,
Current = config.GetBindable<IntroSequence>(OsuSetting.IntroSequence), Current = config.GetBindable<IntroSequence>(OsuSetting.IntroSequence),
}, },
backgroundSourceDropdown = new SettingsEnumDropdown<BackgroundSource> backgroundSourceDropdown = new SettingsEnumDropdown<BackgroundSource>
{ {
LabelText = "Background source", LabelText = UserInterfaceStrings.BackgroundSource,
Current = config.GetBindable<BackgroundSource>(OsuSetting.MenuBackgroundSource), Current = config.GetBindable<BackgroundSource>(OsuSetting.MenuBackgroundSource),
}, },
new SettingsEnumDropdown<SeasonalBackgroundMode> new SettingsEnumDropdown<SeasonalBackgroundMode>
{ {
LabelText = "Seasonal backgrounds", LabelText = UserInterfaceStrings.SeasonalBackgrounds,
Current = config.GetBindable<SeasonalBackgroundMode>(OsuSetting.SeasonalBackgroundMode), Current = config.GetBindable<SeasonalBackgroundMode>(OsuSetting.SeasonalBackgroundMode),
} }
}; };
@ -60,9 +61,7 @@ namespace osu.Game.Overlays.Settings.Sections.UserInterface
user.BindValueChanged(u => user.BindValueChanged(u =>
{ {
const string not_supporter_note = "Changes to this setting will only apply with an active osu!supporter tag."; backgroundSourceDropdown.WarningText = u.NewValue?.IsSupporter != true ? UserInterfaceStrings.NotSupporterNote : default;
backgroundSourceDropdown.WarningText = u.NewValue?.IsSupporter != true ? not_supporter_note : string.Empty;
}, true); }, true);
} }
} }

View File

@ -8,6 +8,7 @@ using osu.Framework.Graphics;
using osu.Framework.Localisation; using osu.Framework.Localisation;
using osu.Game.Configuration; using osu.Game.Configuration;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
using osu.Game.Localisation;
namespace osu.Game.Overlays.Settings.Sections.UserInterface namespace osu.Game.Overlays.Settings.Sections.UserInterface
{ {
@ -16,7 +17,7 @@ namespace osu.Game.Overlays.Settings.Sections.UserInterface
private Bindable<double> minStars; private Bindable<double> minStars;
private Bindable<double> maxStars; private Bindable<double> maxStars;
protected override LocalisableString Header => "Song Select"; protected override LocalisableString Header => UserInterfaceStrings.SongSelectHeader;
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuConfigManager config) private void load(OsuConfigManager config)
@ -31,31 +32,31 @@ namespace osu.Game.Overlays.Settings.Sections.UserInterface
{ {
new SettingsCheckbox new SettingsCheckbox
{ {
LabelText = "Right mouse drag to absolute scroll", LabelText = UserInterfaceStrings.RightMouseScroll,
Current = config.GetBindable<bool>(OsuSetting.SongSelectRightMouseScroll), Current = config.GetBindable<bool>(OsuSetting.SongSelectRightMouseScroll),
}, },
new SettingsCheckbox new SettingsCheckbox
{ {
LabelText = "Show converted beatmaps", LabelText = UserInterfaceStrings.ShowConvertedBeatmaps,
Current = config.GetBindable<bool>(OsuSetting.ShowConvertedBeatmaps), Current = config.GetBindable<bool>(OsuSetting.ShowConvertedBeatmaps),
}, },
new SettingsSlider<double, StarsSlider> new SettingsSlider<double, StarsSlider>
{ {
LabelText = "Display beatmaps from", LabelText = UserInterfaceStrings.StarsMinimum,
Current = config.GetBindable<double>(OsuSetting.DisplayStarsMinimum), Current = config.GetBindable<double>(OsuSetting.DisplayStarsMinimum),
KeyboardStep = 0.1f, KeyboardStep = 0.1f,
Keywords = new[] { "minimum", "maximum", "star", "difficulty" } Keywords = new[] { "minimum", "maximum", "star", "difficulty" }
}, },
new SettingsSlider<double, MaximumStarsSlider> new SettingsSlider<double, MaximumStarsSlider>
{ {
LabelText = "up to", LabelText = UserInterfaceStrings.StarsMaximum,
Current = config.GetBindable<double>(OsuSetting.DisplayStarsMaximum), Current = config.GetBindable<double>(OsuSetting.DisplayStarsMaximum),
KeyboardStep = 0.1f, KeyboardStep = 0.1f,
Keywords = new[] { "minimum", "maximum", "star", "difficulty" } Keywords = new[] { "minimum", "maximum", "star", "difficulty" }
}, },
new SettingsEnumDropdown<RandomSelectAlgorithm> new SettingsEnumDropdown<RandomSelectAlgorithm>
{ {
LabelText = "Random selection algorithm", LabelText = UserInterfaceStrings.RandomSelectionAlgorithm,
Current = config.GetBindable<RandomSelectAlgorithm>(OsuSetting.RandomSelectAlgorithm), Current = config.GetBindable<RandomSelectAlgorithm>(OsuSetting.RandomSelectAlgorithm),
} }
}; };
@ -63,7 +64,7 @@ namespace osu.Game.Overlays.Settings.Sections.UserInterface
private class MaximumStarsSlider : StarsSlider private class MaximumStarsSlider : StarsSlider
{ {
public override LocalisableString TooltipText => Current.IsDefault ? "no limit" : base.TooltipText; public override LocalisableString TooltipText => Current.IsDefault ? UserInterfaceStrings.NoLimit : base.TooltipText;
} }
private class StarsSlider : OsuSliderBar<double> private class StarsSlider : OsuSliderBar<double>

View File

@ -3,13 +3,15 @@
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Game.Localisation;
using osu.Game.Overlays.Settings.Sections.UserInterface; using osu.Game.Overlays.Settings.Sections.UserInterface;
namespace osu.Game.Overlays.Settings.Sections namespace osu.Game.Overlays.Settings.Sections
{ {
public class UserInterfaceSection : SettingsSection public class UserInterfaceSection : SettingsSection
{ {
public override string Header => "User Interface"; public override LocalisableString Header => UserInterfaceStrings.UserInterfaceSectionHeader;
public override Drawable CreateIcon() => new SpriteIcon public override Drawable CreateIcon() => new SpriteIcon
{ {

View File

@ -73,13 +73,7 @@ namespace osu.Game.Overlays.Settings
return; return;
// construct lazily for cases where the label is not needed (may be provided by the Control). // construct lazily for cases where the label is not needed (may be provided by the Control).
FlowContent.Add(warningText = new OsuTextFlowContainer FlowContent.Add(warningText = new SettingsNoticeText(colours) { Margin = new MarginPadding { Bottom = 5 } });
{
Colour = colours.Yellow,
Margin = new MarginPadding { Bottom = 5 },
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
});
} }
warningText.Alpha = hasValue ? 0 : 1; warningText.Alpha = hasValue ? 0 : 1;

View File

@ -0,0 +1,19 @@
// 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.Graphics;
using osu.Game.Graphics.Containers;
namespace osu.Game.Overlays.Settings
{
public class SettingsNoticeText : LinkFlowContainer
{
public SettingsNoticeText(OsuColour colours)
: base(s => s.Colour = colours.Yellow)
{
RelativeSizeAxes = Axes.X;
AutoSizeAxes = Axes.Y;
}
}
}

View File

@ -7,6 +7,7 @@ using osu.Framework.Allocation;
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.Localisation;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Sprites;
using osuTK.Graphics; using osuTK.Graphics;
@ -19,10 +20,10 @@ namespace osu.Game.Overlays.Settings
protected override Container<Drawable> Content => FlowContent; protected override Container<Drawable> Content => FlowContent;
public abstract Drawable CreateIcon(); public abstract Drawable CreateIcon();
public abstract string Header { get; } public abstract LocalisableString Header { get; }
public IEnumerable<IFilterable> FilterableChildren => Children.OfType<IFilterable>(); public IEnumerable<IFilterable> FilterableChildren => Children.OfType<IFilterable>();
public virtual IEnumerable<string> FilterTerms => new[] { Header }; public virtual IEnumerable<string> FilterTerms => new[] { Header.ToString() };
private const int header_size = 26; private const int header_size = 26;
private const int margin = 20; private const int margin = 20;

View File

@ -24,6 +24,11 @@ namespace osu.Game.Overlays.Settings
protected abstract LocalisableString Header { get; } protected abstract LocalisableString Header { get; }
public IEnumerable<IFilterable> FilterableChildren => Children.OfType<IFilterable>(); public IEnumerable<IFilterable> FilterableChildren => Children.OfType<IFilterable>();
// FilterTerms should contains both original string and localised string for user to search.
// Since LocalisableString is unable to get original string at this time (2021-08-14),
// only call .ToString() to use localised one.
// TODO: Update here when FilterTerms accept LocalisableString.
public virtual IEnumerable<string> FilterTerms => new[] { Header.ToString() }; public virtual IEnumerable<string> FilterTerms => new[] { Header.ToString() };
public bool MatchingFilter public bool MatchingFilter

View File

@ -91,7 +91,13 @@ namespace osu.Game.Rulesets.Mods
{ {
// This is required as SettingsItem relies heavily on this bindable for internal use. // This is required as SettingsItem relies heavily on this bindable for internal use.
// The actual update flow is done via the bindable provided in the constructor. // The actual update flow is done via the bindable provided in the constructor.
public Bindable<float?> Current { get; set; } = new Bindable<float?>(); private readonly BindableWithCurrent<float?> current = new BindableWithCurrent<float?>();
public Bindable<float?> Current
{
get => current.Current;
set => current.Current = value;
}
public SliderControl(BindableNumber<float> currentNumber) public SliderControl(BindableNumber<float> currentNumber)
{ {

View File

@ -2,6 +2,8 @@
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using System; using System;
using osu.Framework.Bindables;
using osu.Game.Configuration;
using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
@ -11,9 +13,12 @@ namespace osu.Game.Rulesets.Mods
{ {
public override Type[] IncompatibleMods => new[] { typeof(ModNoFail), typeof(ModRelax), typeof(ModAutoplay) }; public override Type[] IncompatibleMods => new[] { typeof(ModNoFail), typeof(ModRelax), typeof(ModAutoplay) };
[SettingSource("Restart on fail", "Automatically restarts when failed.")]
public BindableBool Restart { get; } = new BindableBool();
public virtual bool PerformFail() => true; public virtual bool PerformFail() => true;
public virtual bool RestartOnFail => true; public virtual bool RestartOnFail => Restart.Value;
public void ApplyToHealthProcessor(HealthProcessor healthProcessor) public void ApplyToHealthProcessor(HealthProcessor healthProcessor)
{ {

View File

@ -21,6 +21,11 @@ namespace osu.Game.Rulesets.Mods
public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(ModSuddenDeath)).ToArray(); public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(ModSuddenDeath)).ToArray();
protected ModPerfect()
{
Restart.Value = Restart.Default = true;
}
protected override bool FailCondition(HealthProcessor healthProcessor, JudgementResult result) protected override bool FailCondition(HealthProcessor healthProcessor, JudgementResult result)
=> result.Type.AffectsAccuracy() => result.Type.AffectsAccuracy()
&& result.Type != result.Judgement.MaxResult; && result.Type != result.Judgement.MaxResult;

View File

@ -15,7 +15,6 @@ using osu.Game.Extensions;
using osu.Game.Rulesets; using osu.Game.Rulesets;
using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Edit;
using osu.Game.Screens.Edit.Compose.Components.Timeline; using osu.Game.Screens.Edit.Compose.Components.Timeline;
using osu.Game.Skinning;
namespace osu.Game.Screens.Edit.Compose namespace osu.Game.Screens.Edit.Compose
{ {
@ -73,7 +72,7 @@ namespace osu.Game.Screens.Edit.Compose
{ {
Debug.Assert(ruleset != null); Debug.Assert(ruleset != null);
return new RulesetSkinProvidingContainer(ruleset, EditorBeatmap.PlayableBeatmap, beatmap.Value.Skin).WithChild(content); return new EditorSkinProvidingContainer(EditorBeatmap).WithChild(content);
} }
#region Input Handling #region Input Handling

View File

@ -153,7 +153,7 @@ namespace osu.Game.Screens.Edit
// todo: remove caching of this and consume via editorBeatmap? // todo: remove caching of this and consume via editorBeatmap?
dependencies.Cache(beatDivisor); dependencies.Cache(beatDivisor);
AddInternal(editorBeatmap = new EditorBeatmap(playableBeatmap, loadableBeatmap.Skin)); AddInternal(editorBeatmap = new EditorBeatmap(playableBeatmap, loadableBeatmap.GetSkin()));
dependencies.CacheAs(editorBeatmap); dependencies.CacheAs(editorBeatmap);
changeHandler = new EditorChangeHandler(editorBeatmap); changeHandler = new EditorChangeHandler(editorBeatmap);
dependencies.CacheAs<IEditorChangeHandler>(changeHandler); dependencies.CacheAs<IEditorChangeHandler>(changeHandler);

View File

@ -54,7 +54,7 @@ namespace osu.Game.Screens.Edit
private readonly Bindable<bool> hasTiming = new Bindable<bool>(); private readonly Bindable<bool> hasTiming = new Bindable<bool>();
[CanBeNull] [CanBeNull]
public readonly ISkin BeatmapSkin; public readonly EditorBeatmapSkin BeatmapSkin;
[Resolved] [Resolved]
private BindableBeatDivisor beatDivisor { get; set; } private BindableBeatDivisor beatDivisor { get; set; }
@ -69,7 +69,8 @@ namespace osu.Game.Screens.Edit
public EditorBeatmap(IBeatmap playableBeatmap, ISkin beatmapSkin = null) public EditorBeatmap(IBeatmap playableBeatmap, ISkin beatmapSkin = null)
{ {
PlayableBeatmap = playableBeatmap; PlayableBeatmap = playableBeatmap;
BeatmapSkin = beatmapSkin; if (beatmapSkin is Skin skin)
BeatmapSkin = new EditorBeatmapSkin(skin);
beatmapProcessor = playableBeatmap.BeatmapInfo.Ruleset?.CreateInstance().CreateBeatmapProcessor(PlayableBeatmap); beatmapProcessor = playableBeatmap.BeatmapInfo.Ruleset?.CreateInstance().CreateBeatmapProcessor(PlayableBeatmap);

View File

@ -0,0 +1,59 @@
// 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 osu.Framework.Audio.Sample;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.OpenGL.Textures;
using osu.Framework.Graphics.Textures;
using osu.Game.Audio;
using osu.Game.Skinning;
using osuTK.Graphics;
namespace osu.Game.Screens.Edit
{
/// <summary>
/// A beatmap skin which is being edited.
/// </summary>
public class EditorBeatmapSkin : ISkin
{
public event Action BeatmapSkinChanged;
/// <summary>
/// The combo colours of this skin.
/// If empty, the default combo colours will be used.
/// </summary>
public readonly BindableList<Colour4> ComboColours;
private readonly Skin skin;
public EditorBeatmapSkin(Skin skin)
{
this.skin = skin;
ComboColours = new BindableList<Colour4>();
if (skin.Configuration.ComboColours != null)
ComboColours.AddRange(skin.Configuration.ComboColours.Select(c => (Colour4)c));
ComboColours.BindCollectionChanged((_, __) => updateColours());
}
private void invokeSkinChanged() => BeatmapSkinChanged?.Invoke();
private void updateColours()
{
skin.Configuration.CustomComboColours = ComboColours.Select(c => (Color4)c).ToList();
invokeSkinChanged();
}
#region Delegated ISkin implementation
public Drawable GetDrawableComponent(ISkinComponent component) => skin.GetDrawableComponent(component);
public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => skin.GetTexture(componentName, wrapModeS, wrapModeT);
public ISample GetSample(ISampleInfo sampleInfo) => skin.GetSample(sampleInfo);
public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) => skin.GetConfig<TLookup, TValue>(lookup);
#endregion
}
}

View File

@ -0,0 +1,40 @@
// 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.Game.Skinning;
#nullable enable
namespace osu.Game.Screens.Edit
{
/// <summary>
/// A <see cref="SkinProvidingContainer"/> that fires <see cref="ISkinSource.SourceChanged"/> when users have made a change to the beatmap skin
/// of the map being edited.
/// </summary>
public class EditorSkinProvidingContainer : RulesetSkinProvidingContainer
{
private readonly EditorBeatmapSkin? beatmapSkin;
public EditorSkinProvidingContainer(EditorBeatmap editorBeatmap)
: base(editorBeatmap.PlayableBeatmap.BeatmapInfo.Ruleset.CreateInstance(), editorBeatmap, editorBeatmap.BeatmapSkin)
{
beatmapSkin = editorBeatmap.BeatmapSkin;
}
protected override void LoadComplete()
{
base.LoadComplete();
if (beatmapSkin != null)
beatmapSkin.BeatmapSkinChanged += TriggerSourceChanged;
}
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
if (beatmapSkin != null)
beatmapSkin.BeatmapSkinChanged -= TriggerSourceChanged;
}
}
}

View File

@ -118,7 +118,7 @@ namespace osu.Game.Screens.Edit
protected override Track GetBeatmapTrack() => throw new NotImplementedException(); protected override Track GetBeatmapTrack() => throw new NotImplementedException();
protected override ISkin GetSkin() => throw new NotImplementedException(); protected internal override ISkin GetSkin() => throw new NotImplementedException();
public override Stream GetStream(string storagePath) => throw new NotImplementedException(); public override Stream GetStream(string storagePath) => throw new NotImplementedException();
} }

View File

@ -1,14 +1,10 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // 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. // See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Localisation; using osu.Framework.Localisation;
using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Graphics.UserInterfaceV2;
using osu.Game.Skinning;
using osuTK.Graphics;
namespace osu.Game.Screens.Edit.Setup namespace osu.Game.Screens.Edit.Setup
{ {
@ -31,9 +27,8 @@ namespace osu.Game.Screens.Edit.Setup
} }
}; };
var colours = Beatmap.BeatmapSkin?.GetConfig<GlobalSkinColours, IReadOnlyList<Color4>>(GlobalSkinColours.ComboColours)?.Value; if (Beatmap.BeatmapSkin != null)
if (colours != null) comboColours.Colours.BindTo(Beatmap.BeatmapSkin.ComboColours);
comboColours.Colours.AddRange(colours.Select(c => (Colour4)c));
} }
} }
} }

View File

@ -10,12 +10,12 @@ namespace osu.Game.Screens.OnlinePlay.Components
{ {
public class OnlinePlayBackgroundSprite : OnlinePlayComposite public class OnlinePlayBackgroundSprite : OnlinePlayComposite
{ {
private readonly BeatmapSetCoverType beatmapSetCoverType; protected readonly BeatmapSetCoverType BeatmapSetCoverType;
private UpdateableBeatmapBackgroundSprite sprite; private UpdateableBeatmapBackgroundSprite sprite;
public OnlinePlayBackgroundSprite(BeatmapSetCoverType beatmapSetCoverType = BeatmapSetCoverType.Cover) public OnlinePlayBackgroundSprite(BeatmapSetCoverType beatmapSetCoverType = BeatmapSetCoverType.Cover)
{ {
this.beatmapSetCoverType = beatmapSetCoverType; BeatmapSetCoverType = beatmapSetCoverType;
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
@ -33,6 +33,6 @@ namespace osu.Game.Screens.OnlinePlay.Components
sprite.Beatmap.Value = Playlist.FirstOrDefault()?.Beatmap.Value; sprite.Beatmap.Value = Playlist.FirstOrDefault()?.Beatmap.Value;
} }
protected virtual UpdateableBeatmapBackgroundSprite CreateBackgroundSprite() => new UpdateableBeatmapBackgroundSprite(beatmapSetCoverType) { RelativeSizeAxes = Axes.Both }; protected virtual UpdateableBeatmapBackgroundSprite CreateBackgroundSprite() => new UpdateableBeatmapBackgroundSprite(BeatmapSetCoverType) { RelativeSizeAxes = Axes.Both };
} }
} }

View File

@ -158,21 +158,14 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
Children = new Drawable[] Children = new Drawable[]
{ {
// This resolves internal 1px gaps due to applying the (parenting) corner radius and masking across multiple filling background sprites. // This resolves internal 1px gaps due to applying the (parenting) corner radius and masking across multiple filling background sprites.
new BufferedContainer new Box
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Children = new Drawable[] Colour = colours.Background5,
{ },
new Box new OnlinePlayBackgroundSprite
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both
Colour = colours.Background5,
},
new OnlinePlayBackgroundSprite
{
RelativeSizeAxes = Axes.Both
},
}
}, },
new Container new Container
{ {
@ -187,37 +180,29 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
CornerRadius = corner_radius, CornerRadius = corner_radius,
Children = new Drawable[] Children = new Drawable[]
{ {
// This resolves internal 1px gaps due to applying the (parenting) corner radius and masking across multiple filling background sprites. new GridContainer
new BufferedContainer
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Children = new Drawable[] ColumnDimensions = new[]
{ {
new GridContainer new Dimension(GridSizeMode.Relative, 0.2f)
{
RelativeSizeAxes = Axes.Both,
ColumnDimensions = new[]
{
new Dimension(GridSizeMode.Relative, 0.2f)
},
Content = new[]
{
new Drawable[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = colours.Background5,
},
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = ColourInfo.GradientHorizontal(colours.Background5, colours.Background5.Opacity(0.3f))
},
}
}
},
}, },
Content = new[]
{
new Drawable[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = colours.Background5,
},
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = ColourInfo.GradientHorizontal(colours.Background5, colours.Background5.Opacity(0.3f))
},
}
}
}, },
new Container new Container
{ {

View File

@ -2,7 +2,6 @@
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.Linq; using System.Linq;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Extensions.Color4Extensions;
@ -83,7 +82,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants
Colour = Color4Extensions.FromHex("#F7E65D"), Colour = Color4Extensions.FromHex("#F7E65D"),
Alpha = 0 Alpha = 0
}, },
new TeamDisplay(user), new TeamDisplay(User),
new Container new Container
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
@ -168,12 +167,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants
Origin = Anchor.Centre, Origin = Anchor.Centre,
Alpha = 0, Alpha = 0,
Margin = new MarginPadding(4), Margin = new MarginPadding(4),
Action = () => Action = () => Client.KickUser(User.UserID),
{
Debug.Assert(user != null);
Client.KickUser(user.Id);
}
}, },
}, },
} }

View File

@ -11,7 +11,6 @@ using osu.Game.Graphics;
using osu.Game.Graphics.Containers; using osu.Game.Graphics.Containers;
using osu.Game.Online.Multiplayer; using osu.Game.Online.Multiplayer;
using osu.Game.Online.Multiplayer.MatchTypes.TeamVersus; using osu.Game.Online.Multiplayer.MatchTypes.TeamVersus;
using osu.Game.Users;
using osuTK; using osuTK;
using osuTK.Graphics; using osuTK.Graphics;
@ -19,16 +18,14 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants
{ {
internal class TeamDisplay : MultiplayerRoomComposite internal class TeamDisplay : MultiplayerRoomComposite
{ {
private readonly User user; private readonly MultiplayerRoomUser user;
private Drawable box; private Drawable box;
[Resolved] [Resolved]
private OsuColour colours { get; set; } private OsuColour colours { get; set; }
[Resolved] public TeamDisplay(MultiplayerRoomUser user)
private MultiplayerClient client { get; set; }
public TeamDisplay(User user)
{ {
this.user = user; this.user = user;
@ -61,7 +58,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants
} }
}; };
if (user.Id == client.LocalUser?.UserID) if (Client.LocalUser?.Equals(user) == true)
{ {
InternalChild = new OsuClickableContainer InternalChild = new OsuClickableContainer
{ {
@ -79,9 +76,9 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants
private void changeTeam() private void changeTeam()
{ {
client.SendMatchRequest(new ChangeTeamRequest Client.SendMatchRequest(new ChangeTeamRequest
{ {
TeamID = ((client.LocalUser?.MatchState as TeamVersusUserState)?.TeamID + 1) % 2 ?? 0, TeamID = ((Client.LocalUser?.MatchState as TeamVersusUserState)?.TeamID + 1) % 2 ?? 0,
}); });
} }
@ -93,7 +90,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants
// we don't have a way of knowing when an individual user's state has updated, so just handle on RoomUpdated for now. // we don't have a way of knowing when an individual user's state has updated, so just handle on RoomUpdated for now.
var userRoomState = Room?.Users.FirstOrDefault(u => u.UserID == user.Id)?.MatchState; var userRoomState = Room?.Users.FirstOrDefault(u => u.Equals(user))?.MatchState;
const double duration = 400; const double duration = 400;

View File

@ -11,6 +11,7 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Logging; using osu.Framework.Logging;
using osu.Framework.Screens; using osu.Framework.Screens;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Drawables; using osu.Game.Beatmaps.Drawables;
using osu.Game.Graphics.Containers; using osu.Game.Graphics.Containers;
using osu.Game.Online.API; using osu.Game.Online.API;
@ -98,14 +99,9 @@ namespace osu.Game.Screens.OnlinePlay
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Children = new Drawable[] Children = new Drawable[]
{ {
new BufferedContainer new BeatmapBackgroundSprite
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both
BlurSigma = new Vector2(10),
Child = new BeatmapBackgroundSprite
{
RelativeSizeAxes = Axes.Both
}
}, },
new Box new Box
{ {
@ -286,11 +282,46 @@ namespace osu.Game.Screens.OnlinePlay
private class BeatmapBackgroundSprite : OnlinePlayBackgroundSprite private class BeatmapBackgroundSprite : OnlinePlayBackgroundSprite
{ {
protected override UpdateableBeatmapBackgroundSprite CreateBackgroundSprite() => new BackgroundSprite { RelativeSizeAxes = Axes.Both }; protected override UpdateableBeatmapBackgroundSprite CreateBackgroundSprite() => new BlurredBackgroundSprite(BeatmapSetCoverType) { RelativeSizeAxes = Axes.Both };
private class BackgroundSprite : UpdateableBeatmapBackgroundSprite public class BlurredBackgroundSprite : UpdateableBeatmapBackgroundSprite
{ {
public BlurredBackgroundSprite(BeatmapSetCoverType type)
: base(type)
{
}
protected override double LoadDelay => 200; protected override double LoadDelay => 200;
protected override Drawable CreateDrawable(BeatmapInfo model) =>
new BufferedLoader(base.CreateDrawable(model));
}
// This class is an unfortunate requirement due to `LongRunningLoad` requiring direct async loading.
// It means that if the web request fetching the beatmap background takes too long, it will suddenly appear.
internal class BufferedLoader : BufferedContainer
{
private readonly Drawable drawable;
public BufferedLoader(Drawable drawable)
{
this.drawable = drawable;
RelativeSizeAxes = Axes.Both;
BlurSigma = new Vector2(10);
FrameBufferScale = new Vector2(0.5f);
CacheDrawnFrameBuffer = true;
}
[BackgroundDependencyLoader]
private void load()
{
LoadComponentAsync(drawable, d =>
{
Add(d);
ForceRedraw();
});
}
} }
} }

View File

@ -57,8 +57,6 @@ namespace osu.Game.Screens.Play
private Bindable<HUDVisibilityMode> configVisibilityMode; private Bindable<HUDVisibilityMode> configVisibilityMode;
private readonly Container visibilityContainer;
private readonly BindableBool replayLoaded = new BindableBool(); private readonly BindableBool replayLoaded = new BindableBool();
private static bool hasShownNotificationOnce; private static bool hasShownNotificationOnce;
@ -72,7 +70,7 @@ namespace osu.Game.Screens.Play
private readonly SkinnableTargetContainer mainComponents; private readonly SkinnableTargetContainer mainComponents;
private IEnumerable<Drawable> hideTargets => new Drawable[] { visibilityContainer, KeyCounter, topRightElements }; private IEnumerable<Drawable> hideTargets => new Drawable[] { mainComponents, KeyCounter, topRightElements };
public HUDOverlay(DrawableRuleset drawableRuleset, IReadOnlyList<Mod> mods) public HUDOverlay(DrawableRuleset drawableRuleset, IReadOnlyList<Mod> mods)
{ {
@ -84,13 +82,9 @@ namespace osu.Game.Screens.Play
Children = new Drawable[] Children = new Drawable[]
{ {
CreateFailingLayer(), CreateFailingLayer(),
visibilityContainer = new Container mainComponents = new SkinnableTargetContainer(SkinnableTarget.MainHUDComponents)
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Child = mainComponents = new SkinnableTargetContainer(SkinnableTarget.MainHUDComponents)
{
RelativeSizeAxes = Axes.Both,
},
}, },
topRightElements = new FillFlowContainer topRightElements = new FillFlowContainer
{ {

View File

@ -125,7 +125,7 @@ namespace osu.Game.Screens.Play
Objects = drawableRuleset.Objects; Objects = drawableRuleset.Objects;
} }
config.BindWith(OsuSetting.ShowDifficultyGraph, ShowGraph); config.BindWith(OsuSetting.ShowProgressGraph, ShowGraph);
graph.FillColour = bar.FillColour = colours.BlueLighter; graph.FillColour = bar.FillColour = colours.BlueLighter;
} }

View File

@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // 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. // See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic;
using JetBrains.Annotations; using JetBrains.Annotations;
using osu.Framework.IO.Stores; using osu.Framework.IO.Stores;
using osu.Game.Extensions; using osu.Game.Extensions;
@ -21,12 +22,13 @@ namespace osu.Game.Skinning
: base(skin, new NamespacedResourceStore<byte[]>(resources.Resources, "Skins/Legacy"), resources, string.Empty) : base(skin, new NamespacedResourceStore<byte[]>(resources.Resources, "Skins/Legacy"), resources, string.Empty)
{ {
Configuration.CustomColours["SliderBall"] = new Color4(2, 170, 255, 255); Configuration.CustomColours["SliderBall"] = new Color4(2, 170, 255, 255);
Configuration.AddComboColours( Configuration.CustomComboColours = new List<Color4>
{
new Color4(255, 192, 0, 255), new Color4(255, 192, 0, 255),
new Color4(0, 202, 0, 255), new Color4(0, 202, 0, 255),
new Color4(18, 124, 255, 255), new Color4(18, 124, 255, 255),
new Color4(242, 24, 57, 255) new Color4(242, 24, 57, 255)
); };
Configuration.LegacyVersion = 2.7m; Configuration.LegacyVersion = 2.7m;
} }

View File

@ -27,14 +27,14 @@ namespace osu.Game.Skinning
new Color4(242, 24, 57, 255), new Color4(242, 24, 57, 255),
}; };
private readonly List<Color4> comboColours = new List<Color4>(); public List<Color4> CustomComboColours { get; set; } = new List<Color4>();
public IReadOnlyList<Color4> ComboColours public IReadOnlyList<Color4> ComboColours
{ {
get get
{ {
if (comboColours.Count > 0) if (CustomComboColours.Count > 0)
return comboColours; return CustomComboColours;
if (AllowDefaultComboColoursFallback) if (AllowDefaultComboColoursFallback)
return DefaultComboColours; return DefaultComboColours;
@ -43,7 +43,7 @@ namespace osu.Game.Skinning
} }
} }
public void AddComboColours(params Color4[] colours) => comboColours.AddRange(colours); void IHasComboColours.AddComboColours(params Color4[] colours) => CustomComboColours.AddRange(colours);
public Dictionary<string, Color4> CustomColours { get; } = new Dictionary<string, Color4>(); public Dictionary<string, Color4> CustomColours { get; } = new Dictionary<string, Color4>();

View File

@ -217,7 +217,7 @@ namespace osu.Game.Tests.Beatmaps
protected override Track GetBeatmapTrack() => throw new NotImplementedException(); protected override Track GetBeatmapTrack() => throw new NotImplementedException();
protected override ISkin GetSkin() => throw new NotImplementedException(); protected internal override ISkin GetSkin() => throw new NotImplementedException();
public override Stream GetStream(string storagePath) => throw new NotImplementedException(); public override Stream GetStream(string storagePath) => throw new NotImplementedException();

View File

@ -211,7 +211,7 @@ namespace osu.Game.Tests.Beatmaps
this.resources = resources; this.resources = resources;
} }
protected override ISkin GetSkin() => new LegacyBeatmapSkin(skinBeatmapInfo, resourceStore, resources); protected internal override ISkin GetSkin() => new LegacyBeatmapSkin(skinBeatmapInfo, resourceStore, resources);
} }
} }
} }

View File

@ -92,7 +92,7 @@ namespace osu.Game.Tests.Beatmaps
HasColours = hasColours; HasColours = hasColours;
} }
protected override ISkin GetSkin() => new TestBeatmapSkin(BeatmapInfo, HasColours); protected internal override ISkin GetSkin() => new TestBeatmapSkin(BeatmapInfo, HasColours);
} }
protected class TestBeatmapSkin : LegacyBeatmapSkin protected class TestBeatmapSkin : LegacyBeatmapSkin
@ -116,7 +116,7 @@ namespace osu.Game.Tests.Beatmaps
{ {
if (hasColours) if (hasColours)
{ {
Configuration.AddComboColours(Colours); Configuration.CustomComboColours = Colours.ToList();
Configuration.CustomColours.Add("HyperDash", HYPER_DASH_COLOUR); Configuration.CustomColours.Add("HyperDash", HYPER_DASH_COLOUR);
Configuration.CustomColours.Add("HyperDashAfterImage", HYPER_DASH_AFTER_IMAGE_COLOUR); Configuration.CustomColours.Add("HyperDashAfterImage", HYPER_DASH_AFTER_IMAGE_COLOUR);
Configuration.CustomColours.Add("HyperDashFruit", HYPER_DASH_FRUIT_COLOUR); Configuration.CustomColours.Add("HyperDashFruit", HYPER_DASH_FRUIT_COLOUR);
@ -145,7 +145,7 @@ namespace osu.Game.Tests.Beatmaps
{ {
if (hasCustomColours) if (hasCustomColours)
{ {
Configuration.AddComboColours(Colours); Configuration.CustomComboColours = Colours.ToList();
Configuration.CustomColours.Add("HyperDash", HYPER_DASH_COLOUR); Configuration.CustomColours.Add("HyperDash", HYPER_DASH_COLOUR);
Configuration.CustomColours.Add("HyperDashAfterImage", HYPER_DASH_AFTER_IMAGE_COLOUR); Configuration.CustomColours.Add("HyperDashAfterImage", HYPER_DASH_AFTER_IMAGE_COLOUR);
Configuration.CustomColours.Add("HyperDashFruit", HYPER_DASH_FRUIT_COLOUR); Configuration.CustomColours.Add("HyperDashFruit", HYPER_DASH_FRUIT_COLOUR);

View File

@ -37,7 +37,7 @@ namespace osu.Game.Tests.Beatmaps
protected override Storyboard GetStoryboard() => storyboard ?? base.GetStoryboard(); protected override Storyboard GetStoryboard() => storyboard ?? base.GetStoryboard();
protected override ISkin GetSkin() => null; protected internal override ISkin GetSkin() => null;
public override Stream GetStream(string storagePath) => null; public override Stream GetStream(string storagePath) => null;

View File

@ -61,7 +61,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
return roomUser; return roomUser;
} }
public void AddNullUser(int userId) => ((IMultiplayerClient)this).UserJoined(new MultiplayerRoomUser(userId)); public void AddNullUser() => ((IMultiplayerClient)this).UserJoined(new MultiplayerRoomUser(TestUserLookupCache.NULL_USER_ID));
public void RemoveUser(User user) public void RemoveUser(User user)
{ {

View File

@ -10,10 +10,22 @@ namespace osu.Game.Tests.Visual
{ {
public class TestUserLookupCache : UserLookupCache public class TestUserLookupCache : UserLookupCache
{ {
protected override Task<User> ComputeValueAsync(int lookup, CancellationToken token = default) => Task.FromResult(new User /// <summary>
/// A special user ID which <see cref="ComputeValueAsync"/> would return a <see langword="null"/> <see cref="User"/> for.
/// As a simulation to what a regular <see cref="UserLookupCache"/> would return in the case of failing to fetch the user.
/// </summary>
public const int NULL_USER_ID = -1;
protected override Task<User> ComputeValueAsync(int lookup, CancellationToken token = default)
{ {
Id = lookup, if (lookup == NULL_USER_ID)
Username = $"User {lookup}" return Task.FromResult((User)null);
});
return Task.FromResult(new User
{
Id = lookup,
Username = $"User {lookup}"
});
}
} }
} }

View File

@ -304,6 +304,7 @@
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=AABB/@EntryIndexedValue">AABB</s:String> <s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=AABB/@EntryIndexedValue">AABB</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=API/@EntryIndexedValue">API</s:String> <s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=API/@EntryIndexedValue">API</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=BPM/@EntryIndexedValue">BPM</s:String> <s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=BPM/@EntryIndexedValue">BPM</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=FPS/@EntryIndexedValue">FPS</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=GC/@EntryIndexedValue">GC</s:String> <s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=GC/@EntryIndexedValue">GC</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=GL/@EntryIndexedValue">GL</s:String> <s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=GL/@EntryIndexedValue">GL</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=GLSL/@EntryIndexedValue">GLSL</s:String> <s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=GLSL/@EntryIndexedValue">GLSL</s:String>