diff --git a/osu.Android.props b/osu.Android.props
index bbe8426316..5078fee1cf 100644
--- a/osu.Android.props
+++ b/osu.Android.props
@@ -52,6 +52,6 @@
   </ItemGroup>
   <ItemGroup>
     <PackageReference Include="ppy.osu.Game.Resources" Version="2020.1030.0" />
-    <PackageReference Include="ppy.osu.Framework.Android" Version="2020.1110.0" />
+    <PackageReference Include="ppy.osu.Framework.Android" Version="2020.1111.0" />
   </ItemGroup>
 </Project>
diff --git a/osu.Game.Rulesets.Mania.Tests/TestSceneOutOfOrderHits.cs b/osu.Game.Rulesets.Mania.Tests/TestSceneOutOfOrderHits.cs
index e8c2472c3b..cecac38f70 100644
--- a/osu.Game.Rulesets.Mania.Tests/TestSceneOutOfOrderHits.cs
+++ b/osu.Game.Rulesets.Mania.Tests/TestSceneOutOfOrderHits.cs
@@ -1,6 +1,7 @@
 // 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.Collections.Generic;
 using System.Linq;
 using NUnit.Framework;
@@ -54,12 +55,77 @@ namespace osu.Game.Rulesets.Mania.Tests
             }
         }
 
+        [Test]
+        public void TestHoldNoteMissAfterNextObjectStartTime()
+        {
+            var objects = new List<ManiaHitObject>
+            {
+                new HoldNote
+                {
+                    StartTime = 1000,
+                    EndTime = 1010,
+                },
+                new HoldNote
+                {
+                    StartTime = 1020,
+                    EndTime = 1030
+                }
+            };
+
+            performTest(objects, new List<ReplayFrame>());
+
+            addJudgementAssert(objects[0], HitResult.IgnoreHit);
+            addJudgementAssert(objects[1], HitResult.IgnoreHit);
+        }
+
+        [Test]
+        public void TestHoldNoteReleasedHitAfterNextObjectStartTime()
+        {
+            var objects = new List<ManiaHitObject>
+            {
+                new HoldNote
+                {
+                    StartTime = 1000,
+                    EndTime = 1010,
+                },
+                new HoldNote
+                {
+                    StartTime = 1020,
+                    EndTime = 1030
+                }
+            };
+
+            var frames = new List<ReplayFrame>
+            {
+                new ManiaReplayFrame(1000, ManiaAction.Key1),
+                new ManiaReplayFrame(1030),
+                new ManiaReplayFrame(1040, ManiaAction.Key1),
+                new ManiaReplayFrame(1050)
+            };
+
+            performTest(objects, frames);
+
+            addJudgementAssert(objects[0], HitResult.IgnoreHit);
+            addJudgementAssert("first head", () => ((HoldNote)objects[0]).Head, HitResult.Perfect);
+            addJudgementAssert("first tail", () => ((HoldNote)objects[0]).Tail, HitResult.Perfect);
+
+            addJudgementAssert(objects[1], HitResult.IgnoreHit);
+            addJudgementAssert("second head", () => ((HoldNote)objects[1]).Head, HitResult.Great);
+            addJudgementAssert("second tail", () => ((HoldNote)objects[1]).Tail, HitResult.Perfect);
+        }
+
         private void addJudgementAssert(ManiaHitObject hitObject, HitResult result)
         {
             AddAssert($"({hitObject.GetType().ReadableName()} @ {hitObject.StartTime}) judgement is {result}",
                 () => judgementResults.Single(r => r.HitObject == hitObject).Type == result);
         }
 
