diff --git a/Directory.Build.props b/Directory.Build.props
index 3ab3dc3d13..709545bf1d 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -34,7 +34,7 @@
https://github.com/ppy/osu
Automated release.
ppy Pty Ltd
- Copyright (c) 2021 ppy Pty Ltd
+ Copyright (c) 2022 ppy Pty Ltd
osu game
diff --git a/LICENCE b/LICENCE
index b5962ad3b2..d3e7537cef 100644
--- a/LICENCE
+++ b/LICENCE
@@ -1,4 +1,4 @@
-Copyright (c) 2021 ppy Pty Ltd .
+Copyright (c) 2022 ppy Pty Ltd .
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/Templates/osu.Game.Templates.csproj b/Templates/osu.Game.Templates.csproj
index 4624d3d771..b8c3ad373a 100644
--- a/Templates/osu.Game.Templates.csproj
+++ b/Templates/osu.Game.Templates.csproj
@@ -8,7 +8,7 @@
https://github.com/ppy/osu/blob/master/Templates
https://github.com/ppy/osu
Automated release.
- Copyright (c) 2021 ppy Pty Ltd
+ Copyright (c) 2022 ppy Pty Ltd
Templates to use when creating a ruleset for consumption in osu!.
dotnet-new;templates;osu
netstandard2.1
diff --git a/osu.Desktop/osu.nuspec b/osu.Desktop/osu.nuspec
index 1757fd7c73..dc1ec17e2c 100644
--- a/osu.Desktop/osu.nuspec
+++ b/osu.Desktop/osu.nuspec
@@ -11,7 +11,7 @@
false
A free-to-win rhythm game. Rhythm is just a *click* away!
testing
- Copyright (c) 2021 ppy Pty Ltd
+ Copyright (c) 2022 ppy Pty Ltd
en-AU
diff --git a/osu.Game.Tests/NonVisual/Skinning/LegacySkinTextureFallbackTest.cs b/osu.Game.Tests/NonVisual/Skinning/LegacySkinTextureFallbackTest.cs
index db7fc0b4a0..76c49edf78 100644
--- a/osu.Game.Tests/NonVisual/Skinning/LegacySkinTextureFallbackTest.cs
+++ b/osu.Game.Tests/NonVisual/Skinning/LegacySkinTextureFallbackTest.cs
@@ -83,6 +83,20 @@ namespace osu.Game.Tests.NonVisual.Skinning
"followpoint.png",
"followpoint@2x.png", 2
},
+ new object[]
+ {
+ // Looking up a path with extension specified should work.
+ new[] { "Gameplay/osu/followpoint.png" },
+ "Gameplay/osu/followpoint.png",
+ "Gameplay/osu/followpoint.png", 1
+ },
+ new object[]
+ {
+ // Looking up a path with extension specified should also work with @2x sprites.
+ new[] { "Gameplay/osu/followpoint@2x.png" },
+ "Gameplay/osu/followpoint.png",
+ "Gameplay/osu/followpoint@2x.png", 2
+ },
};
[TestCaseSource(nameof(fallbackTestCases))]
diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs
index 2f966ac0a9..9aacb50684 100644
--- a/osu.Game/Configuration/OsuConfigManager.cs
+++ b/osu.Game/Configuration/OsuConfigManager.cs
@@ -3,6 +3,7 @@
using System;
using System.Diagnostics;
+using System.Globalization;
using osu.Framework.Configuration;
using osu.Framework.Configuration.Tracking;
using osu.Framework.Extensions;
@@ -102,6 +103,9 @@ namespace osu.Game.Configuration
SetDefault(OsuSetting.MenuParallax, true);
+ // See https://stackoverflow.com/a/63307411 for default sourcing.
+ SetDefault(OsuSetting.Prefer24HourTime, CultureInfo.CurrentCulture.DateTimeFormat.ShortTimePattern.Contains(@"tt"));
+
// Gameplay
SetDefault(OsuSetting.PositionalHitsounds, true); // replaced by level setting below, can be removed 20220703.
SetDefault(OsuSetting.PositionalHitsoundsLevel, 0.2f, 0, 1);
@@ -287,6 +291,7 @@ namespace osu.Game.Configuration
MenuVoice,
CursorRotation,
MenuParallax,
+ Prefer24HourTime,
BeatmapDetailTab,
BeatmapDetailModsFilter,
Username,
diff --git a/osu.Game/Localisation/GeneralSettingsStrings.cs b/osu.Game/Localisation/GeneralSettingsStrings.cs
index a60e4891f4..c65e6c77f4 100644
--- a/osu.Game/Localisation/GeneralSettingsStrings.cs
+++ b/osu.Game/Localisation/GeneralSettingsStrings.cs
@@ -29,6 +29,11 @@ namespace osu.Game.Localisation
///
public static LocalisableString PreferOriginalMetadataLanguage => new TranslatableString(getKey(@"prefer_original"), @"Prefer metadata in original language");
+ ///
+ /// "Prefer 24-hour time display"
+ ///
+ public static LocalisableString Prefer24HourTimeDisplay => new TranslatableString(getKey(@"prefer_24_hour_time_display"), @"Prefer 24-hour time display");
+
///
/// "Updates"
///
diff --git a/osu.Game/Overlays/Settings/Sections/General/LanguageSettings.cs b/osu.Game/Overlays/Settings/Sections/General/LanguageSettings.cs
index 200618c469..cdce187a35 100644
--- a/osu.Game/Overlays/Settings/Sections/General/LanguageSettings.cs
+++ b/osu.Game/Overlays/Settings/Sections/General/LanguageSettings.cs
@@ -6,6 +6,7 @@ using osu.Framework.Bindables;
using osu.Framework.Configuration;
using osu.Framework.Graphics;
using osu.Framework.Localisation;
+using osu.Game.Configuration;
using osu.Game.Extensions;
using osu.Game.Localisation;
@@ -19,7 +20,7 @@ namespace osu.Game.Overlays.Settings.Sections.General
protected override LocalisableString Header => GeneralSettingsStrings.LanguageHeader;
[BackgroundDependencyLoader]
- private void load(FrameworkConfigManager frameworkConfig)
+ private void load(FrameworkConfigManager frameworkConfig, OsuConfigManager config)
{
frameworkLocale = frameworkConfig.GetBindable(FrameworkSetting.Locale);
@@ -34,6 +35,11 @@ namespace osu.Game.Overlays.Settings.Sections.General
LabelText = GeneralSettingsStrings.PreferOriginalMetadataLanguage,
Current = frameworkConfig.GetBindable(FrameworkSetting.ShowUnicode)
},
+ new SettingsCheckbox
+ {
+ LabelText = GeneralSettingsStrings.Prefer24HourTimeDisplay,
+ Current = config.GetBindable(OsuSetting.Prefer24HourTime)
+ },
};
if (!LanguageExtensions.TryParseCultureCode(frameworkLocale.Value, out var locale))
diff --git a/osu.Game/Overlays/Toolbar/DigitalClockDisplay.cs b/osu.Game/Overlays/Toolbar/DigitalClockDisplay.cs
index 81a362450c..ac6f563336 100644
--- a/osu.Game/Overlays/Toolbar/DigitalClockDisplay.cs
+++ b/osu.Game/Overlays/Toolbar/DigitalClockDisplay.cs
@@ -29,6 +29,23 @@ namespace osu.Game.Overlays.Toolbar
}
}
+ private bool use24HourDisplay;
+
+ public bool Use24HourDisplay
+ {
+ get => use24HourDisplay;
+ set
+ {
+ if (use24HourDisplay == value)
+ return;
+
+ use24HourDisplay = value;
+
+ updateMetrics();
+ UpdateDisplay(DateTimeOffset.Now); //Update realTime.Text immediately instead of waiting until next second
+ }
+ }
+
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
@@ -50,13 +67,14 @@ namespace osu.Game.Overlays.Toolbar
protected override void UpdateDisplay(DateTimeOffset now)
{
- realTime.Text = $"{now:HH:mm:ss}";
+ realTime.Text = use24HourDisplay ? $"{now:HH:mm:ss}" : $"{now:h:mm:ss tt}";
gameTime.Text = $"running {new TimeSpan(TimeSpan.TicksPerSecond * (int)(Clock.CurrentTime / 1000)):c}";
}
private void updateMetrics()
{
- Width = showRuntime ? 66 : 45; // Allows for space for game time up to 99 days (in the padding area since this is quite rare).
+ Width = showRuntime || !use24HourDisplay ? 66 : 45; // Allows for space for game time up to 99 days (in the padding area since this is quite rare).
+
gameTime.FadeTo(showRuntime ? 1 : 0);
}
}
diff --git a/osu.Game/Overlays/Toolbar/ToolbarClock.cs b/osu.Game/Overlays/Toolbar/ToolbarClock.cs
index 22a96603dc..308359570f 100644
--- a/osu.Game/Overlays/Toolbar/ToolbarClock.cs
+++ b/osu.Game/Overlays/Toolbar/ToolbarClock.cs
@@ -20,6 +20,7 @@ namespace osu.Game.Overlays.Toolbar
public class ToolbarClock : OsuClickableContainer
{
private Bindable clockDisplayMode;
+ private Bindable prefer24HourTime;
private Box hoverBackground;
private Box flashBackground;
@@ -38,6 +39,7 @@ namespace osu.Game.Overlays.Toolbar
private void load(OsuConfigManager config)
{
clockDisplayMode = config.GetBindable(OsuSetting.ToolbarClockDisplayMode);
+ prefer24HourTime = config.GetBindable(OsuSetting.Prefer24HourTime);
Children = new Drawable[]
{
@@ -94,6 +96,8 @@ namespace osu.Game.Overlays.Toolbar
analog.FadeTo(showAnalog ? 1 : 0);
}, true);
+
+ prefer24HourTime.BindValueChanged(prefer24H => digital.Use24HourDisplay = prefer24H.NewValue, true);
}
protected override bool OnClick(ClickEvent e)
diff --git a/osu.Game/Skinning/Editor/SkinBlueprintContainer.cs b/osu.Game/Skinning/Editor/SkinBlueprintContainer.cs
index d67bfb89ab..ebf3c9c319 100644
--- a/osu.Game/Skinning/Editor/SkinBlueprintContainer.cs
+++ b/osu.Game/Skinning/Editor/SkinBlueprintContainer.cs
@@ -21,21 +21,20 @@ namespace osu.Game.Skinning.Editor
private readonly List> targetComponents = new List>();
+ [Resolved]
+ private SkinEditor editor { get; set; }
+
public SkinBlueprintContainer(Drawable target)
{
this.target = target;
}
- [BackgroundDependencyLoader(true)]
- private void load(SkinEditor editor)
- {
- SelectedItems.BindTo(editor.SelectedComponents);
- }
-
protected override void LoadComplete()
{
base.LoadComplete();
+ SelectedItems.BindTo(editor.SelectedComponents);
+
// track each target container on the current screen.
var targetContainers = target.ChildrenOfType().ToArray();
@@ -56,7 +55,7 @@ namespace osu.Game.Skinning.Editor
}
}
- private void componentsChanged(object sender, NotifyCollectionChangedEventArgs e)
+ private void componentsChanged(object sender, NotifyCollectionChangedEventArgs e) => Schedule(() =>
{
switch (e.Action)
{
@@ -79,7 +78,7 @@ namespace osu.Game.Skinning.Editor
AddBlueprintFor(item);
break;
}
- }
+ });
protected override void AddBlueprintFor(ISkinnableDrawable item)
{
@@ -93,5 +92,13 @@ namespace osu.Game.Skinning.Editor
protected override SelectionBlueprint CreateBlueprintFor(ISkinnableDrawable component)
=> new SkinBlueprint(component);
+
+ protected override void Dispose(bool isDisposing)
+ {
+ base.Dispose(isDisposing);
+
+ foreach (var list in targetComponents)
+ list.UnbindAll();
+ }
}
}
diff --git a/osu.Game/Skinning/Editor/SkinEditor.cs b/osu.Game/Skinning/Editor/SkinEditor.cs
index bcff70c008..e36d5ca3c6 100644
--- a/osu.Game/Skinning/Editor/SkinEditor.cs
+++ b/osu.Game/Skinning/Editor/SkinEditor.cs
@@ -203,6 +203,9 @@ namespace osu.Game.Skinning.Editor
SelectedComponents.Clear();
+ // Immediately clear the previous blueprint container to ensure it doesn't try to interact with the old target.
+ content?.Clear();
+
Scheduler.AddOnce(loadBlueprintContainer);
Scheduler.AddOnce(populateSettings);
diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs
index a97b5d44ce..f7d5581621 100644
--- a/osu.Game/Skinning/LegacySkin.cs
+++ b/osu.Game/Skinning/LegacySkin.cs
@@ -443,9 +443,7 @@ namespace osu.Game.Skinning
string lookupName = name.Replace(@"@2x", string.Empty);
float ratio = 2;
- string twoTimesFilename = Path.HasExtension(lookupName)
- ? @$"{Path.GetFileNameWithoutExtension(lookupName)}@2x{Path.GetExtension(lookupName)}"
- : @$"{lookupName}@2x";
+ string twoTimesFilename = $"{Path.ChangeExtension(lookupName, null)}@2x{Path.GetExtension(lookupName)}";
var texture = Textures?.Get(twoTimesFilename, wrapModeS, wrapModeT);