diff --git a/osu.Game/Skinning/PoolableSkinnableSample.cs b/osu.Game/Skinning/PoolableSkinnableSample.cs
index b04158a58f..9acc1f1a9d 100644
--- a/osu.Game/Skinning/PoolableSkinnableSample.cs
+++ b/osu.Game/Skinning/PoolableSkinnableSample.cs
@@ -2,6 +2,7 @@
// See the LICENCE file in the repository root for full licence text.
using System;
+using System.Linq;
using JetBrains.Annotations;
using osu.Framework.Allocation;
using osu.Framework.Audio;
@@ -70,22 +71,48 @@ namespace osu.Game.Skinning
updateSample();
}
+ protected override void LoadComplete()
+ {
+ base.LoadComplete();
+
+ CurrentSkin.SourceChanged += skinChangedImmediate;
+ }
+
+ private void skinChangedImmediate()
+ {
+ // Clean up the previous sample immediately on a source change.
+ // This avoids a potential call to Play() of an already disposed sample (samples are disposed along with the skin, but SkinChanged is scheduled).
+ clearPreviousSamples();
+ }
+
protected override void SkinChanged(ISkinSource skin, bool allowFallback)
{
base.SkinChanged(skin, allowFallback);
updateSample();
}
+ ///
+ /// Whether this sample was playing before a skin source change.
+ ///
+ private bool wasPlaying;
+
+ private void clearPreviousSamples()
+ {
+ // only run if the samples aren't already cleared.
+ // this ensures the "wasPlaying" state is stored correctly even if multiple clear calls are executed.
+ if (!sampleContainer.Any()) return;
+
+ wasPlaying = Playing;
+
+ sampleContainer.Clear();
+ Sample = null;
+ }
+
private void updateSample()
{
if (sampleInfo == null)
return;
- bool wasPlaying = Playing;
-
- sampleContainer.Clear();
- Sample = null;
-
var sample = CurrentSkin.GetSample(sampleInfo);
if (sample == null && AllowDefaultFallback)
@@ -155,6 +182,14 @@ namespace osu.Game.Skinning
}
}
+ protected override void Dispose(bool isDisposing)
+ {
+ base.Dispose(isDisposing);
+
+ if (CurrentSkin != null)
+ CurrentSkin.SourceChanged -= skinChangedImmediate;
+ }
+
#region Re-expose AudioContainer
public BindableNumber Volume => sampleContainer.Volume;