mirror of
https://github.com/ppy/osu.git
synced 2025-01-13 13:32:54 +08:00
Merge branch 'master' into watch-replays-4
This commit is contained in:
commit
466bc7f28a
@ -30,9 +30,9 @@ namespace osu.Game.Tests
|
||||
trackStore = audioManager.GetTrackStore(reader);
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
protected override void Dispose(bool isDisposing)
|
||||
{
|
||||
base.Dispose();
|
||||
base.Dispose(isDisposing);
|
||||
stream?.Dispose();
|
||||
reader?.Dispose();
|
||||
trackStore?.Dispose();
|
||||
|
@ -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
|
||||
/// <param name="beatmap">The beatmap difficulty to restore.</param>
|
||||
public void Restore(BeatmapInfo beatmap) => beatmaps.Restore(beatmap);
|
||||
|
||||
private readonly WeakList<WorkingBeatmap> workingCache = new WeakList<WorkingBeatmap>();
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve a <see cref="WorkingBeatmap"/> instance for the provided <see cref="BeatmapInfo"/>
|
||||
/// </summary>
|
||||
@ -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;
|
||||
}
|
||||
|
@ -11,7 +11,9 @@ using osu.Framework.IO.File;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Statistics;
|
||||
using osu.Game.IO.Serialization;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
@ -31,6 +33,8 @@ namespace osu.Game.Beatmaps
|
||||
|
||||
protected AudioManager AudioManager { get; }
|
||||
|
||||
private static readonly GlobalStatistic<int> total_count = GlobalStatistics.Get<int>(nameof(Beatmaps), $"Total {nameof(WorkingBeatmap)}s");
|
||||
|
||||
protected WorkingBeatmap(BeatmapInfo beatmapInfo, AudioManager audioManager)
|
||||
{
|
||||
AudioManager = audioManager;
|
||||
@ -38,24 +42,13 @@ namespace osu.Game.Beatmaps
|
||||
BeatmapSetInfo = beatmapInfo.BeatmapSet;
|
||||
Metadata = beatmapInfo.Metadata ?? BeatmapSetInfo?.Metadata ?? new BeatmapMetadata();
|
||||
|
||||
beatmap = new RecyclableLazy<IBeatmap>(() =>
|
||||
{
|
||||
var b = GetBeatmap() ?? new Beatmap();
|
||||
|
||||
// The original beatmap version needs to be preserved as the database doesn't contain it
|
||||
BeatmapInfo.BeatmapVersion = b.BeatmapInfo.BeatmapVersion;
|
||||
|
||||
// Use the database-backed info for more up-to-date values (beatmap id, ranked status, etc)
|
||||
b.BeatmapInfo = BeatmapInfo;
|
||||
|
||||
return b;
|
||||
});
|
||||
|
||||
track = new RecyclableLazy<Track>(() => GetTrack() ?? GetVirtualTrack());
|
||||
background = new RecyclableLazy<Texture>(GetBackground, BackgroundStillValid);
|
||||
waveform = new RecyclableLazy<Waveform>(GetWaveform);
|
||||
storyboard = new RecyclableLazy<Storyboard>(GetStoryboard);
|
||||
skin = new RecyclableLazy<Skin>(GetSkin);
|
||||
|
||||
total_count.Value++;
|
||||
}
|
||||
|
||||
protected virtual Track GetVirtualTrack()
|
||||
@ -153,10 +146,40 @@ namespace osu.Game.Beatmaps
|
||||
|
||||
public override string ToString() => BeatmapInfo.ToString();
|
||||
|
||||
public bool BeatmapLoaded => beatmap.IsResultAvailable;
|
||||
public IBeatmap Beatmap => beatmap.Value;
|
||||
public bool BeatmapLoaded => beatmapLoadTask?.IsCompleted ?? false;
|
||||
|
||||
public Task<IBeatmap> LoadBeatmapAsync() => (beatmapLoadTask ?? (beatmapLoadTask = Task.Factory.StartNew(() =>
|
||||
{
|
||||
// Todo: Handle cancellation during beatmap parsing
|
||||
var b = GetBeatmap() ?? new Beatmap();
|
||||
|
||||
// The original beatmap version needs to be preserved as the database doesn't contain it
|
||||
BeatmapInfo.BeatmapVersion = b.BeatmapInfo.BeatmapVersion;
|
||||
|
||||
// Use the database-backed info for more up-to-date values (beatmap id, ranked status, etc)
|
||||
b.BeatmapInfo = BeatmapInfo;
|
||||
|
||||
return b;
|
||||
}, beatmapCancellation.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default)));
|
||||
|
||||
public IBeatmap Beatmap
|
||||
{
|
||||
get
|
||||
{
|
||||
try
|
||||
{
|
||||
return LoadBeatmapAsync().Result;
|
||||
}
|
||||
catch (TaskCanceledException)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private readonly CancellationTokenSource beatmapCancellation = new CancellationTokenSource();
|
||||
protected abstract IBeatmap GetBeatmap();
|
||||
private readonly RecyclableLazy<IBeatmap> beatmap;
|
||||
private Task<IBeatmap> beatmapLoadTask;
|
||||
|
||||
public bool BackgroundLoaded => background.IsResultAvailable;
|
||||
public Texture Background => background.Value;
|
||||
@ -195,20 +218,46 @@ namespace osu.Game.Beatmaps
|
||||
other.track = track;
|
||||
}
|
||||
|
||||
public virtual void Dispose()
|
||||
{
|
||||
background.Recycle();
|
||||
waveform.Recycle();
|
||||
storyboard.Recycle();
|
||||
skin.Recycle();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Eagerly dispose of the audio track associated with this <see cref="WorkingBeatmap"/> (if any).
|
||||
/// Accessing track again will load a fresh instance.
|
||||
/// </summary>
|
||||
public virtual void RecycleTrack() => track.Recycle();
|
||||
|
||||
#region Disposal
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
private bool isDisposed;
|
||||
|
||||
protected virtual void Dispose(bool isDisposing)
|
||||
{
|
||||
if (isDisposed)
|
||||
return;
|
||||
|
||||
isDisposed = true;
|
||||
|
||||
// recycling logic is not here for the time being, as components which use
|
||||
// retrieved objects from WorkingBeatmap may not hold a reference to the WorkingBeatmap itself.
|
||||
// this should be fine as each retrieved component do have their own finalizers.
|
||||
|
||||
// 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--;
|
||||
}
|
||||
|
||||
~WorkingBeatmap()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public class RecyclableLazy<T>
|
||||
{
|
||||
private Lazy<T> lazy;
|
||||
|
@ -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<int> reads = GlobalStatistics.Get<int>("Database", "Get (Read)");
|
||||
private static readonly GlobalStatistic<int> writes = GlobalStatistics.Get<int>("Database", "Get (Write)");
|
||||
private static readonly GlobalStatistic<int> commits = GlobalStatistics.Get<int>("Database", "Commits");
|
||||
private static readonly GlobalStatistic<int> rollbacks = GlobalStatistics.Get<int>("Database", "Rollbacks");
|
||||
|
||||
/// <summary>
|
||||
/// Get a context for the current thread for read-only usage.
|
||||
/// If a <see cref="DatabaseWriteUsage"/> is in progress, the existing write-safe context will be returned.
|
||||
/// </summary>
|
||||
public OsuDbContext Get() => threadContexts.Value;
|
||||
public OsuDbContext Get()
|
||||
{
|
||||
reads.Value++;
|
||||
return threadContexts.Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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
|
||||
/// <returns>A usage containing a usable context.</returns>
|
||||
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)
|
||||
{
|
||||
|
@ -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<OsuDbLoggerFactory> logger = new Lazy<OsuDbLoggerFactory>(() => new OsuDbLoggerFactory());
|
||||
|
||||
private static readonly GlobalStatistic<int> contexts = GlobalStatistics.Get<int>("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);
|
||||
|
@ -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
|
||||
/// <summary>
|
||||
/// A background which offers blurring via a <see cref="BufferedContainer"/> on demand.
|
||||
/// </summary>
|
||||
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;
|
||||
|
||||
/// <summary>
|
||||
/// Smoothly adjusts <see cref="IBufferedContainer.BlurSigma"/> over time.
|
||||
/// </summary>
|
||||
/// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns>
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -297,6 +297,10 @@ namespace osu.Game
|
||||
var nextBeatmap = beatmap.NewValue;
|
||||
if (nextBeatmap?.Track != null)
|
||||
nextBeatmap.Track.Completed += currentTrackCompleted;
|
||||
|
||||
beatmap.OldValue?.Dispose();
|
||||
|
||||
nextBeatmap?.LoadBeatmapAsync();
|
||||
}
|
||||
|
||||
private void currentTrackCompleted()
|
||||
|
@ -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<string> currentQuery = new Bindable<string>();
|
||||
|
||||
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<string> currentQuery = new Bindable<string>();
|
||||
|
||||
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<User> newUsers)
|
||||
{
|
||||
Users = newUsers;
|
||||
@ -193,7 +194,7 @@ namespace osu.Game.Overlays
|
||||
switch (state)
|
||||
{
|
||||
case APIState.Online:
|
||||
Scheduler.AddOnce(updateSearch);
|
||||
queueUpdate();
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -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}";
|
||||
|
||||
|
@ -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());
|
||||
|
||||
|
@ -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()
|
||||
|
@ -137,9 +137,9 @@ namespace osu.Game.Tests.Visual
|
||||
track = audio?.Tracks.GetVirtual(length);
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
protected override void Dispose(bool isDisposing)
|
||||
{
|
||||
base.Dispose();
|
||||
base.Dispose(isDisposing);
|
||||
store?.Dispose();
|
||||
}
|
||||
|
||||
|
@ -14,8 +14,8 @@
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.4" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.4" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2019.701.0" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2019.702.0" />
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2019.702.0" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2019.703.0" />
|
||||
<PackageReference Include="SharpCompress" Version="0.23.0" />
|
||||
<PackageReference Include="NUnit" Version="3.12.0" />
|
||||
<PackageReference Include="SharpRaven" Version="2.4.0" />
|
||||
|
@ -104,9 +104,9 @@
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.1" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.1" />
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2019.701.0" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2019.702.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.iOS" Version="2019.702.0" />
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2019.702.0" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2019.703.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.iOS" Version="2019.703.0" />
|
||||
<PackageReference Include="SharpCompress" Version="0.22.0" />
|
||||
<PackageReference Include="NUnit" Version="3.11.0" />
|
||||
<PackageReference Include="SharpRaven" Version="2.4.0" />
|
||||
|
Loading…
Reference in New Issue
Block a user