diff --git a/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform/EmptyFreeformRuleset.cs b/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform/EmptyFreeformRuleset.cs
index 00754c6346..1e88f87f09 100644
--- a/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform/EmptyFreeformRuleset.cs
+++ b/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform/EmptyFreeformRuleset.cs
@@ -77,5 +77,8 @@ namespace osu.Game.Rulesets.EmptyFreeform
};
}
}
+
+ // Leave this line intact. It will bake the correct version into the ruleset on each build/release.
+ public override string RulesetAPIVersionSupported => CURRENT_RULESET_API_VERSION;
}
}
diff --git a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/PippidonRuleset.cs b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/PippidonRuleset.cs
index 0522840e9e..2f6ba0dda6 100644
--- a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/PippidonRuleset.cs
+++ b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/PippidonRuleset.cs
@@ -49,5 +49,8 @@ namespace osu.Game.Rulesets.Pippidon
};
public override Drawable CreateIcon() => new PippidonRulesetIcon(this);
+
+ // Leave this line intact. It will bake the correct version into the ruleset on each build/release.
+ public override string RulesetAPIVersionSupported => CURRENT_RULESET_API_VERSION;
}
}
diff --git a/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling/EmptyScrollingRuleset.cs b/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling/EmptyScrollingRuleset.cs
index c8f0c07724..a32586c414 100644
--- a/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling/EmptyScrollingRuleset.cs
+++ b/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling/EmptyScrollingRuleset.cs
@@ -54,5 +54,8 @@ namespace osu.Game.Rulesets.EmptyScrolling
Text = ShortName[0].ToString(),
Font = OsuFont.Default.With(size: 18),
};
+
+ // Leave this line intact. It will bake the correct version into the ruleset on each build/release.
+ public override string RulesetAPIVersionSupported => CURRENT_RULESET_API_VERSION;
}
}
diff --git a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/PippidonRuleset.cs b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/PippidonRuleset.cs
index 89246373ee..bde530feb8 100644
--- a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/PippidonRuleset.cs
+++ b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/PippidonRuleset.cs
@@ -46,5 +46,8 @@ namespace osu.Game.Rulesets.Pippidon
};
public override Drawable CreateIcon() => new PippidonRulesetIcon(this);
+
+ // Leave this line intact. It will bake the correct version into the ruleset on each build/release.
+ public override string RulesetAPIVersionSupported => CURRENT_RULESET_API_VERSION;
}
}
diff --git a/osu.Android.props b/osu.Android.props
index bff3627af7..85857771a5 100644
--- a/osu.Android.props
+++ b/osu.Android.props
@@ -51,7 +51,7 @@
-
+
diff --git a/osu.Desktop/Security/ElevatedPrivilegesChecker.cs b/osu.Desktop/Security/ElevatedPrivilegesChecker.cs
index 9959b24b35..cc4337fb02 100644
--- a/osu.Desktop/Security/ElevatedPrivilegesChecker.cs
+++ b/osu.Desktop/Security/ElevatedPrivilegesChecker.cs
@@ -76,7 +76,7 @@ namespace osu.Desktop.Security
private void load(OsuColour colours)
{
Icon = FontAwesome.Solid.ShieldAlt;
- IconBackground.Colour = colours.YellowDark;
+ IconContent.Colour = colours.YellowDark;
}
}
}
diff --git a/osu.Game.Rulesets.Catch.Tests/Editor/CatchSelectionBlueprintTestScene.cs b/osu.Game.Rulesets.Catch.Tests/Editor/CatchSelectionBlueprintTestScene.cs
index ea17fa400c..60fb31d1e0 100644
--- a/osu.Game.Rulesets.Catch.Tests/Editor/CatchSelectionBlueprintTestScene.cs
+++ b/osu.Game.Rulesets.Catch.Tests/Editor/CatchSelectionBlueprintTestScene.cs
@@ -70,10 +70,17 @@ namespace osu.Game.Rulesets.Catch.Tests.Editor
[Cached]
private readonly BindableBeatDivisor beatDivisor;
+ protected override Container Content { get; } = new Container { RelativeSizeAxes = Axes.Both };
+
public EditorBeatmapDependencyContainer(IBeatmap beatmap, BindableBeatDivisor beatDivisor)
{
- editorClock = new EditorClock(beatmap, beatDivisor);
this.beatDivisor = beatDivisor;
+
+ InternalChildren = new Drawable[]
+ {
+ editorClock = new EditorClock(beatmap, beatDivisor),
+ Content,
+ };
}
}
}
diff --git a/osu.Game.Rulesets.Catch/CatchRuleset.cs b/osu.Game.Rulesets.Catch/CatchRuleset.cs
index ed151855b1..321399c597 100644
--- a/osu.Game.Rulesets.Catch/CatchRuleset.cs
+++ b/osu.Game.Rulesets.Catch/CatchRuleset.cs
@@ -3,30 +3,30 @@
#nullable disable
-using osu.Game.Beatmaps;
-using osu.Game.Graphics;
-using osu.Game.Rulesets.Catch.Mods;
-using osu.Game.Rulesets.Catch.UI;
-using osu.Game.Rulesets.Mods;
-using osu.Game.Rulesets.UI;
+using System;
using System.Collections.Generic;
+using osu.Framework.Extensions.EnumExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Input.Bindings;
-using osu.Game.Rulesets.Catch.Replays;
-using osu.Game.Rulesets.Replays.Types;
+using osu.Framework.Localisation;
+using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Legacy;
+using osu.Game.Graphics;
using osu.Game.Rulesets.Catch.Beatmaps;
using osu.Game.Rulesets.Catch.Difficulty;
-using osu.Game.Rulesets.Catch.Scoring;
-using osu.Game.Rulesets.Difficulty;
-using osu.Game.Rulesets.Scoring;
-using System;
-using osu.Framework.Extensions.EnumExtensions;
-using osu.Framework.Localisation;
using osu.Game.Rulesets.Catch.Edit;
+using osu.Game.Rulesets.Catch.Mods;
+using osu.Game.Rulesets.Catch.Replays;
+using osu.Game.Rulesets.Catch.Scoring;
using osu.Game.Rulesets.Catch.Skinning.Legacy;
+using osu.Game.Rulesets.Catch.UI;
+using osu.Game.Rulesets.Difficulty;
using osu.Game.Rulesets.Edit;
+using osu.Game.Rulesets.Mods;
+using osu.Game.Rulesets.Replays.Types;
+using osu.Game.Rulesets.Scoring;
+using osu.Game.Rulesets.UI;
using osu.Game.Skinning;
namespace osu.Game.Rulesets.Catch
@@ -43,6 +43,8 @@ namespace osu.Game.Rulesets.Catch
public const string SHORT_NAME = "fruits";
+ public override string RulesetAPIVersionSupported => CURRENT_RULESET_API_VERSION;
+
public override IEnumerable GetDefaultKeyBindings(int variant = 0) => new[]
{
new KeyBinding(InputKey.Z, CatchAction.MoveLeft),
diff --git a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaComposeScreen.cs b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaComposeScreen.cs
index 15b38b39ba..0354228cca 100644
--- a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaComposeScreen.cs
+++ b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaComposeScreen.cs
@@ -10,6 +10,7 @@ using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Testing;
+using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Database;
using osu.Game.Overlays;
using osu.Game.Rulesets.Edit;
@@ -34,10 +35,14 @@ namespace osu.Game.Rulesets.Mania.Tests.Editor
{
AddStep("setup compose screen", () =>
{
- var editorBeatmap = new EditorBeatmap(new ManiaBeatmap(new StageDefinition { Columns = 4 })
+ var beatmap = new ManiaBeatmap(new StageDefinition { Columns = 4 })
{
BeatmapInfo = { Ruleset = new ManiaRuleset().RulesetInfo },
- });
+ };
+
+ beatmap.ControlPointInfo.Add(0, new TimingControlPoint());
+
+ var editorBeatmap = new EditorBeatmap(beatmap, new LegacyBeatmapSkin(beatmap.BeatmapInfo, null));
Beatmap.Value = CreateWorkingBeatmap(editorBeatmap.PlayableBeatmap);
@@ -50,7 +55,11 @@ namespace osu.Game.Rulesets.Mania.Tests.Editor
(typeof(IBeatSnapProvider), editorBeatmap),
(typeof(OverlayColourProvider), new OverlayColourProvider(OverlayColourScheme.Green)),
},
- Child = new ComposeScreen { State = { Value = Visibility.Visible } },
+ Children = new Drawable[]
+ {
+ editorBeatmap,
+ new ComposeScreen { State = { Value = Visibility.Visible } },
+ }
};
});
diff --git a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaHitObjectComposer.cs b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaHitObjectComposer.cs
index 4ad27348fc..fcc9e2e6c3 100644
--- a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaHitObjectComposer.cs
+++ b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaHitObjectComposer.cs
@@ -35,7 +35,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Editor
public void Setup() => Schedule(() =>
{
BeatDivisor.Value = 8;
- Clock.Seek(0);
+ EditorClock.Seek(0);
Child = composer = new TestComposer { RelativeSizeAxes = Axes.Both };
});
@@ -53,7 +53,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Editor
{
lastObject = this.ChildrenOfType().Single(d => d.HitObject == composer.EditorBeatmap.HitObjects.Last());
originalTime = lastObject.HitObject.StartTime;
- Clock.Seek(composer.EditorBeatmap.HitObjects.Last().StartTime);
+ EditorClock.Seek(composer.EditorBeatmap.HitObjects.Last().StartTime);
});
AddStep("select all objects", () => composer.EditorBeatmap.SelectedHitObjects.AddRange(composer.EditorBeatmap.HitObjects));
@@ -90,7 +90,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Editor
{
lastObject = this.ChildrenOfType().Single(d => d.HitObject == composer.EditorBeatmap.HitObjects.Last());
originalTime = lastObject.HitObject.StartTime;
- Clock.Seek(composer.EditorBeatmap.HitObjects.Last().StartTime);
+ EditorClock.Seek(composer.EditorBeatmap.HitObjects.Last().StartTime);
});
AddStep("select all objects", () => composer.EditorBeatmap.SelectedHitObjects.AddRange(composer.EditorBeatmap.HitObjects));
@@ -125,7 +125,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Editor
AddStep("seek to last object", () =>
{
lastObject = this.ChildrenOfType().Single(d => d.HitObject == composer.EditorBeatmap.HitObjects.Last());
- Clock.Seek(composer.EditorBeatmap.HitObjects.Last().StartTime);
+ EditorClock.Seek(composer.EditorBeatmap.HitObjects.Last().StartTime);
});
AddStep("select all objects", () => composer.EditorBeatmap.SelectedHitObjects.AddRange(composer.EditorBeatmap.HitObjects));
diff --git a/osu.Game.Rulesets.Mania/ManiaRuleset.cs b/osu.Game.Rulesets.Mania/ManiaRuleset.cs
index ac6060ceed..813e2c461a 100644
--- a/osu.Game.Rulesets.Mania/ManiaRuleset.cs
+++ b/osu.Game.Rulesets.Mania/ManiaRuleset.cs
@@ -4,11 +4,6 @@
#nullable disable
using System;
-using osu.Game.Beatmaps;
-using osu.Game.Rulesets.Mania.Mods;
-using osu.Game.Rulesets.Mania.UI;
-using osu.Game.Rulesets.Mods;
-using osu.Game.Rulesets.UI;
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Extensions.EnumExtensions;
@@ -16,11 +11,10 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Input.Bindings;
using osu.Framework.Localisation;
-using osu.Game.Graphics;
-using osu.Game.Rulesets.Mania.Replays;
-using osu.Game.Rulesets.Replays.Types;
+using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Legacy;
using osu.Game.Configuration;
+using osu.Game.Graphics;
using osu.Game.Overlays.Settings;
using osu.Game.Rulesets.Configuration;
using osu.Game.Rulesets.Difficulty;
@@ -31,13 +25,19 @@ using osu.Game.Rulesets.Mania.Configuration;
using osu.Game.Rulesets.Mania.Difficulty;
using osu.Game.Rulesets.Mania.Edit;
using osu.Game.Rulesets.Mania.Edit.Setup;
+using osu.Game.Rulesets.Mania.Mods;
+using osu.Game.Rulesets.Mania.Replays;
using osu.Game.Rulesets.Mania.Scoring;
using osu.Game.Rulesets.Mania.Skinning.Legacy;
+using osu.Game.Rulesets.Mania.UI;
+using osu.Game.Rulesets.Mods;
+using osu.Game.Rulesets.Replays.Types;
using osu.Game.Rulesets.Scoring;
-using osu.Game.Skinning;
+using osu.Game.Rulesets.UI;
using osu.Game.Scoring;
using osu.Game.Screens.Edit.Setup;
using osu.Game.Screens.Ranking.Statistics;
+using osu.Game.Skinning;
namespace osu.Game.Rulesets.Mania
{
@@ -60,6 +60,8 @@ namespace osu.Game.Rulesets.Mania
public const string SHORT_NAME = "mania";
+ public override string RulesetAPIVersionSupported => CURRENT_RULESET_API_VERSION;
+
public override HitObjectComposer CreateHitObjectComposer() => new ManiaHitObjectComposer(this);
public override ISkin CreateLegacySkinProvider(ISkin skin, IBeatmap beatmap) => new ManiaLegacySkinTransformer(skin, beatmap);
diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneObjectMerging.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneObjectMerging.cs
index cdb2a7fe77..5c5384e0b7 100644
--- a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneObjectMerging.cs
+++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneObjectMerging.cs
@@ -3,9 +3,11 @@
using System.Linq;
using NUnit.Framework;
+using osu.Framework.Testing;
using osu.Framework.Utils;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Types;
+using osu.Game.Rulesets.Osu.Edit;
using osu.Game.Rulesets.Osu.Objects;
using osuTK;
using osuTK.Input;
@@ -14,6 +16,8 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor
{
public class TestSceneObjectMerging : TestSceneOsuEditor
{
+ private OsuSelectionHandler selectionHandler => Editor.ChildrenOfType().First();
+
[Test]
public void TestSimpleMerge()
{
@@ -29,6 +33,9 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor
EditorBeatmap.SelectedHitObjects.Add(circle2);
});
+ moveMouseToHitObject(1);
+ AddAssert("merge option available", () => selectionHandler.ContextMenuItems.Any(o => o.Text.Value == "Merge selection"));
+
mergeSelection();
AddAssert("slider created", () => circle1 is not null && circle2 is not null && sliderCreatedFor(
@@ -174,6 +181,57 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor
AddAssert("spinner not merged", () => EditorBeatmap.HitObjects.Contains(spinner));
}
+ [Test]
+ public void TestIllegalMerge()
+ {
+ HitCircle? circle1 = null;
+ HitCircle? circle2 = null;
+
+ AddStep("add two circles on the same position", () =>
+ {
+ circle1 = new HitCircle();
+ circle2 = new HitCircle { Position = circle1.Position + Vector2.UnitX };
+ EditorClock.Seek(0);
+ EditorBeatmap.Add(circle1);
+ EditorBeatmap.Add(circle2);
+ EditorBeatmap.SelectedHitObjects.Add(circle1);
+ EditorBeatmap.SelectedHitObjects.Add(circle2);
+ });
+
+ moveMouseToHitObject(1);
+ AddAssert("merge option not available", () => selectionHandler.ContextMenuItems.Length > 0 && selectionHandler.ContextMenuItems.All(o => o.Text.Value != "Merge selection"));
+ mergeSelection();
+ AddAssert("circles not merged", () => circle1 is not null && circle2 is not null
+ && EditorBeatmap.HitObjects.Contains(circle1) && EditorBeatmap.HitObjects.Contains(circle2));
+ }
+
+ [Test]
+ public void TestSameStartTimeMerge()
+ {
+ HitCircle? circle1 = null;
+ HitCircle? circle2 = null;
+
+ AddStep("add two circles at the same time", () =>
+ {
+ circle1 = new HitCircle();
+ circle2 = new HitCircle { Position = circle1.Position + 100 * Vector2.UnitX };
+ EditorClock.Seek(0);
+ EditorBeatmap.Add(circle1);
+ EditorBeatmap.Add(circle2);
+ EditorBeatmap.SelectedHitObjects.Add(circle1);
+ EditorBeatmap.SelectedHitObjects.Add(circle2);
+ });
+
+ moveMouseToHitObject(1);
+ AddAssert("merge option available", () => selectionHandler.ContextMenuItems.Any(o => o.Text.Value == "Merge selection"));
+
+ mergeSelection();
+
+ AddAssert("slider created", () => circle1 is not null && circle2 is not null && sliderCreatedFor(
+ (pos: circle1.Position, pathType: PathType.Linear),
+ (pos: circle2.Position, pathType: null)));
+ }
+
private void mergeSelection()
{
AddStep("merge selection", () =>
@@ -225,5 +283,17 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor
return mergedSlider.Samples[0] is not null;
}
+
+ private void moveMouseToHitObject(int index)
+ {
+ AddStep($"hover mouse over hit object {index}", () =>
+ {
+ if (EditorBeatmap.HitObjects.Count <= index)
+ return;
+
+ Vector2 position = ((OsuHitObject)EditorBeatmap.HitObjects[index]).Position;
+ InputManager.MoveMouseTo(selectionHandler.ToScreenSpace(position));
+ });
+ }
}
}
diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuDistanceSnapGrid.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuDistanceSnapGrid.cs
index e54ce45ccc..c102678e00 100644
--- a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuDistanceSnapGrid.cs
+++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuDistanceSnapGrid.cs
@@ -59,10 +59,9 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor
}
});
- editorClock = new EditorClock(editorBeatmap);
-
base.Content.Children = new Drawable[]
{
+ editorClock = new EditorClock(editorBeatmap),
snapProvider,
Content
};
diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs
index fcf4179a3b..2ba856d014 100644
--- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs
+++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs
@@ -18,11 +18,14 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators
private const double min_velocity = 0.5;
private const double slider_multiplier = 1.3;
+ private const double min_angle_multiplier = 0.2;
+
///
/// Evaluates the difficulty of memorising and hitting an object, based on:
///
/// - distance between a number of previous objects and the current object,
/// - the visual opacity of the current object,
+ /// - the angle made by the current object,
/// - length and speed of the current object (for sliders),
/// - and whether the hidden mod is enabled.
///
@@ -43,6 +46,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators
OsuDifficultyHitObject lastObj = osuCurrent;
+ double angleRepeatCount = 0.0;
+
// This is iterating backwards in time from the current object.
for (int i = 0; i < Math.Min(current.Index, 10); i++)
{
@@ -66,6 +71,13 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators
double opacityBonus = 1.0 + max_opacity_bonus * (1.0 - osuCurrent.OpacityAt(currentHitObject.StartTime, hidden));
result += stackNerf * opacityBonus * scalingFactor * jumpDistance / cumulativeStrainTime;
+
+ if (currentObj.Angle != null && osuCurrent.Angle != null)
+ {
+ // Objects further back in time should count less for the nerf.
+ if (Math.Abs(currentObj.Angle.Value - osuCurrent.Angle.Value) < 0.02)
+ angleRepeatCount += Math.Max(1.0 - 0.1 * i, 0.0);
+ }
}
lastObj = currentObj;
@@ -77,6 +89,9 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators
if (hidden)
result *= 1.0 + hidden_bonus;
+ // Nerf patterns with repeated angles.
+ result *= min_angle_multiplier + (1.0 - min_angle_multiplier) / (angleRepeatCount + 1.0);
+
double sliderBonus = 0.0;
if (osuCurrent.BaseObject is Slider osuSlider)
diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs
index 84ef109598..40448c444c 100644
--- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs
+++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs
@@ -26,7 +26,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills
hasHiddenMod = mods.Any(m => m is OsuModHidden);
}
- private double skillMultiplier => 0.05;
+ private double skillMultiplier => 0.052;
private double strainDecayBase => 0.15;
private double currentStrain;
diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs
index a156726f94..c39d61020c 100644
--- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs
+++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs
@@ -64,7 +64,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills
if (maxStrain == 0)
return 0;
- return objectStrains.Aggregate((total, next) => total + (1.0 / (1.0 + Math.Exp(-(next / maxStrain * 12.0 - 6.0)))));
+ return objectStrains.Sum(strain => 1.0 / (1.0 + Math.Exp(-(strain / maxStrain * 12.0 - 6.0))));
}
}
}
diff --git a/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs b/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs
index 2c5bbdb279..57d67acad5 100644
--- a/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs
+++ b/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs
@@ -358,10 +358,10 @@ namespace osu.Game.Rulesets.Osu.Edit
{
var mergeableObjects = selectedMergeableObjects;
- if (mergeableObjects.Length < 2)
+ if (!canMerge(mergeableObjects))
return;
- ChangeHandler?.BeginChange();
+ EditorBeatmap.BeginChange();
// Have an initial slider object.
var firstHitObject = mergeableObjects[0];
@@ -437,7 +437,7 @@ namespace osu.Game.Rulesets.Osu.Edit
SelectedItems.Clear();
SelectedItems.Add(mergedHitObject);
- ChangeHandler?.EndChange();
+ EditorBeatmap.EndChange();
}
protected override IEnumerable
-
+