diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs
index fe8fef3e07..860c7fc0fa 100644
--- a/osu.Game/Beatmaps/BeatmapManager.cs
+++ b/osu.Game/Beatmaps/BeatmapManager.cs
@@ -13,6 +13,7 @@ using osu.Framework.Audio;
using osu.Framework.Audio.Track;
using osu.Framework.Extensions;
using osu.Framework.Graphics.Textures;
+using osu.Framework.Lists;
using osu.Framework.Logging;
using osu.Framework.Platform;
using osu.Framework.Threading;
@@ -159,6 +160,8 @@ namespace osu.Game.Beatmaps
/// The beatmap difficulty to restore.
public void Restore(BeatmapInfo beatmap) => beatmaps.Restore(beatmap);
+ private readonly WeakList workingCache = new WeakList();
+
///
/// Retrieve a instance for the provided
///
@@ -173,12 +176,18 @@ namespace osu.Game.Beatmaps
if (beatmapInfo?.BeatmapSet == null || beatmapInfo == DefaultBeatmap?.BeatmapInfo)
return DefaultBeatmap;
+ var cached = workingCache.FirstOrDefault(w => w.BeatmapInfo?.ID == beatmapInfo.ID);
+
+ if (cached != null)
+ return cached;
+
if (beatmapInfo.Metadata == null)
beatmapInfo.Metadata = beatmapInfo.BeatmapSet.Metadata;
WorkingBeatmap working = new BeatmapManagerWorkingBeatmap(Files.Store, new LargeTextureStore(host?.CreateTextureLoaderStore(Files.Store)), beatmapInfo, audioManager);
previous?.TransferTo(working);
+ workingCache.Add(working);
return working;
}
diff --git a/osu.Game/Beatmaps/WorkingBeatmap.cs b/osu.Game/Beatmaps/WorkingBeatmap.cs
index 138d911556..c6f26423dd 100644
--- a/osu.Game/Beatmaps/WorkingBeatmap.cs
+++ b/osu.Game/Beatmaps/WorkingBeatmap.cs
@@ -51,6 +51,11 @@ namespace osu.Game.Beatmaps
total_count.Value++;
}
+ ~WorkingBeatmap()
+ {
+ Dispose(false);
+ }
+
protected virtual Track GetVirtualTrack()
{
const double excess_length = 1000;
@@ -248,7 +253,6 @@ namespace osu.Game.Beatmaps
// cancelling the beatmap load is safe for now since the retrieval is a synchronous
// operation. if we add an async retrieval method this may need to be reconsidered.
beatmapCancellation.Cancel();
-
total_count.Value--;
}
diff --git a/osu.Game/Database/DatabaseContextFactory.cs b/osu.Game/Database/DatabaseContextFactory.cs
index 554337c477..bb6bef1c50 100644
--- a/osu.Game/Database/DatabaseContextFactory.cs
+++ b/osu.Game/Database/DatabaseContextFactory.cs
@@ -5,6 +5,7 @@ using System.Linq;
using System.Threading;
using Microsoft.EntityFrameworkCore.Storage;
using osu.Framework.Platform;
+using osu.Framework.Statistics;
namespace osu.Game.Database
{
@@ -31,11 +32,20 @@ namespace osu.Game.Database
recycleThreadContexts();
}
+ private static readonly GlobalStatistic reads = GlobalStatistics.Get("Database", "Get (Read)");
+ private static readonly GlobalStatistic writes = GlobalStatistics.Get("Database", "Get (Write)");
+ private static readonly GlobalStatistic commits = GlobalStatistics.Get("Database", "Commits");
+ private static readonly GlobalStatistic rollbacks = GlobalStatistics.Get("Database", "Rollbacks");
+
///
/// Get a context for the current thread for read-only usage.
/// If a is in progress, the existing write-safe context will be returned.
///
- public OsuDbContext Get() => threadContexts.Value;
+ public OsuDbContext Get()
+ {
+ reads.Value++;
+ return threadContexts.Value;
+ }
///
/// Request a context for write usage. Can be consumed in a nested fashion (and will return the same underlying context).
@@ -45,6 +55,7 @@ namespace osu.Game.Database
/// A usage containing a usable context.
public DatabaseWriteUsage GetForWrite(bool withTransaction = true)
{
+ writes.Value++;
Monitor.Enter(writeLock);
OsuDbContext context;
@@ -90,9 +101,15 @@ namespace osu.Game.Database
if (usages == 0)
{
if (currentWriteDidError)
+ {
+ rollbacks.Value++;
currentWriteTransaction?.Rollback();
+ }
else
+ {
+ commits.Value++;
currentWriteTransaction?.Commit();
+ }
if (currentWriteDidWrite || currentWriteDidError)
{
diff --git a/osu.Game/Database/OsuDbContext.cs b/osu.Game/Database/OsuDbContext.cs
index d31d7cbff7..538ec41b3d 100644
--- a/osu.Game/Database/OsuDbContext.cs
+++ b/osu.Game/Database/OsuDbContext.cs
@@ -6,6 +6,7 @@ using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.Extensions.Logging;
using osu.Framework.Logging;
+using osu.Framework.Statistics;
using osu.Game.Beatmaps;
using osu.Game.Configuration;
using osu.Game.IO;
@@ -34,6 +35,8 @@ namespace osu.Game.Database
private static readonly Lazy logger = new Lazy(() => new OsuDbLoggerFactory());
+ private static readonly GlobalStatistic contexts = GlobalStatistics.Get("Database", "Contexts");
+
static OsuDbContext()
{
// required to initialise native SQLite libraries on some platforms.
@@ -76,6 +79,8 @@ namespace osu.Game.Database
connection.Close();
throw;
}
+
+ contexts.Value++;
}
~OsuDbContext()
@@ -85,6 +90,20 @@ namespace osu.Game.Database
Dispose();
}
+ private bool isDisposed;
+
+ public override void Dispose()
+ {
+ if (isDisposed) return;
+
+ isDisposed = true;
+
+ base.Dispose();
+
+ contexts.Value--;
+ GC.SuppressFinalize(this);
+ }
+
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
base.OnConfiguring(optionsBuilder);
diff --git a/osu.Game/Graphics/Backgrounds/Background.cs b/osu.Game/Graphics/Backgrounds/Background.cs
index db055d15e5..526b3da8a6 100644
--- a/osu.Game/Graphics/Backgrounds/Background.cs
+++ b/osu.Game/Graphics/Backgrounds/Background.cs
@@ -6,23 +6,28 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
+using osu.Framework.Graphics.Transforms;
+using osuTK;
namespace osu.Game.Graphics.Backgrounds
{
- public class Background : BufferedContainer
+ ///
+ /// A background which offers blurring via a on demand.
+ ///
+ public class Background : CompositeDrawable
{
public Sprite Sprite;
private readonly string textureName;
+ private BufferedContainer bufferedContainer;
+
public Background(string textureName = @"")
{
- CacheDrawnFrameBuffer = true;
-
this.textureName = textureName;
RelativeSizeAxes = Axes.Both;
- Add(Sprite = new Sprite
+ AddInternal(Sprite = new Sprite
{
RelativeSizeAxes = Axes.Both,
Anchor = Anchor.Centre,
@@ -37,5 +42,28 @@ namespace osu.Game.Graphics.Backgrounds
if (!string.IsNullOrEmpty(textureName))
Sprite.Texture = textures.Get(textureName);
}
+
+ public Vector2 BlurSigma => bufferedContainer?.BlurSigma ?? Vector2.Zero;
+
+ ///
+ /// Smoothly adjusts over time.
+ ///
+ /// A to which further transforms can be added.
+ public void BlurTo(Vector2 newBlurSigma, double duration = 0, Easing easing = Easing.None)
+ {
+ if (bufferedContainer == null)
+ {
+ RemoveInternal(Sprite);
+
+ AddInternal(bufferedContainer = new BufferedContainer
+ {
+ CacheDrawnFrameBuffer = true,
+ RelativeSizeAxes = Axes.Both,
+ Child = Sprite
+ });
+ }
+
+ bufferedContainer.BlurTo(newBlurSigma, duration, easing);
+ }
}
}
diff --git a/osu.Game/Overlays/SocialOverlay.cs b/osu.Game/Overlays/SocialOverlay.cs
index 780a80b4fc..4def249200 100644
--- a/osu.Game/Overlays/SocialOverlay.cs
+++ b/osu.Game/Overlays/SocialOverlay.cs
@@ -66,24 +66,64 @@ namespace osu.Game.Overlays
}
};
- Header.Tabs.Current.ValueChanged += _ => Scheduler.AddOnce(updateSearch);
+ Header.Tabs.Current.ValueChanged += _ => queueUpdate();
- Filter.Tabs.Current.ValueChanged += _ => Scheduler.AddOnce(updateSearch);
+ Filter.Tabs.Current.ValueChanged += _ => queueUpdate();
Filter.DisplayStyleControl.DisplayStyle.ValueChanged += style => recreatePanels(style.NewValue);
- Filter.DisplayStyleControl.Dropdown.Current.ValueChanged += _ => Scheduler.AddOnce(updateSearch);
+ Filter.DisplayStyleControl.Dropdown.Current.ValueChanged += _ => queueUpdate();
+ currentQuery.BindTo(Filter.Search.Current);
currentQuery.ValueChanged += query =>
{
queryChangedDebounce?.Cancel();
if (string.IsNullOrEmpty(query.NewValue))
- Scheduler.AddOnce(updateSearch);
+ queueUpdate();
else
queryChangedDebounce = Scheduler.AddDelayed(updateSearch, 500);
};
+ }
- currentQuery.BindTo(Filter.Search.Current);
+ private APIRequest getUsersRequest;
+
+ private readonly Bindable currentQuery = new Bindable();
+
+ private ScheduledDelegate queryChangedDebounce;
+
+ private void queueUpdate() => Scheduler.AddOnce(updateSearch);
+
+ private void updateSearch()
+ {
+ queryChangedDebounce?.Cancel();
+
+ if (!IsLoaded)
+ return;
+
+ Users = null;
+ clearPanels();
+ loading.Hide();
+ getUsersRequest?.Cancel();
+
+ if (API?.IsLoggedIn != true)
+ return;
+
+ switch (Header.Tabs.Current.Value)
+ {
+ case SocialTab.Friends:
+ var friendRequest = new GetFriendsRequest(); // TODO filter arguments?
+ friendRequest.Success += updateUsers;
+ API.Queue(getUsersRequest = friendRequest);
+ break;
+
+ default:
+ var userRequest = new GetUsersRequest(); // TODO filter arguments!
+ userRequest.Success += response => updateUsers(response.Select(r => r.User));
+ API.Queue(getUsersRequest = userRequest);
+ break;
+ }
+
+ loading.Show();
}
private void recreatePanels(PanelDisplayStyle displayStyle)
@@ -133,45 +173,6 @@ namespace osu.Game.Overlays
});
}
- private APIRequest getUsersRequest;
-
- private readonly Bindable currentQuery = new Bindable();
-
- private ScheduledDelegate queryChangedDebounce;
-
- private void updateSearch()
- {
- queryChangedDebounce?.Cancel();
-
- if (!IsLoaded)
- return;
-
- Users = null;
- clearPanels();
- loading.Hide();
- getUsersRequest?.Cancel();
-
- if (API?.IsLoggedIn != true)
- return;
-
- switch (Header.Tabs.Current.Value)
- {
- case SocialTab.Friends:
- var friendRequest = new GetFriendsRequest(); // TODO filter arguments?
- friendRequest.Success += updateUsers;
- API.Queue(getUsersRequest = friendRequest);
- break;
-
- default:
- var userRequest = new GetUsersRequest(); // TODO filter arguments!
- userRequest.Success += response => updateUsers(response.Select(r => r.User));
- API.Queue(getUsersRequest = userRequest);
- break;
- }
-
- loading.Show();
- }
-
private void updateUsers(IEnumerable newUsers)
{
Users = newUsers;
@@ -193,7 +194,7 @@ namespace osu.Game.Overlays
switch (state)
{
case APIState.Online:
- Scheduler.AddOnce(updateSearch);
+ queueUpdate();
break;
default:
diff --git a/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs b/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs
index 7092ac0c4a..55338ea01a 100644
--- a/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs
+++ b/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs
@@ -18,7 +18,7 @@ namespace osu.Game.Screens.Backgrounds
private Background background;
private int currentDisplay;
- private const int background_count = 5;
+ private const int background_count = 7;
private string backgroundName => $@"Menu/menu-background-{currentDisplay % background_count + 1}";
diff --git a/osu.Game/Screens/Menu/Intro.cs b/osu.Game/Screens/Menu/Intro.cs
index c52e8541c5..dab5066c52 100644
--- a/osu.Game/Screens/Menu/Intro.cs
+++ b/osu.Game/Screens/Menu/Intro.cs
@@ -86,6 +86,7 @@ namespace osu.Game.Screens.Menu
if (!resuming)
{
Beatmap.Value = introBeatmap;
+ introBeatmap = null;
if (menuVoice.Value)
welcome.Play();
@@ -94,7 +95,10 @@ namespace osu.Game.Screens.Menu
{
// Only start the current track if it is the menu music. A beatmap's track is started when entering the Main Manu.
if (menuMusic.Value)
+ {
track.Start();
+ track = null;
+ }
LoadComponentAsync(mainMenu = new MainMenu());
diff --git a/osu.Game/Screens/Menu/LogoVisualisation.cs b/osu.Game/Screens/Menu/LogoVisualisation.cs
index c6de5857c2..2ba82b5d9b 100644
--- a/osu.Game/Screens/Menu/LogoVisualisation.cs
+++ b/osu.Game/Screens/Menu/LogoVisualisation.cs
@@ -96,13 +96,13 @@ namespace osu.Game.Screens.Menu
var track = beatmap.Value.TrackLoaded ? beatmap.Value.Track : null;
var effect = beatmap.Value.BeatmapLoaded ? beatmap.Value.Beatmap.ControlPointInfo.EffectPointAt(track?.CurrentTime ?? Time.Current) : null;
- float[] temporalAmplitudes = track?.CurrentAmplitudes.FrequencyAmplitudes ?? new float[256];
+ float[] temporalAmplitudes = track?.CurrentAmplitudes.FrequencyAmplitudes;
for (int i = 0; i < bars_per_visualiser; i++)
{
if (track?.IsRunning ?? false)
{
- float targetAmplitude = temporalAmplitudes[(i + indexOffset) % bars_per_visualiser] * (effect?.KiaiMode == true ? 1 : 0.5f);
+ float targetAmplitude = (temporalAmplitudes?[(i + indexOffset) % bars_per_visualiser] ?? 0) * (effect?.KiaiMode == true ? 1 : 0.5f);
if (targetAmplitude > frequencyAmplitudes[i])
frequencyAmplitudes[i] = targetAmplitude;
}
@@ -115,7 +115,6 @@ namespace osu.Game.Screens.Menu
}
indexOffset = (indexOffset + index_change) % bars_per_visualiser;
- Scheduler.AddDelayed(updateAmplitudes, time_between_updates);
}
private void updateColour()
@@ -131,7 +130,8 @@ namespace osu.Game.Screens.Menu
protected override void LoadComplete()
{
base.LoadComplete();
- updateAmplitudes();
+
+ Scheduler.AddDelayed(updateAmplitudes, time_between_updates, true);
}
protected override void Update()
diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj
index d6a998bf55..8c4f5dcb7d 100644
--- a/osu.Game/osu.Game.csproj
+++ b/osu.Game/osu.Game.csproj
@@ -14,7 +14,7 @@
-
+
diff --git a/osu.iOS.props b/osu.iOS.props
index de4a14f01f..113874f6f6 100644
--- a/osu.iOS.props
+++ b/osu.iOS.props
@@ -104,7 +104,7 @@
-
+