+        private void addJudgementAssert(string name, Func<ManiaHitObject> hitObject, HitResult result)
+        {
+            AddAssert($"{name} judgement is {result}",
+                () => judgementResults.Single(r => r.HitObject == hitObject()).Type == result);
+        }
+
         private void addJudgementOffsetAssert(ManiaHitObject hitObject, double offset)
         {
             AddAssert($"({hitObject.GetType().ReadableName()} @ {hitObject.StartTime}) judged at {offset}",
diff --git a/osu.Game.Rulesets.Mania/UI/OrderedHitPolicy.cs b/osu.Game.Rulesets.Mania/UI/OrderedHitPolicy.cs
index 0f9cd48dd8..961858b62b 100644
--- a/osu.Game.Rulesets.Mania/UI/OrderedHitPolicy.cs
+++ b/osu.Game.Rulesets.Mania/UI/OrderedHitPolicy.cs
@@ -1,7 +1,6 @@
 // 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.Collections.Generic;
 using osu.Framework.Extensions.IEnumerableExtensions;
 using osu.Game.Rulesets.Mania.Objects.Drawables;
@@ -44,9 +43,6 @@ namespace osu.Game.Rulesets.Mania.UI
         /// <param name="hitObject">The <see cref="HitObject"/> that was hit.</param>
         public void HandleHit(DrawableHitObject hitObject)
         {
-            if (!IsHittable(hitObject, hitObject.HitObject.StartTime + hitObject.Result.TimeOffset))
-                throw new InvalidOperationException($"A {hitObject} was hit before it became hittable!");
-
             foreach (var obj in enumerateHitObjectsUpTo(hitObject.HitObject.StartTime))
             {
                 if (obj.Judged)
diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSkinFallbacks.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSkinFallbacks.cs
index 075bf314bc..856bfd7e80 100644
--- a/osu.Game.Rulesets.Osu.Tests/TestSceneSkinFallbacks.cs
+++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSkinFallbacks.cs
@@ -125,6 +125,9 @@ namespace osu.Game.Rulesets.Osu.Tests
             {
                 if (!enabled) return null;
 
+                if (component is OsuSkinComponent osuComponent && osuComponent.Component == OsuSkinComponents.SliderBody)
+                    return null;
+
                 return new OsuSpriteText
                 {
                     Text = identifier,
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModHidden.cs b/osu.Game.Rulesets.Osu/Mods/OsuModHidden.cs
index 025e202666..cf7faca9b9 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModHidden.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModHidden.cs
@@ -27,17 +27,23 @@ namespace osu.Game.Rulesets.Osu.Mods
         public override void ApplyToDrawableHitObjects(IEnumerable<DrawableHitObject> drawables)
         {
             foreach (var d in drawables)
-                d.ApplyCustomUpdateState += applyFadeInAdjustment;
+            {
+                d.HitObjectApplied += applyFadeInAdjustment;
+                applyFadeInAdjustment(d);
+            }
 
             base.ApplyToDrawableHitObjects(drawables);
         }
 
-        private void applyFadeInAdjustment(DrawableHitObject hitObject, ArmedState state)
+        private void applyFadeInAdjustment(DrawableHitObject hitObject)
         {
             if (!(hitObject is DrawableOsuHitObject d))
                 return;
 
             d.HitObject.TimeFadeIn = d.HitObject.TimePreempt * fade_in_duration_multiplier;
+
+            foreach (var nested in d.NestedHitObjects)
+                applyFadeInAdjustment(nested);
         }
 
         private double lastSliderHeadFadeOutStartTime;
diff --git a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneKiaiHitExplosion.cs b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneKiaiHitExplosion.cs
new file mode 100644
index 0000000000..b558709592
--- /dev/null
+++ b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneKiaiHitExplosion.cs
@@ -0,0 +1,37 @@
+// 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 NUnit.Framework;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Game.Rulesets.Taiko.Objects;
+using osu.Game.Rulesets.Taiko.UI;
+
+namespace osu.Game.Rulesets.Taiko.Tests.Skinning
+{
+    [TestFixture]
+    public class TestSceneKiaiHitExplosion : TaikoSkinnableTestScene
+    {
+        [Test]
+        public void TestKiaiHits()
+        {
+            AddStep("rim hit", () => SetContents(() => getContentFor(createHit(HitType.Rim))));
+            AddStep("centre hit", () => SetContents(() => getContentFor(createHit(HitType.Centre))));
+        }
+
+        private Drawable getContentFor(DrawableTestHit hit)
+        {
+            return new Container
+            {
+                RelativeSizeAxes = Axes.Both,
+                Child = new KiaiHitExplosion(hit, hit.HitObject.Type)
+                {
+                    Anchor = Anchor.Centre,
+                    Origin = Anchor.Centre,
+                }
+            };
+        }
+
+        private DrawableTestHit createHit(HitType type) => new DrawableTestHit(new Hit { StartTime = Time.Current, Type = type });
+    }
+}
diff --git a/osu.Game.Rulesets.Taiko/Skinning/TaikoLegacySkinTransformer.cs b/osu.Game.Rulesets.Taiko/Skinning/TaikoLegacySkinTransformer.cs
index c88480d18f..96fb065e79 100644
--- a/osu.Game.Rulesets.Taiko/Skinning/TaikoLegacySkinTransformer.cs
+++ b/osu.Game.Rulesets.Taiko/Skinning/TaikoLegacySkinTransformer.cs
@@ -114,6 +114,14 @@ namespace osu.Game.Rulesets.Taiko.Skinning
 
                     return null;
 
+                case TaikoSkinComponents.TaikoExplosionKiai:
+                    // suppress the default kiai explosion if the skin brings its own sprites.
+                    // the drawable needs to expire as soon as possible to avoid accumulating empty drawables on the playfield.
+                    if (hasExplosion.Value)
+                        return Drawable.Empty().With(d => d.LifetimeEnd = double.MinValue);
+
+                    return null;
+
                 case TaikoSkinComponents.Scroller:
                     if (GetTexture("taiko-slider") != null)
                         return new LegacyTaikoScroller();
diff --git a/osu.Game.Rulesets.Taiko/TaikoSkinComponents.cs b/osu.Game.Rulesets.Taiko/TaikoSkinComponents.cs
index 132d8f8868..bf48898dd2 100644
--- a/osu.Game.Rulesets.Taiko/TaikoSkinComponents.cs
+++ b/osu.Game.Rulesets.Taiko/TaikoSkinComponents.cs
@@ -18,6 +18,7 @@ namespace osu.Game.Rulesets.Taiko
         TaikoExplosionMiss,
         TaikoExplosionOk,
         TaikoExplosionGreat,
+        TaikoExplosionKiai,
         Scroller,
         Mascot,
     }
diff --git a/osu.Game.Rulesets.Taiko/UI/DefaultKiaiHitExplosion.cs b/osu.Game.Rulesets.Taiko/UI/DefaultKiaiHitExplosion.cs
new file mode 100644
index 0000000000..7ce8b016d5
--- /dev/null
+++ b/osu.Game.Rulesets.Taiko/UI/DefaultKiaiHitExplosion.cs
@@ -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 osuTK;
+using osu.Framework.Allocation;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Effects;
+using osu.Framework.Graphics.Shapes;
+using osu.Game.Graphics;
+using osu.Game.Rulesets.Taiko.Objects;
+
+namespace osu.Game.Rulesets.Taiko.UI
+{
+    public class DefaultKiaiHitExplosion : CircularContainer
+    {
+        public override bool RemoveWhenNotAlive => true;
+
+        private readonly HitType type;
+
+        public DefaultKiaiHitExplosion(HitType type)
+        {
+            this.type = type;
+
+            RelativeSizeAxes = Axes.Both;
+
+            Blending = BlendingParameters.Additive;
+
+            Masking = true;
+            Alpha = 0.25f;
+
+            Children = new[]
+            {
+                new Box
+                {
+                    RelativeSizeAxes = Axes.Both,
+                    Alpha = 0,
+                    AlwaysPresent = true
+                }
+            };
+        }
+
+        [BackgroundDependencyLoader]
+        private void load(OsuColour colours)
+        {
+            EdgeEffect = new EdgeEffectParameters
+            {
+                Type = EdgeEffectType.Glow,
+                Colour = type == HitType.Rim ? colours.BlueDarker : colours.PinkDarker,
+                Radius = 60,
+            };
+        }
+
+        protected override void LoadComplete()
+        {
+            base.LoadComplete();
+
+            this.ScaleTo(new Vector2(1, 3f), 500, Easing.OutQuint);
+            this.FadeOut(250);
+
+            Expire(true);
+        }
+    }
+}
diff --git a/osu.Game.Rulesets.Taiko/UI/KiaiHitExplosion.cs b/osu.Game.Rulesets.Taiko/UI/KiaiHitExplosion.cs
index 067d390894..20900a9352 100644
--- a/osu.Game.Rulesets.Taiko/UI/KiaiHitExplosion.cs
+++ b/osu.Game.Rulesets.Taiko/UI/KiaiHitExplosion.cs
@@ -1,71 +1,47 @@
 // 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 osuTK;
 using osu.Framework.Allocation;
 using osu.Framework.Graphics;
 using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Effects;
-using osu.Framework.Graphics.Shapes;
-using osu.Game.Graphics;
 using osu.Game.Rulesets.Objects.Drawables;
 using osu.Game.Rulesets.Taiko.Objects;
+using osu.Game.Skinning;
+using osuTK;
 
 namespace osu.Game.Rulesets.Taiko.UI
 {
-    public class KiaiHitExplosion : CircularContainer
+    public class KiaiHitExplosion : Container
     {
         public override bool RemoveWhenNotAlive => true;
 
+        [Cached(typeof(DrawableHitObject))]
         public readonly DrawableHitObject JudgedObject;
-        private readonly HitType type;
 
-        public KiaiHitExplosion(DrawableHitObject judgedObject, HitType type)
+        private readonly HitType hitType;
+
+        private SkinnableDrawable skinnable;
+
+        public override double LifetimeStart => skinnable.Drawable.LifetimeStart;
+
+        public override double LifetimeEnd => skinnable.Drawable.LifetimeEnd;
+
+        public KiaiHitExplosion(DrawableHitObject judgedObject, HitType hitType)
         {
             JudgedObject = judgedObject;
-            this.type = type;
+            this.hitType = hitType;
 
             Anchor = Anchor.CentreLeft;
             Origin = Anchor.Centre;
 
             RelativeSizeAxes = Axes.Both;
             Size = new Vector2(TaikoHitObject.DEFAULT_SIZE, 1);
-
-            Blending = BlendingParameters.Additive;
-
-            Masking = true;
-            Alpha = 0.25f;
-
-            Children = new[]
-            {
-                new Box
-                {
-                    RelativeSizeAxes = Axes.Both,
-                    Alpha = 0,
-                    AlwaysPresent = true
-                }
-            };
         }
 
         [BackgroundDependencyLoader]
-        private void load(OsuColour colours)
+        private void load()
         {
-            EdgeEffect = new EdgeEffectParameters
-            {
-                Type = EdgeEffectType.Glow,
-                Colour = type == HitType.Rim ? colours.BlueDarker : colours.PinkDarker,
-                Radius = 60,
-            };
-        }
-
-        protected override void LoadComplete()
-        {
-            base.LoadComplete();
-
-            this.ScaleTo(new Vector2(1, 3f), 500, Easing.OutQuint);
-            this.FadeOut(250);
-
-            Expire(true);
+            Child = skinnable = new SkinnableDrawable(new TaikoSkinComponent(TaikoSkinComponents.TaikoExplosionKiai), _ => new DefaultKiaiHitExplosion(hitType));
         }
     }
 }
diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs
index 442be6e837..37ab489da5 100644
--- a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs
+++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs
@@ -16,8 +16,6 @@ namespace osu.Game.Beatmaps.Formats
 {
     public class LegacyBeatmapDecoder : LegacyDecoder<Beatmap>
     {
-        public const int LATEST_VERSION = 14;
-
         private Beatmap beatmap;
 
         private ConvertHitObjectParser parser;
diff --git a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs
index 7b377e481f..de4dc8cdc8 100644
--- a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs
+++ b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs
@@ -16,6 +16,8 @@ namespace osu.Game.Beatmaps.Formats
     public abstract class LegacyDecoder<T> : Decoder<T>
         where T : new()
     {
+        public const int LATEST_VERSION = 14;
+
         protected readonly int FormatVersion;
 
         protected LegacyDecoder(int version)
diff --git a/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs
index 8d8ca523d5..9a244c8bb2 100644
--- a/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs
+++ b/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs
@@ -4,6 +4,7 @@
 using System;
 using System.Collections.Generic;
 using System.IO;
+using System.Linq;
 using osu.Framework.Graphics;
 using osu.Framework.Utils;
 using osu.Game.Beatmaps.Legacy;
@@ -23,15 +24,15 @@ namespace osu.Game.Beatmaps.Formats
 
         private readonly Dictionary<string, string> variables = new Dictionary<string, string>();
 
-        public LegacyStoryboardDecoder()
-            : base(0)
+        public LegacyStoryboardDecoder(int version = LATEST_VERSION)
+            : base(version)
         {
         }
 
         public static void Register()
         {
             // note that this isn't completely correct
-            AddDecoder<Storyboard>(@"osu file format v", m => new LegacyStoryboardDecoder());
+            AddDecoder<Storyboard>(@"osu file format v", m => new LegacyStoryboardDecoder(Parsing.ParseInt(m.Split('v').Last())));
             AddDecoder<Storyboard>(@"[Events]", m => new LegacyStoryboardDecoder());
             SetFallbackDecoder<Storyboard>(() => new LegacyStoryboardDecoder());
         }
@@ -133,6 +134,11 @@ namespace osu.Game.Beatmaps.Formats
                         var y = Parsing.ParseFloat(split[5], Parsing.MAX_COORDINATE_VALUE);
                         var frameCount = Parsing.ParseInt(split[6]);
                         var frameDelay = Parsing.ParseDouble(split[7]);
+
+                        if (FormatVersion < 6)
+                            // this is random as hell but taken straight from osu-stable.
+                            frameDelay = Math.Round(0.015 * frameDelay) * 1.186 * (1000 / 60f);
+
                         var loopType = split.Length > 8 ? (AnimationLoopType)Enum.Parse(typeof(AnimationLoopType), split[8]) : AnimationLoopType.LoopForever;
                         storyboardSprite = new StoryboardAnimation(path, origin, new Vector2(x, y), frameCount, frameDelay, loopType);
                         storyboard.GetLayer(layer).Add(storyboardSprite);
diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs
index 6b768cc8fc..1a1ebcc2d4 100644
--- a/osu.Game/OsuGame.cs
+++ b/osu.Game/OsuGame.cs
@@ -681,7 +681,6 @@ namespace osu.Game
 
             loadComponentSingleFile(new AccountCreationOverlay(), topMostOverlayContent.Add, true);
             loadComponentSingleFile(new DialogOverlay(), topMostOverlayContent.Add, true);
-            loadComponentSingleFile(externalLinkOpener = new ExternalLinkOpener(), topMostOverlayContent.Add);
 
             chatOverlay.State.ValueChanged += state => channelManager.HighPollRate.Value = state.NewValue == Visibility.Visible;
 
diff --git a/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs b/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs
index 8f19cd900c..556f3139dd 100644
--- a/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs
+++ b/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs
@@ -16,7 +16,7 @@ namespace osu.Game.Overlays.Profile.Sections.Historical
     public class PaginatedMostPlayedBeatmapContainer : PaginatedContainer<APIUserMostPlayedBeatmap>
     {
         public PaginatedMostPlayedBeatmapContainer(Bindable<User> user)
-            : base(user, "Most Played Beatmaps", "No records. :(")
+            : base(user, "Most Played Beatmaps", "No records. :(", CounterVisibilityState.AlwaysVisible)
         {
             ItemsPerPage = 5;
         }
@@ -27,6 +27,8 @@ namespace osu.Game.Overlays.Profile.Sections.Historical
             ItemsContainer.Direction = FillDirection.Vertical;
         }
 
+        protected override int GetCount(User user) => user.BeatmapPlaycountsCount;
+
         protected override APIRequest<List<APIUserMostPlayedBeatmap>> CreateRequest() =>
             new GetUserMostPlayedBeatmapsRequest(User.Value.Id, VisiblePages++, ItemsPerPage);
 
diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs
index 6af445939b..56b725da0e 100644
--- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs
+++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs
@@ -27,8 +27,16 @@ namespace osu.Game.Rulesets.Objects.Drawables
     [Cached(typeof(DrawableHitObject))]
     public abstract class DrawableHitObject : SkinReloadableDrawable
     {
+        /// <summary>
+        /// Invoked after this <see cref="DrawableHitObject"/>'s applied <see cref="HitObject"/> has had its defaults applied.
+        /// </summary>
         public event Action<DrawableHitObject> DefaultsApplied;
 
+        /// <summary>
+        /// Invoked after a <see cref="HitObject"/> has been applied to this <see cref="DrawableHitObject"/>.
+        /// </summary>
+        public event Action<DrawableHitObject> HitObjectApplied;
+
         /// <summary>
         /// The <see cref="HitObject"/> currently represented by this <see cref="DrawableHitObject"/>.
         /// </summary>
@@ -221,6 +229,7 @@ namespace osu.Game.Rulesets.Objects.Drawables
             HitObject.DefaultsApplied += onDefaultsApplied;
 
             OnApply(hitObject);
+            HitObjectApplied?.Invoke(this);
 
             // If not loaded, the state update happens in LoadComplete(). Otherwise, the update is scheduled to allow for lifetime updates.
             if (IsLoaded)
diff --git a/osu.Game/Users/User.cs b/osu.Game/Users/User.cs
index 2a76a963e1..d7e78d5b35 100644
--- a/osu.Game/Users/User.cs
+++ b/osu.Game/Users/User.cs
@@ -144,6 +144,9 @@ namespace osu.Game.Users
         [JsonProperty(@"scores_first_count")]
         public int ScoresFirstCount;
 
+        [JsonProperty(@"beatmap_playcounts_count")]
+        public int BeatmapPlaycountsCount;
+
         [JsonProperty]
         private string[] playstyle
         {
diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj
index 8f0cc58594..405fb1a6ca 100644
--- a/osu.Game/osu.Game.csproj
+++ b/osu.Game/osu.Game.csproj
@@ -26,7 +26,7 @@
     <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" />
     <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" />
     <PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
-    <PackageReference Include="ppy.osu.Framework" Version="2020.1110.0" />
+    <PackageReference Include="ppy.osu.Framework" Version="2020.1111.0" />
     <PackageReference Include="ppy.osu.Game.Resources" Version="2020.1030.0" />
     <PackageReference Include="Sentry" Version="2.1.6" />
     <PackageReference Include="SharpCompress" Version="0.26.0" />
diff --git a/osu.iOS.props b/osu.iOS.props
index f766e0ec03..099ecd8319 100644
--- a/osu.iOS.props
+++ b/osu.iOS.props
@@ -70,7 +70,7 @@
     <Reference Include="System.Net.Http" />
   </ItemGroup>
   <ItemGroup Label="Package References">
-    <PackageReference Include="ppy.osu.Framework.iOS" Version="2020.1110.0" />
+    <PackageReference Include="ppy.osu.Framework.iOS" Version="2020.1111.0" />
     <PackageReference Include="ppy.osu.Game.Resources" Version="2020.1030.0" />
   </ItemGroup>
   <!-- See https://github.com/dotnet/runtime/issues/35988 (can be removed after Xamarin uses net5.0 / net6.0) -->
@@ -88,7 +88,7 @@
     <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" />
     <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" />
     <PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
-    <PackageReference Include="ppy.osu.Framework" Version="2020.1110.0" />
+    <PackageReference Include="ppy.osu.Framework" Version="2020.1111.0" />
     <PackageReference Include="SharpCompress" Version="0.26.0" />
     <PackageReference Include="NUnit" Version="3.12.0" />
     <PackageReference Include="SharpRaven" Version="2.4.0" />