diff --git a/osu.Android/OsuGameActivity.cs b/osu.Android/OsuGameActivity.cs
index 762a9c418d..2e5fa59d20 100644
--- a/osu.Android/OsuGameActivity.cs
+++ b/osu.Android/OsuGameActivity.cs
@@ -16,6 +16,11 @@ namespace osu.Android
protected override void OnCreate(Bundle savedInstanceState)
{
+ // The default current directory on android is '/'.
+ // On some devices '/' maps to the app data directory. On others it maps to the root of the internal storage.
+ // In order to have a consistent current directory on all devices the full path of the app data directory is set as the current directory.
+ System.Environment.CurrentDirectory = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal);
+
base.OnCreate(savedInstanceState);
Window.AddFlags(WindowManagerFlags.Fullscreen);
diff --git a/osu.Game.Rulesets.Mania/Edit/ManiaSelectionHandler.cs b/osu.Game.Rulesets.Mania/Edit/ManiaSelectionHandler.cs
index f576c43e52..2fba0639da 100644
--- a/osu.Game.Rulesets.Mania/Edit/ManiaSelectionHandler.cs
+++ b/osu.Game.Rulesets.Mania/Edit/ManiaSelectionHandler.cs
@@ -65,24 +65,27 @@ namespace osu.Game.Rulesets.Mania.Edit
private void performDragMovement(MoveSelectionEvent moveEvent)
{
+ float delta = moveEvent.InstantDelta.Y;
+
+ // When scrolling downwards the anchor position is at the bottom of the screen, however the movement event assumes the anchor is at the top of the screen.
+ // This causes the delta to assume a positive hitobject position, and which can be corrected for by subtracting the parent height.
+ if (scrollingInfo.Direction.Value == ScrollingDirection.Down)
+ delta -= moveEvent.Blueprint.HitObject.Parent.DrawHeight;
+
foreach (var b in SelectedBlueprints)
{
var hitObject = b.HitObject;
-
var objectParent = (HitObjectContainer)hitObject.Parent;
- // Using the hitobject position is required since AdjustPosition can be invoked multiple times per frame
- // without the position having been updated by the parenting ScrollingHitObjectContainer
- hitObject.Y += moveEvent.InstantDelta.Y;
+ // StartTime could be used to adjust the position if only one movement event was received per frame.
+ // However this is not the case and ScrollingHitObjectContainer performs movement in UpdateAfterChildren() so the position must also be updated to be valid for further movement events
+ hitObject.Y += delta;
- float targetPosition;
+ float targetPosition = hitObject.Position.Y;
- // If we're scrolling downwards, a position of 0 is actually further away from the hit target
- // so we need to flip the vertical coordinate in the hitobject container's space
+ // The scrolling algorithm always assumes an anchor at the top of the screen, so the position must be flipped when scrolling downwards to reflect a top anchor
if (scrollingInfo.Direction.Value == ScrollingDirection.Down)
- targetPosition = -hitObject.Position.Y;
- else
- targetPosition = hitObject.Position.Y;
+ targetPosition = -targetPosition;
objectParent.Remove(hitObject);
diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleSelectionBlueprint.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleSelectionBlueprint.cs
index d4cdabdb07..cf24306623 100644
--- a/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleSelectionBlueprint.cs
+++ b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleSelectionBlueprint.cs
@@ -52,6 +52,13 @@ namespace osu.Game.Rulesets.Osu.Tests
AddAssert("blueprint positioned over hitobject", () => blueprint.CirclePiece.Position == hitCircle.Position);
}
+ [Test]
+ public void TestStackedHitObject()
+ {
+ AddStep("set stacking", () => hitCircle.StackHeight = 5);
+ AddAssert("blueprint positioned over hitobject", () => blueprint.CirclePiece.Position == hitCircle.StackedPosition);
+ }
+
private class TestBlueprint : HitCircleSelectionBlueprint
{
public new HitCirclePiece CirclePiece => base.CirclePiece;
diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/BlueprintPiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/BlueprintPiece.cs
index 95e926fdfa..b9c77d3f56 100644
--- a/osu.Game.Rulesets.Osu/Edit/Blueprints/BlueprintPiece.cs
+++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/BlueprintPiece.cs
@@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints
/// The to reference properties from.
public virtual void UpdateFrom(T hitObject)
{
- Position = hitObject.Position;
+ Position = hitObject.StackedPosition;
}
}
}
diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursor.cs b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursor.cs
index 41a02deaca..0aa8661fd3 100644
--- a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursor.cs
+++ b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursor.cs
@@ -2,14 +2,11 @@
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Allocation;
-using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes;
-using osu.Game.Beatmaps;
-using osu.Game.Configuration;
using osu.Game.Rulesets.Osu.Skinning;
using osu.Game.Skinning;
using osuTK;
@@ -23,12 +20,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
private bool cursorExpand;
- private Bindable cursorScale;
- private Bindable autoCursorScale;
- private readonly IBindable beatmap = new Bindable();
-
private Container expandTarget;
- private Drawable scaleTarget;
public OsuCursor()
{
@@ -43,43 +35,19 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
}
[BackgroundDependencyLoader]
- private void load(OsuConfigManager config, IBindable beatmap)
+ private void load()
{
InternalChild = expandTarget = new Container
{
RelativeSizeAxes = Axes.Both,
Origin = Anchor.Centre,
Anchor = Anchor.Centre,
- Child = scaleTarget = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.Cursor), _ => new DefaultCursor(), confineMode: ConfineMode.NoScaling)
+ Child = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.Cursor), _ => new DefaultCursor(), confineMode: ConfineMode.NoScaling)
{
Origin = Anchor.Centre,
Anchor = Anchor.Centre,
}
};
-
- this.beatmap.BindTo(beatmap);
- this.beatmap.ValueChanged += _ => calculateScale();
-
- cursorScale = config.GetBindable(OsuSetting.GameplayCursorSize);
- cursorScale.ValueChanged += _ => calculateScale();
-
- autoCursorScale = config.GetBindable(OsuSetting.AutoCursorSize);
- autoCursorScale.ValueChanged += _ => calculateScale();
-
- calculateScale();
- }
-
- private void calculateScale()
- {
- float scale = cursorScale.Value;
-
- if (autoCursorScale.Value && beatmap.Value != null)
- {
- // if we have a beatmap available, let's get its circle size to figure out an automatic cursor scale modifier.
- scale *= 1f - 0.7f * (1f + beatmap.Value.BeatmapInfo.BaseDifficulty.CircleSize - BeatmapDifficulty.DEFAULT_DIFFICULTY) / BeatmapDifficulty.DEFAULT_DIFFICULTY;
- }
-
- scaleTarget.Scale = new Vector2(scale);
}
private const float pressed_scale = 1.2f;
diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs
index 6dbdf0114d..6433ced624 100644
--- a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs
+++ b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs
@@ -8,6 +8,8 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Textures;
using osu.Framework.Input.Bindings;
+using osu.Game.Beatmaps;
+using osu.Game.Configuration;
using osu.Game.Rulesets.Osu.Configuration;
using osu.Game.Rulesets.UI;
using osu.Game.Skinning;
@@ -27,6 +29,11 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
private readonly Drawable cursorTrail;
+ public Bindable CursorScale;
+ private Bindable userCursorScale;
+ private Bindable autoCursorScale;
+ private readonly IBindable beatmap = new Bindable();
+
public OsuCursorContainer()
{
InternalChild = fadeContainer = new Container
@@ -37,9 +44,36 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
}
[BackgroundDependencyLoader(true)]
- private void load(OsuRulesetConfigManager config)
+ private void load(OsuConfigManager config, OsuRulesetConfigManager rulesetConfig, IBindable beatmap)
{
- config?.BindWith(OsuRulesetSetting.ShowCursorTrail, showTrail);
+ rulesetConfig?.BindWith(OsuRulesetSetting.ShowCursorTrail, showTrail);
+
+ this.beatmap.BindTo(beatmap);
+ this.beatmap.ValueChanged += _ => calculateScale();
+
+ userCursorScale = config.GetBindable(OsuSetting.GameplayCursorSize);
+ userCursorScale.ValueChanged += _ => calculateScale();
+
+ autoCursorScale = config.GetBindable(OsuSetting.AutoCursorSize);
+ autoCursorScale.ValueChanged += _ => calculateScale();
+
+ CursorScale = new Bindable();
+ CursorScale.ValueChanged += e => ActiveCursor.Scale = cursorTrail.Scale = new Vector2(e.NewValue);
+
+ calculateScale();
+ }
+
+ private void calculateScale()
+ {
+ float scale = userCursorScale.Value;
+
+ if (autoCursorScale.Value && beatmap.Value != null)
+ {
+ // if we have a beatmap available, let's get its circle size to figure out an automatic cursor scale modifier.
+ scale *= 1f - 0.7f * (1f + beatmap.Value.BeatmapInfo.BaseDifficulty.CircleSize - BeatmapDifficulty.DEFAULT_DIFFICULTY) / BeatmapDifficulty.DEFAULT_DIFFICULTY;
+ }
+
+ CursorScale.Value = scale;
}
protected override void LoadComplete()
@@ -95,13 +129,13 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
protected override void PopIn()
{
fadeContainer.FadeTo(1, 300, Easing.OutQuint);
- ActiveCursor.ScaleTo(1, 400, Easing.OutQuint);
+ ActiveCursor.ScaleTo(CursorScale.Value, 400, Easing.OutQuint);
}
protected override void PopOut()
{
fadeContainer.FadeTo(0.05f, 450, Easing.OutQuint);
- ActiveCursor.ScaleTo(0.8f, 450, Easing.OutQuint);
+ ActiveCursor.ScaleTo(CursorScale.Value * 0.8f, 450, Easing.OutQuint);
}
private class DefaultCursorTrail : CursorTrail
diff --git a/osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs b/osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs
index 9e5df0d6b1..8347d255fa 100644
--- a/osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs
+++ b/osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs
@@ -1,15 +1,15 @@
-// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System;
using osu.Framework.Allocation;
+using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Input.Bindings;
using osu.Framework.Input.Events;
using osu.Game.Rulesets.Osu.UI.Cursor;
-using osu.Game.Rulesets.UI;
using osu.Game.Screens.Play;
using osuTK;
using osuTK.Graphics;
@@ -18,9 +18,11 @@ namespace osu.Game.Rulesets.Osu.UI
{
public class OsuResumeOverlay : ResumeOverlay
{
+ private Container cursorScaleContainer;
private OsuClickToResumeCursor clickToResumeCursor;
- private GameplayCursorContainer localCursorContainer;
+ private OsuCursorContainer localCursorContainer;
+ private Bindable localCursorScale;
public override CursorContainer LocalCursor => State.Value == Visibility.Visible ? localCursorContainer : null;
@@ -29,22 +31,35 @@ namespace osu.Game.Rulesets.Osu.UI
[BackgroundDependencyLoader]
private void load()
{
- Add(clickToResumeCursor = new OsuClickToResumeCursor { ResumeRequested = Resume });
+ Add(cursorScaleContainer = new Container
+ {
+ RelativePositionAxes = Axes.Both,
+ Child = clickToResumeCursor = new OsuClickToResumeCursor { ResumeRequested = Resume }
+ });
}
public override void Show()
{
base.Show();
- clickToResumeCursor.ShowAt(GameplayCursor.ActiveCursor.Position);
+ GameplayCursor.ActiveCursor.Hide();
+ cursorScaleContainer.MoveTo(GameplayCursor.ActiveCursor.Position);
+ clickToResumeCursor.Appear();
if (localCursorContainer == null)
+ {
Add(localCursorContainer = new OsuCursorContainer());
+
+ localCursorScale = new Bindable();
+ localCursorScale.BindTo(localCursorContainer.CursorScale);
+ localCursorScale.BindValueChanged(scale => cursorScaleContainer.Scale = new Vector2(scale.NewValue), true);
+ }
}
public override void Hide()
{
localCursorContainer?.Expire();
localCursorContainer = null;
+ GameplayCursor.ActiveCursor.Show();
base.Hide();
}
@@ -82,7 +97,7 @@ namespace osu.Game.Rulesets.Osu.UI
case OsuAction.RightButton:
if (!IsHovered) return false;
- this.ScaleTo(new Vector2(2), TRANSITION_TIME, Easing.OutQuint);
+ this.ScaleTo(2, TRANSITION_TIME, Easing.OutQuint);
ResumeRequested?.Invoke();
return true;
@@ -93,11 +108,10 @@ namespace osu.Game.Rulesets.Osu.UI
public bool OnReleased(OsuAction action) => false;
- public void ShowAt(Vector2 activeCursorPosition) => Schedule(() =>
+ public void Appear() => Schedule(() =>
{
updateColour();
- this.MoveTo(activeCursorPosition);
- this.ScaleTo(new Vector2(4)).Then().ScaleTo(Vector2.One, 1000, Easing.OutQuint);
+ this.ScaleTo(4).Then().ScaleTo(1, 1000, Easing.OutQuint);
});
private void updateColour()
diff --git a/osu.Game.Tests/Gameplay/TestSceneHitObjectAccentColour.cs b/osu.Game.Tests/Gameplay/TestSceneHitObjectAccentColour.cs
new file mode 100644
index 0000000000..6d7159a825
--- /dev/null
+++ b/osu.Game.Tests/Gameplay/TestSceneHitObjectAccentColour.cs
@@ -0,0 +1,143 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System;
+using System.Collections.Generic;
+using NUnit.Framework;
+using osu.Framework.Audio.Sample;
+using osu.Framework.Bindables;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Textures;
+using osu.Framework.Testing;
+using osu.Game.Audio;
+using osu.Game.Rulesets.Objects;
+using osu.Game.Rulesets.Objects.Drawables;
+using osu.Game.Rulesets.Objects.Types;
+using osu.Game.Skinning;
+using osu.Game.Tests.Visual;
+using osuTK.Graphics;
+
+namespace osu.Game.Tests.Gameplay
+{
+ [HeadlessTest]
+ public class TestSceneHitObjectAccentColour : OsuTestScene
+ {
+ private Container skinContainer;
+
+ [SetUp]
+ public void Setup() => Schedule(() => Child = skinContainer = new SkinProvidingContainer(new TestSkin()));
+
+ [Test]
+ public void TestChangeComboIndexBeforeLoad()
+ {
+ TestDrawableHitObject hitObject = null;
+
+ AddStep("set combo and add hitobject", () =>
+ {
+ hitObject = new TestDrawableHitObject();
+ hitObject.HitObject.ComboIndex = 1;
+
+ skinContainer.Add(hitObject);
+ });
+
+ AddAssert("combo colour is green", () => hitObject.AccentColour.Value == Color4.Green);
+ }
+
+ [Test]
+ public void TestChangeComboIndexDuringLoad()
+ {
+ TestDrawableHitObject hitObject = null;
+
+ AddStep("add hitobject and set combo", () =>
+ {
+ skinContainer.Add(hitObject = new TestDrawableHitObject());
+ hitObject.HitObject.ComboIndex = 1;
+ });
+
+ AddAssert("combo colour is green", () => hitObject.AccentColour.Value == Color4.Green);
+ }
+
+ [Test]
+ public void TestChangeComboIndexAfterLoad()
+ {
+ TestDrawableHitObject hitObject = null;
+
+ AddStep("add hitobject", () => skinContainer.Add(hitObject = new TestDrawableHitObject()));
+ AddAssert("combo colour is red", () => hitObject.AccentColour.Value == Color4.Red);
+
+ AddStep("change combo", () => hitObject.HitObject.ComboIndex = 1);
+ AddAssert("combo colour is green", () => hitObject.AccentColour.Value == Color4.Green);
+ }
+
+ private class TestDrawableHitObject : DrawableHitObject
+ {
+ public TestDrawableHitObject()
+ : base(new TestHitObjectWithCombo())
+ {
+ }
+ }
+
+ private class TestHitObjectWithCombo : HitObject, IHasComboInformation
+ {
+ public bool NewCombo { get; } = false;
+ public int ComboOffset { get; } = 0;
+
+ public Bindable IndexInCurrentComboBindable { get; } = new Bindable();
+
+ public int IndexInCurrentCombo
+ {
+ get => IndexInCurrentComboBindable.Value;
+ set => IndexInCurrentComboBindable.Value = value;
+ }
+
+ public Bindable ComboIndexBindable { get; } = new Bindable();
+
+ public int ComboIndex
+ {
+ get => ComboIndexBindable.Value;
+ set => ComboIndexBindable.Value = value;
+ }
+
+ public Bindable LastInComboBindable { get; } = new Bindable();
+
+ public bool LastInCombo
+ {
+ get => LastInComboBindable.Value;
+ set => LastInComboBindable.Value = value;
+ }
+ }
+
+ private class TestSkin : ISkin
+ {
+ public readonly List ComboColours = new List
+ {
+ Color4.Red,
+ Color4.Green
+ };
+
+ public Drawable GetDrawableComponent(ISkinComponent component) => throw new NotImplementedException();
+
+ public Texture GetTexture(string componentName) => throw new NotImplementedException();
+
+ public SampleChannel GetSample(ISampleInfo sampleInfo) => throw new NotImplementedException();
+
+ public IBindable GetConfig(TLookup lookup)
+ {
+ switch (lookup)
+ {
+ case GlobalSkinConfiguration global:
+ switch (global)
+ {
+ case GlobalSkinConfiguration.ComboColours:
+ return SkinUtils.As(new Bindable>(ComboColours));
+ }
+
+ break;
+ }
+
+ throw new NotImplementedException();
+ }
+ }
+ }
+}
diff --git a/osu.Game.Tests/NonVisual/BeatmapSetInfoEqualityTest.cs b/osu.Game.Tests/NonVisual/BeatmapSetInfoEqualityTest.cs
new file mode 100644
index 0000000000..42a3b4cf43
--- /dev/null
+++ b/osu.Game.Tests/NonVisual/BeatmapSetInfoEqualityTest.cs
@@ -0,0 +1,48 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using NUnit.Framework;
+using osu.Game.Beatmaps;
+
+namespace osu.Game.Tests.NonVisual
+{
+ [TestFixture]
+ public class BeatmapSetInfoEqualityTest
+ {
+ [Test]
+ public void TestOnlineWithOnline()
+ {
+ var ourInfo = new BeatmapSetInfo { OnlineBeatmapSetID = 123 };
+ var otherInfo = new BeatmapSetInfo { OnlineBeatmapSetID = 123 };
+
+ Assert.AreEqual(ourInfo, otherInfo);
+ }
+
+ [Test]
+ public void TestDatabasedWithDatabased()
+ {
+ var ourInfo = new BeatmapSetInfo { ID = 123 };
+ var otherInfo = new BeatmapSetInfo { ID = 123 };
+
+ Assert.AreEqual(ourInfo, otherInfo);
+ }
+
+ [Test]
+ public void TestDatabasedWithOnline()
+ {
+ var ourInfo = new BeatmapSetInfo { ID = 123, OnlineBeatmapSetID = 12 };
+ var otherInfo = new BeatmapSetInfo { OnlineBeatmapSetID = 12 };
+
+ Assert.AreEqual(ourInfo, otherInfo);
+ }
+
+ [Test]
+ public void TestCheckNullID()
+ {
+ var ourInfo = new BeatmapSetInfo { Status = BeatmapSetOnlineStatus.Loved };
+ var otherInfo = new BeatmapSetInfo { Status = BeatmapSetOnlineStatus.Approved };
+
+ Assert.AreNotEqual(ourInfo, otherInfo);
+ }
+ }
+}
diff --git a/osu.Game/Beatmaps/BeatmapSetInfo.cs b/osu.Game/Beatmaps/BeatmapSetInfo.cs
index 03bc7c7312..a8b83dca38 100644
--- a/osu.Game/Beatmaps/BeatmapSetInfo.cs
+++ b/osu.Game/Beatmaps/BeatmapSetInfo.cs
@@ -63,6 +63,21 @@ namespace osu.Game.Beatmaps
public bool Protected { get; set; }
- public bool Equals(BeatmapSetInfo other) => OnlineBeatmapSetID == other?.OnlineBeatmapSetID;
+ public bool Equals(BeatmapSetInfo other)
+ {
+ if (other == null)
+ return false;
+
+ if (ID != 0 && other.ID != 0)
+ return ID == other.ID;
+
+ if (OnlineBeatmapSetID.HasValue && other.OnlineBeatmapSetID.HasValue)
+ return OnlineBeatmapSetID == other.OnlineBeatmapSetID;
+
+ if (!string.IsNullOrEmpty(Hash) && !string.IsNullOrEmpty(other.Hash))
+ return Hash == other.Hash;
+
+ return ReferenceEquals(this, other);
+ }
}
}
diff --git a/osu.Game/Overlays/AccountCreation/ScreenWarning.cs b/osu.Game/Overlays/AccountCreation/ScreenWarning.cs
index be417f4aac..f91d2e3323 100644
--- a/osu.Game/Overlays/AccountCreation/ScreenWarning.cs
+++ b/osu.Game/Overlays/AccountCreation/ScreenWarning.cs
@@ -121,7 +121,7 @@ namespace osu.Game.Overlays.AccountCreation
multiAccountExplanationText.AddText("? osu! has a policy of ");
multiAccountExplanationText.AddText("one account per person!", cp => cp.Colour = colours.Yellow);
multiAccountExplanationText.AddText(" Please be aware that creating more than one account per person may result in ");
- multiAccountExplanationText.AddText("permanent deactivation of accounts", cp => cp.Colour = colours.Yellow);
+ multiAccountExplanationText.AddText("permanent deactivation of accounts", cp => cp.Colour = colours.Yellow);
multiAccountExplanationText.AddText(".");
furtherAssistance.AddText("Need further assistance? Contact us via our ");
diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs
index c769ccae41..51155ce3fd 100644
--- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs
+++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs
@@ -64,7 +64,8 @@ namespace osu.Game.Rulesets.Edit
{
drawableRulesetWrapper = new DrawableEditRulesetWrapper(CreateDrawableRuleset(Ruleset, workingBeatmap, Array.Empty()))
{
- Clock = framedClock
+ Clock = framedClock,
+ ProcessCustomClock = false
};
}
catch (Exception e)
diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs
index 0a8648516e..19bb95d36f 100644
--- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs
+++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs
@@ -135,7 +135,7 @@ namespace osu.Game.Rulesets.Objects.Drawables
if (HitObject is IHasComboInformation combo)
{
comboIndexBindable = combo.ComboIndexBindable.GetBoundCopy();
- comboIndexBindable.BindValueChanged(_ => updateAccentColour());
+ comboIndexBindable.BindValueChanged(_ => updateAccentColour(), true);
}
updateState(ArmedState.Idle, true);
@@ -161,11 +161,7 @@ namespace osu.Game.Rulesets.Objects.Drawables
{
var drawableNested = CreateNestedHitObject(h) ?? throw new InvalidOperationException($"{nameof(CreateNestedHitObject)} returned null for {h.GetType().ReadableName()}.");
- drawableNested.OnNewResult += (d, r) => OnNewResult?.Invoke(d, r);
- drawableNested.OnRevertResult += (d, r) => OnRevertResult?.Invoke(d, r);
- drawableNested.ApplyCustomUpdateState += (d, j) => ApplyCustomUpdateState?.Invoke(d, j);
-
- nestedHitObjects.Value.Add(drawableNested);
+ addNested(drawableNested);
AddNestedHitObject(drawableNested);
}
}
@@ -183,14 +179,7 @@ namespace osu.Game.Rulesets.Objects.Drawables
///
///
[Obsolete("Use AddNestedHitObject() / ClearNestedHitObjects() / CreateNestedHitObject() instead.")] // can be removed 20200417
- protected virtual void AddNested(DrawableHitObject h)
- {
- h.OnNewResult += (d, r) => OnNewResult?.Invoke(d, r);
- h.OnRevertResult += (d, r) => OnRevertResult?.Invoke(d, r);
- h.ApplyCustomUpdateState += (d, j) => ApplyCustomUpdateState?.Invoke(d, j);
-
- nestedHitObjects.Value.Add(h);
- }
+ protected virtual void AddNested(DrawableHitObject h) => addNested(h);
///
/// Invoked by the base to remove all previously-added nested s.
@@ -206,6 +195,17 @@ namespace osu.Game.Rulesets.Objects.Drawables
/// The drawable representation for .
protected virtual DrawableHitObject CreateNestedHitObject(HitObject hitObject) => null;
+ private void addNested(DrawableHitObject hitObject)
+ {
+ // Todo: Exists for legacy purposes, can be removed 20200417
+
+ hitObject.OnNewResult += (d, r) => OnNewResult?.Invoke(d, r);
+ hitObject.OnRevertResult += (d, r) => OnRevertResult?.Invoke(d, r);
+ hitObject.ApplyCustomUpdateState += (d, j) => ApplyCustomUpdateState?.Invoke(d, j);
+
+ nestedHitObjects.Value.Add(hitObject);
+ }
+
#region State / Transform Management
///
diff --git a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs
index 039e324e4b..bef608036b 100644
--- a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs
+++ b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs
@@ -124,20 +124,12 @@ namespace osu.Game.Screens.Edit.Compose.Components
if (blueprint == null)
return;
- if (hitObject.IsLoaded)
- addBlueprint();
- else
- hitObject.OnLoadComplete += _ => addBlueprint();
+ blueprint.Selected += onBlueprintSelected;
+ blueprint.Deselected += onBlueprintDeselected;
+ blueprint.SelectionRequested += onSelectionRequested;
+ blueprint.DragRequested += onDragRequested;
- void addBlueprint()
- {
- blueprint.Selected += onBlueprintSelected;
- blueprint.Deselected += onBlueprintDeselected;
- blueprint.SelectionRequested += onSelectionRequested;
- blueprint.DragRequested += onDragRequested;
-
- selectionBlueprints.Add(blueprint);
- }
+ selectionBlueprints.Add(blueprint);
}
private void removeBlueprintFor(DrawableHitObject hitObject) => removeBlueprintFor(hitObject.HitObject);
diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs
index 7f08c2f8b9..35408e4003 100644
--- a/osu.Game/Screens/Edit/Editor.cs
+++ b/osu.Game/Screens/Edit/Editor.cs
@@ -173,6 +173,12 @@ namespace osu.Game.Screens.Edit
bottomBackground.Colour = colours.Gray2;
}
+ protected override void Update()
+ {
+ base.Update();
+ clock.ProcessFrame();
+ }
+
protected override bool OnKeyDown(KeyDownEvent e)
{
switch (e.Key)