diff --git a/osu.Android.props b/osu.Android.props index 9a3d42d6b7..eaedcb7bc3 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,6 +52,6 @@ - + diff --git a/osu.Desktop/osu.Desktop.csproj b/osu.Desktop/osu.Desktop.csproj index adf9c452f6..8b8ad9f8af 100644 --- a/osu.Desktop/osu.Desktop.csproj +++ b/osu.Desktop/osu.Desktop.csproj @@ -29,7 +29,7 @@ - + diff --git a/osu.Game.Rulesets.Catch.Tests/CatchSkinColourDecodingTest.cs b/osu.Game.Rulesets.Catch.Tests/CatchSkinColourDecodingTest.cs index b570f090ca..e70def7f8b 100644 --- a/osu.Game.Rulesets.Catch.Tests/CatchSkinColourDecodingTest.cs +++ b/osu.Game.Rulesets.Catch.Tests/CatchSkinColourDecodingTest.cs @@ -4,6 +4,7 @@ using NUnit.Framework; using osu.Framework.IO.Stores; using osu.Game.Rulesets.Catch.Skinning; +using osu.Game.Rulesets.Catch.Skinning.Legacy; using osu.Game.Skinning; using osuTK.Graphics; diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs index 194a12a9b7..e8bb57cdf3 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs @@ -1,6 +1,7 @@ // 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 System.Linq; using NUnit.Framework; @@ -12,8 +13,12 @@ using osu.Framework.Testing; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Configuration; +using osu.Game.Rulesets.Catch.Judgements; using osu.Game.Rulesets.Catch.Objects; using osu.Game.Rulesets.Catch.Objects.Drawables; +using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Scoring; +using osu.Game.Skinning; using osu.Game.Tests.Visual; namespace osu.Game.Rulesets.Catch.Tests @@ -24,7 +29,7 @@ namespace osu.Game.Rulesets.Catch.Tests [Resolved] private OsuConfigManager config { get; set; } - private Container droppedObjectContainer; + private Container droppedObjectContainer; private TestCatcher catcher; @@ -37,7 +42,7 @@ namespace osu.Game.Rulesets.Catch.Tests }; var trailContainer = new Container(); - droppedObjectContainer = new Container(); + droppedObjectContainer = new Container(); catcher = new TestCatcher(trailContainer, droppedObjectContainer, difficulty); Child = new Container @@ -52,6 +57,50 @@ namespace osu.Game.Rulesets.Catch.Tests }; }); + [Test] + public void TestCatcherHyperStateReverted() + { + DrawableCatchHitObject drawableObject1 = null; + DrawableCatchHitObject drawableObject2 = null; + JudgementResult result1 = null; + JudgementResult result2 = null; + AddStep("catch hyper fruit", () => + { + attemptCatch(new Fruit { HyperDashTarget = new Fruit { X = 100 } }, out drawableObject1, out result1); + }); + AddStep("catch normal fruit", () => + { + attemptCatch(new Fruit(), out drawableObject2, out result2); + }); + AddStep("revert second result", () => + { + catcher.OnRevertResult(drawableObject2, result2); + }); + checkHyperDash(true); + AddStep("revert first result", () => + { + catcher.OnRevertResult(drawableObject1, result1); + }); + checkHyperDash(false); + } + + [Test] + public void TestCatcherAnimationStateReverted() + { + DrawableCatchHitObject drawableObject = null; + JudgementResult result = null; + AddStep("catch kiai fruit", () => + { + attemptCatch(new TestKiaiFruit(), out drawableObject, out result); + }); + checkState(CatcherAnimationState.Kiai); + AddStep("revert result", () => + { + catcher.OnRevertResult(drawableObject, result); + }); + checkState(CatcherAnimationState.Idle); + } + [Test] public void TestCatcherCatchWidth() { @@ -149,13 +198,22 @@ namespace osu.Game.Rulesets.Catch.Tests AddAssert("fruits are dropped", () => !catcher.CaughtObjects.Any() && droppedObjectContainer.Count == 10); } - [TestCase(true)] - [TestCase(false)] - public void TestHitLighting(bool enabled) + [Test] + public void TestHitLightingColour() { - AddStep($"{(enabled ? "enable" : "disable")} hit lighting", () => config.Set(OsuSetting.HitLighting, enabled)); + var fruitColour = SkinConfiguration.DefaultComboColours[1]; + AddStep("enable hit lighting", () => config.Set(OsuSetting.HitLighting, true)); AddStep("catch fruit", () => attemptCatch(new Fruit())); - AddAssert("check hit lighting", () => catcher.ChildrenOfType().Any() == enabled); + AddAssert("correct hit lighting colour", () => + catcher.ChildrenOfType().First()?.ObjectColour == fruitColour); + } + + [Test] + public void TestHitLightingDisabled() + { + AddStep("disable hit lighting", () => config.Set(OsuSetting.HitLighting, false)); + AddStep("catch fruit", () => attemptCatch(new Fruit())); + AddAssert("no hit lighting", () => !catcher.ChildrenOfType().Any()); } private void checkPlate(int count) => AddAssert($"{count} objects on the plate", () => catcher.CaughtObjects.Count() == count); @@ -166,17 +224,60 @@ namespace osu.Game.Rulesets.Catch.Tests private void attemptCatch(CatchHitObject hitObject, int count = 1) { - hitObject.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); - for (var i = 0; i < count; i++) - catcher.AttemptCatch(hitObject); + attemptCatch(hitObject, out _, out _); + } + + private void attemptCatch(CatchHitObject hitObject, out DrawableCatchHitObject drawableObject, out JudgementResult result) + { + hitObject.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); + drawableObject = createDrawableObject(hitObject); + result = createResult(hitObject); + applyResult(drawableObject, result); + } + + private void applyResult(DrawableCatchHitObject drawableObject, JudgementResult result) + { + // Load DHO to set colour of hit explosion correctly + Add(drawableObject); + drawableObject.OnLoadComplete += _ => + { + catcher.OnNewResult(drawableObject, result); + drawableObject.Expire(); + }; + } + + private JudgementResult createResult(CatchHitObject hitObject) + { + return new CatchJudgementResult(hitObject, hitObject.CreateJudgement()) + { + Type = catcher.CanCatch(hitObject) ? HitResult.Great : HitResult.Miss + }; + } + + private DrawableCatchHitObject createDrawableObject(CatchHitObject hitObject) + { + switch (hitObject) + { + case Banana banana: + return new DrawableBanana(banana); + + case Droplet droplet: + return new DrawableDroplet(droplet); + + case Fruit fruit: + return new DrawableFruit(fruit); + + default: + throw new ArgumentOutOfRangeException(nameof(hitObject)); + } } public class TestCatcher : Catcher { - public IEnumerable CaughtObjects => this.ChildrenOfType(); + public IEnumerable CaughtObjects => this.ChildrenOfType(); - public TestCatcher(Container trailsTarget, Container droppedObjectTarget, BeatmapDifficulty difficulty) + public TestCatcher(Container trailsTarget, Container droppedObjectTarget, BeatmapDifficulty difficulty) : base(trailsTarget, droppedObjectTarget, difficulty) { } diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneCatcherArea.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneCatcherArea.cs index 281ddc7eaa..31c285ef22 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneCatcherArea.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneCatcherArea.cs @@ -15,7 +15,6 @@ using osu.Game.Rulesets.Catch.Judgements; using osu.Game.Rulesets.Catch.Objects; using osu.Game.Rulesets.Catch.Objects.Drawables; using osu.Game.Rulesets.Catch.UI; -using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Scoring; namespace osu.Game.Rulesets.Catch.Tests @@ -58,10 +57,9 @@ namespace osu.Game.Rulesets.Catch.Tests Schedule(() => { - bool caught = area.AttemptCatch(fruit); - area.OnNewResult(drawable, new JudgementResult(fruit, new CatchJudgement()) + area.OnNewResult(drawable, new CatchJudgementResult(fruit, new CatchJudgement()) { - Type = caught ? HitResult.Great : HitResult.Miss + Type = area.MovableCatcher.CanCatch(fruit) ? HitResult.Great : HitResult.Miss }); drawable.Expire(); @@ -75,7 +73,10 @@ namespace osu.Game.Rulesets.Catch.Tests SetContents(() => { - var droppedObjectContainer = new Container(); + var droppedObjectContainer = new Container + { + RelativeSizeAxes = Axes.Both + }; return new CatchInputManager(catchRuleset) { @@ -101,7 +102,7 @@ namespace osu.Game.Rulesets.Catch.Tests private class TestCatcherArea : CatcherArea { - public TestCatcherArea(Container droppedObjectContainer, BeatmapDifficulty beatmapDifficulty) + public TestCatcherArea(Container droppedObjectContainer, BeatmapDifficulty beatmapDifficulty) : base(droppedObjectContainer, beatmapDifficulty) { } diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneFruitRandomness.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneFruitRandomness.cs index 2ffebb7de1..c888dc0a65 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneFruitRandomness.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneFruitRandomness.cs @@ -5,19 +5,20 @@ using NUnit.Framework; using osu.Game.Rulesets.Catch.Objects; using osu.Game.Rulesets.Catch.Objects.Drawables; using osu.Game.Tests.Visual; +using osuTK; using osuTK.Graphics; namespace osu.Game.Rulesets.Catch.Tests { public class TestSceneFruitRandomness : OsuTestScene { - private readonly TestDrawableFruit drawableFruit; - private readonly TestDrawableBanana drawableBanana; + private readonly DrawableFruit drawableFruit; + private readonly DrawableBanana drawableBanana; public TestSceneFruitRandomness() { - drawableFruit = new TestDrawableFruit(new Fruit()); - drawableBanana = new TestDrawableBanana(new Banana()); + drawableFruit = new DrawableFruit(new Fruit()); + drawableBanana = new DrawableBanana(new Banana()); Add(new TestDrawableCatchHitObjectSpecimen(drawableFruit) { X = -200 }); Add(new TestDrawableCatchHitObjectSpecimen(drawableBanana)); @@ -37,16 +38,16 @@ namespace osu.Game.Rulesets.Catch.Tests float fruitRotation = 0; float bananaRotation = 0; - float bananaScale = 0; + Vector2 bananaSize = new Vector2(); Color4 bananaColour = new Color4(); AddStep("Initialize start time", () => { drawableFruit.HitObject.StartTime = drawableBanana.HitObject.StartTime = initial_start_time; - fruitRotation = drawableFruit.InnerRotation; - bananaRotation = drawableBanana.InnerRotation; - bananaScale = drawableBanana.InnerScale; + fruitRotation = drawableFruit.DisplayRotation; + bananaRotation = drawableBanana.DisplayRotation; + bananaSize = drawableBanana.DisplaySize; bananaColour = drawableBanana.AccentColour.Value; }); @@ -55,9 +56,9 @@ namespace osu.Game.Rulesets.Catch.Tests drawableFruit.HitObject.StartTime = drawableBanana.HitObject.StartTime = another_start_time; }); - AddAssert("fruit rotation is changed", () => drawableFruit.InnerRotation != fruitRotation); - AddAssert("banana rotation is changed", () => drawableBanana.InnerRotation != bananaRotation); - AddAssert("banana scale is changed", () => drawableBanana.InnerScale != bananaScale); + AddAssert("fruit rotation is changed", () => drawableFruit.DisplayRotation != fruitRotation); + AddAssert("banana rotation is changed", () => drawableBanana.DisplayRotation != bananaRotation); + AddAssert("banana size is changed", () => drawableBanana.DisplaySize != bananaSize); AddAssert("banana colour is changed", () => drawableBanana.AccentColour.Value != bananaColour); AddStep("reset start time", () => @@ -65,32 +66,11 @@ namespace osu.Game.Rulesets.Catch.Tests drawableFruit.HitObject.StartTime = drawableBanana.HitObject.StartTime = initial_start_time; }); - AddAssert("rotation and scale restored", () => - drawableFruit.InnerRotation == fruitRotation && - drawableBanana.InnerRotation == bananaRotation && - drawableBanana.InnerScale == bananaScale && + AddAssert("rotation and size restored", () => + drawableFruit.DisplayRotation == fruitRotation && + drawableBanana.DisplayRotation == bananaRotation && + drawableBanana.DisplaySize == bananaSize && drawableBanana.AccentColour.Value == bananaColour); } - - private class TestDrawableFruit : DrawableFruit - { - public float InnerRotation => ScaleContainer.Rotation; - - public TestDrawableFruit(Fruit h) - : base(h) - { - } - } - - private class TestDrawableBanana : DrawableBanana - { - public float InnerRotation => ScaleContainer.Rotation; - public float InnerScale => ScaleContainer.Scale.X; - - public TestDrawableBanana(Banana h) - : base(h) - { - } - } } } diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneHyperDashColouring.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneHyperDashColouring.cs index 07cb73e5ff..683a776dcc 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneHyperDashColouring.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneHyperDashColouring.cs @@ -13,6 +13,7 @@ using osu.Game.Beatmaps.ControlPoints; using osu.Game.Rulesets.Catch.Objects; using osu.Game.Rulesets.Catch.Objects.Drawables; using osu.Game.Rulesets.Catch.Skinning; +using osu.Game.Rulesets.Catch.Skinning.Legacy; using osu.Game.Rulesets.Catch.UI; using osu.Game.Skinning; using osu.Game.Tests.Visual; @@ -117,7 +118,7 @@ namespace osu.Game.Rulesets.Catch.Tests AddStep("create hyper-dashing catcher", () => { - Child = setupSkinHierarchy(catcherArea = new CatcherArea(new Container()) + Child = setupSkinHierarchy(catcherArea = new CatcherArea(new Container()) { Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game.Rulesets.Catch/CatchRuleset.cs b/osu.Game.Rulesets.Catch/CatchRuleset.cs index ad584d3f48..0a817eca0d 100644 --- a/osu.Game.Rulesets.Catch/CatchRuleset.cs +++ b/osu.Game.Rulesets.Catch/CatchRuleset.cs @@ -21,7 +21,7 @@ using osu.Game.Rulesets.Difficulty; using osu.Game.Rulesets.Scoring; using osu.Game.Scoring; using System; -using osu.Game.Rulesets.Catch.Skinning; +using osu.Game.Rulesets.Catch.Skinning.Legacy; using osu.Game.Skinning; namespace osu.Game.Rulesets.Catch diff --git a/osu.Game.Rulesets.Catch/CatchSkinComponents.cs b/osu.Game.Rulesets.Catch/CatchSkinComponents.cs index 23d8428fec..668f7197be 100644 --- a/osu.Game.Rulesets.Catch/CatchSkinComponents.cs +++ b/osu.Game.Rulesets.Catch/CatchSkinComponents.cs @@ -5,11 +5,8 @@ namespace osu.Game.Rulesets.Catch { public enum CatchSkinComponents { - FruitBananas, - FruitApple, - FruitGrapes, - FruitOrange, - FruitPear, + Fruit, + Banana, Droplet, CatcherIdle, CatcherFail, diff --git a/osu.Game.Rulesets.Catch/Judgements/CatchJudgementResult.cs b/osu.Game.Rulesets.Catch/Judgements/CatchJudgementResult.cs new file mode 100644 index 0000000000..c09355d59c --- /dev/null +++ b/osu.Game.Rulesets.Catch/Judgements/CatchJudgementResult.cs @@ -0,0 +1,28 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using JetBrains.Annotations; +using osu.Game.Rulesets.Catch.UI; +using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Objects; + +namespace osu.Game.Rulesets.Catch.Judgements +{ + public class CatchJudgementResult : JudgementResult + { + /// + /// The catcher animation state prior to this judgement. + /// + public CatcherAnimationState CatcherAnimationState; + + /// + /// Whether the catcher was hyper dashing prior to this judgement. + /// + public bool CatcherHyperDash; + + public CatchJudgementResult([NotNull] HitObject hitObject, [NotNull] Judgement judgement) + : base(hitObject, judgement) + { + } + } +} diff --git a/osu.Game.Rulesets.Catch/Objects/Banana.cs b/osu.Game.Rulesets.Catch/Objects/Banana.cs index 3f71da713e..178306b3bc 100644 --- a/osu.Game.Rulesets.Catch/Objects/Banana.cs +++ b/osu.Game.Rulesets.Catch/Objects/Banana.cs @@ -14,7 +14,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Catch.Objects { - public class Banana : Fruit, IHasComboInformation + public class Banana : PalpableCatchHitObject, IHasComboInformation { /// /// Index of banana in current shower. diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/CaughtBanana.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/CaughtBanana.cs new file mode 100644 index 0000000000..8a91f82437 --- /dev/null +++ b/osu.Game.Rulesets.Catch/Objects/Drawables/CaughtBanana.cs @@ -0,0 +1,18 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Game.Rulesets.Catch.Skinning.Default; + +namespace osu.Game.Rulesets.Catch.Objects.Drawables +{ + /// + /// Represents a caught by the catcher. + /// + public class CaughtBanana : CaughtObject + { + public CaughtBanana() + : base(CatchSkinComponents.Banana, _ => new BananaPiece()) + { + } + } +} diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/CaughtDroplet.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/CaughtDroplet.cs new file mode 100644 index 0000000000..4a3397feff --- /dev/null +++ b/osu.Game.Rulesets.Catch/Objects/Drawables/CaughtDroplet.cs @@ -0,0 +1,20 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Game.Rulesets.Catch.Skinning.Default; + +namespace osu.Game.Rulesets.Catch.Objects.Drawables +{ + /// + /// Represents a caught by the catcher. + /// + public class CaughtDroplet : CaughtObject + { + public override bool StaysOnPlate => false; + + public CaughtDroplet() + : base(CatchSkinComponents.Droplet, _ => new DropletPiece()) + { + } + } +} diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/CaughtFruit.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/CaughtFruit.cs new file mode 100644 index 0000000000..140b411c88 --- /dev/null +++ b/osu.Game.Rulesets.Catch/Objects/Drawables/CaughtFruit.cs @@ -0,0 +1,29 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Bindables; +using osu.Game.Rulesets.Catch.Skinning.Default; + +namespace osu.Game.Rulesets.Catch.Objects.Drawables +{ + /// + /// Represents a caught by the catcher. + /// + public class CaughtFruit : CaughtObject, IHasFruitState + { + public Bindable VisualRepresentation { get; } = new Bindable(); + + public CaughtFruit() + : base(CatchSkinComponents.Fruit, _ => new FruitPiece()) + { + } + + public override void CopyStateFrom(IHasCatchObjectState objectState) + { + base.CopyStateFrom(objectState); + + var fruitState = (IHasFruitState)objectState; + VisualRepresentation.Value = fruitState.VisualRepresentation.Value; + } + } +} diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/CaughtObject.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/CaughtObject.cs new file mode 100644 index 0000000000..524505d588 --- /dev/null +++ b/osu.Game.Rulesets.Catch/Objects/Drawables/CaughtObject.cs @@ -0,0 +1,64 @@ +// 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.Game.Skinning; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Rulesets.Catch.Objects.Drawables +{ + /// + /// Represents a caught by the catcher. + /// + [Cached(typeof(IHasCatchObjectState))] + public abstract class CaughtObject : SkinnableDrawable, IHasCatchObjectState + { + public PalpableCatchHitObject HitObject { get; private set; } + public Bindable AccentColour { get; } = new Bindable(); + public Bindable HyperDash { get; } = new Bindable(); + + public Vector2 DisplaySize => Size * Scale; + + public float DisplayRotation => Rotation; + + /// + /// Whether this hit object should stay on the catcher plate when the object is caught by the catcher. + /// + public virtual bool StaysOnPlate => true; + + public override bool RemoveWhenNotAlive => true; + + protected CaughtObject(CatchSkinComponents skinComponent, Func defaultImplementation) + : base(new CatchSkinComponent(skinComponent), defaultImplementation) + { + Origin = Anchor.Centre; + + RelativeSizeAxes = Axes.None; + Size = new Vector2(CatchHitObject.OBJECT_RADIUS * 2); + } + + /// + /// Copies the hit object visual state from another object. + /// + public virtual void CopyStateFrom(IHasCatchObjectState objectState) + { + HitObject = objectState.HitObject; + Scale = Vector2.Divide(objectState.DisplaySize, Size); + Rotation = objectState.DisplayRotation; + AccentColour.Value = objectState.AccentColour.Value; + HyperDash.Value = objectState.HyperDash.Value; + } + + protected override void FreeAfterUse() + { + ClearTransforms(); + Alpha = 1; + + base.FreeAfterUse(); + } + } +} diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableBanana.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableBanana.cs index 8e9d80106b..c1b41a7afc 100644 --- a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableBanana.cs +++ b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableBanana.cs @@ -2,14 +2,15 @@ // See the LICENCE file in the repository root for full licence text. using JetBrains.Annotations; +using osu.Framework.Allocation; using osu.Framework.Graphics; +using osu.Game.Rulesets.Catch.Skinning.Default; +using osu.Game.Skinning; namespace osu.Game.Rulesets.Catch.Objects.Drawables { - public class DrawableBanana : DrawableFruit + public class DrawableBanana : DrawablePalpableCatchHitObject { - protected override FruitVisualRepresentation GetVisualRepresentation(int indexInBeatmap) => FruitVisualRepresentation.Banana; - public DrawableBanana() : this(null) { @@ -20,6 +21,14 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables { } + [BackgroundDependencyLoader] + private void load() + { + ScalingContainer.Child = new SkinnableDrawable( + new CatchSkinComponent(CatchSkinComponents.Banana), + _ => new BananaPiece()); + } + protected override void LoadComplete() { base.LoadComplete(); @@ -35,12 +44,12 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables const float end_scale = 0.6f; const float random_scale_range = 1.6f; - ScaleContainer.ScaleTo(HitObject.Scale * (end_scale + random_scale_range * RandomSingle(3))) - .Then().ScaleTo(HitObject.Scale * end_scale, HitObject.TimePreempt); + ScalingContainer.ScaleTo(HitObject.Scale * (end_scale + random_scale_range * RandomSingle(3))) + .Then().ScaleTo(HitObject.Scale * end_scale, HitObject.TimePreempt); - ScaleContainer.RotateTo(getRandomAngle(1)) - .Then() - .RotateTo(getRandomAngle(2), HitObject.TimePreempt); + ScalingContainer.RotateTo(getRandomAngle(1)) + .Then() + .RotateTo(getRandomAngle(2), HitObject.TimePreempt); float getRandomAngle(int series) => 180 * (RandomSingle(series) * 2 - 1); } diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableCatchHitObject.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableCatchHitObject.cs index 6aa8ff439e..bfd124c691 100644 --- a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableCatchHitObject.cs +++ b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableCatchHitObject.cs @@ -5,7 +5,9 @@ using System; using JetBrains.Annotations; using osu.Framework.Bindables; using osu.Framework.Graphics; +using osu.Game.Rulesets.Catch.Judgements; using osu.Game.Rulesets.Catch.UI; +using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Utils; @@ -48,9 +50,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables public Func CheckPosition; - public bool IsOnPlate; - - public override bool RemoveWhenNotAlive => IsOnPlate; + protected override JudgementResult CreateResult(Judgement judgement) => new CatchJudgementResult(HitObject, judgement); protected override void CheckForResult(bool userTriggered, double timeOffset) { diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableDroplet.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableDroplet.cs index b8acea625b..2dce9507a5 100644 --- a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableDroplet.cs +++ b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableDroplet.cs @@ -4,15 +4,13 @@ using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Graphics; -using osu.Game.Rulesets.Catch.Objects.Drawables.Pieces; +using osu.Game.Rulesets.Catch.Skinning.Default; using osu.Game.Skinning; namespace osu.Game.Rulesets.Catch.Objects.Drawables { public class DrawableDroplet : DrawablePalpableCatchHitObject { - public override bool StaysOnPlate => false; - public DrawableDroplet() : this(null) { @@ -26,17 +24,9 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables [BackgroundDependencyLoader] private void load() { - HyperDash.BindValueChanged(_ => updatePiece(), true); - } - - private void updatePiece() - { - ScaleContainer.Child = new SkinnableDrawable( + ScalingContainer.Child = new SkinnableDrawable( new CatchSkinComponent(CatchSkinComponents.Droplet), - _ => new DropletPiece - { - HyperDash = { BindTarget = HyperDash } - }); + _ => new DropletPiece()); } protected override void UpdateInitialTransforms() @@ -47,7 +37,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables float startRotation = RandomSingle(1) * 20; double duration = HitObject.TimePreempt + 2000; - ScaleContainer.RotateTo(startRotation).RotateTo(startRotation + 720, duration); + ScalingContainer.RotateTo(startRotation).RotateTo(startRotation + 720, duration); } } } diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableFruit.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableFruit.cs index ef9df02a68..0b89c46480 100644 --- a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableFruit.cs +++ b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableFruit.cs @@ -1,21 +1,18 @@ // 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 JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; -using osu.Game.Rulesets.Catch.Objects.Drawables.Pieces; +using osu.Game.Rulesets.Catch.Skinning.Default; using osu.Game.Skinning; namespace osu.Game.Rulesets.Catch.Objects.Drawables { - public class DrawableFruit : DrawablePalpableCatchHitObject + public class DrawableFruit : DrawablePalpableCatchHitObject, IHasFruitState { - public readonly Bindable VisualRepresentation = new Bindable(); - - protected virtual FruitVisualRepresentation GetVisualRepresentation(int indexInBeatmap) => (FruitVisualRepresentation)(indexInBeatmap % 4); + public Bindable VisualRepresentation { get; } = new Bindable(); public DrawableFruit() : this(null) @@ -32,53 +29,19 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables { IndexInBeatmap.BindValueChanged(change => { - VisualRepresentation.Value = GetVisualRepresentation(change.NewValue); + VisualRepresentation.Value = (FruitVisualRepresentation)(change.NewValue % 4); }, true); - VisualRepresentation.BindValueChanged(_ => updatePiece()); - HyperDash.BindValueChanged(_ => updatePiece(), true); + ScalingContainer.Child = new SkinnableDrawable( + new CatchSkinComponent(CatchSkinComponents.Fruit), + _ => new FruitPiece()); } protected override void UpdateInitialTransforms() { base.UpdateInitialTransforms(); - ScaleContainer.RotateTo((RandomSingle(1) - 0.5f) * 40); - } - - private void updatePiece() - { - ScaleContainer.Child = new SkinnableDrawable( - new CatchSkinComponent(getComponent(VisualRepresentation.Value)), - _ => new FruitPiece - { - VisualRepresentation = { BindTarget = VisualRepresentation }, - HyperDash = { BindTarget = HyperDash }, - }); - } - - private CatchSkinComponents getComponent(FruitVisualRepresentation hitObjectVisualRepresentation) - { - switch (hitObjectVisualRepresentation) - { - case FruitVisualRepresentation.Pear: - return CatchSkinComponents.FruitPear; - - case FruitVisualRepresentation.Grape: - return CatchSkinComponents.FruitGrapes; - - case FruitVisualRepresentation.Pineapple: - return CatchSkinComponents.FruitApple; - - case FruitVisualRepresentation.Raspberry: - return CatchSkinComponents.FruitOrange; - - case FruitVisualRepresentation.Banana: - return CatchSkinComponents.FruitBananas; - - default: - throw new ArgumentOutOfRangeException(nameof(hitObjectVisualRepresentation), hitObjectVisualRepresentation, null); - } + ScalingContainer.RotateTo((RandomSingle(1) - 0.5f) * 40); } } @@ -88,6 +51,5 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables Grape, Pineapple, Raspberry, - Banana // banananananannaanana } } diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawablePalpableCatchHitObject.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawablePalpableCatchHitObject.cs index 0877b5e248..7df06bd92d 100644 --- a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawablePalpableCatchHitObject.cs +++ b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawablePalpableCatchHitObject.cs @@ -7,32 +7,36 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osuTK; +using osuTK.Graphics; namespace osu.Game.Rulesets.Catch.Objects.Drawables { - public abstract class DrawablePalpableCatchHitObject : DrawableCatchHitObject + [Cached(typeof(IHasCatchObjectState))] + public abstract class DrawablePalpableCatchHitObject : DrawableCatchHitObject, IHasCatchObjectState { public new PalpableCatchHitObject HitObject => (PalpableCatchHitObject)base.HitObject; - public readonly Bindable HyperDash = new Bindable(); + Bindable IHasCatchObjectState.AccentColour => AccentColour; - public readonly Bindable ScaleBindable = new Bindable(1); + public Bindable HyperDash { get; } = new Bindable(); - public readonly Bindable IndexInBeatmap = new Bindable(); + public Bindable ScaleBindable { get; } = new Bindable(1); + + public Bindable IndexInBeatmap { get; } = new Bindable(); /// - /// The multiplicative factor applied to scale relative to scale. + /// The multiplicative factor applied to relative to scale. /// protected virtual float ScaleFactor => 1; /// - /// Whether this hit object should stay on the catcher plate when the object is caught by the catcher. + /// The container internal transforms (such as scaling based on the circle size) are applied to. /// - public virtual bool StaysOnPlate => true; + protected readonly Container ScalingContainer; - public float DisplayRadius => CatchHitObject.OBJECT_RADIUS * HitObject.Scale * ScaleFactor; + public Vector2 DisplaySize => ScalingContainer.Size * ScalingContainer.Scale; - protected readonly Container ScaleContainer; + public float DisplayRotation => ScalingContainer.Rotation; protected DrawablePalpableCatchHitObject([CanBeNull] CatchHitObject h) : base(h) @@ -40,11 +44,11 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables Origin = Anchor.Centre; Size = new Vector2(CatchHitObject.OBJECT_RADIUS * 2); - AddInternal(ScaleContainer = new Container + AddInternal(ScalingContainer = new Container { - RelativeSizeAxes = Axes.Both, - Origin = Anchor.Centre, Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(CatchHitObject.OBJECT_RADIUS * 2) }); } @@ -53,12 +57,13 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables { XBindable.BindValueChanged(x => { - if (!IsOnPlate) X = x.NewValue; + X = x.NewValue; }, true); ScaleBindable.BindValueChanged(scale => { - ScaleContainer.Scale = new Vector2(scale.NewValue * ScaleFactor); + ScalingContainer.Scale = new Vector2(scale.NewValue * ScaleFactor); + Size = DisplaySize; }, true); IndexInBeatmap.BindValueChanged(_ => UpdateComboColour()); diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/IHasCatchObjectState.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/IHasCatchObjectState.cs new file mode 100644 index 0000000000..81b61f0959 --- /dev/null +++ b/osu.Game.Rulesets.Catch/Objects/Drawables/IHasCatchObjectState.cs @@ -0,0 +1,25 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Bindables; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Rulesets.Catch.Objects.Drawables +{ + /// + /// Provides a visual state of a . + /// + public interface IHasCatchObjectState + { + PalpableCatchHitObject HitObject { get; } + + Bindable AccentColour { get; } + + Bindable HyperDash { get; } + + Vector2 DisplaySize { get; } + + float DisplayRotation { get; } + } +} diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/IHasFruitState.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/IHasFruitState.cs new file mode 100644 index 0000000000..2d4de543c3 --- /dev/null +++ b/osu.Game.Rulesets.Catch/Objects/Drawables/IHasFruitState.cs @@ -0,0 +1,15 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Bindables; + +namespace osu.Game.Rulesets.Catch.Objects.Drawables +{ + /// + /// Provides a visual state of a . + /// + public interface IHasFruitState : IHasCatchObjectState + { + Bindable VisualRepresentation { get; } + } +} diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/Pieces/BananaPiece.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/Pieces/BananaPiece.cs deleted file mode 100644 index fa8837dec5..0000000000 --- a/osu.Game.Rulesets.Catch/Objects/Drawables/Pieces/BananaPiece.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Framework.Graphics; -using osuTK; - -namespace osu.Game.Rulesets.Catch.Objects.Drawables.Pieces -{ - public class BananaPiece : PulpFormation - { - public BananaPiece() - { - InternalChildren = new Drawable[] - { - new Pulp - { - AccentColour = { BindTarget = AccentColour }, - Size = new Vector2(SMALL_PULP), - Y = -0.3f - }, - new Pulp - { - AccentColour = { BindTarget = AccentColour }, - Size = new Vector2(LARGE_PULP_4 * 0.8f, LARGE_PULP_4 * 2.5f), - Y = 0.05f, - }, - }; - } - } -} diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/Pieces/DropletPiece.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/Pieces/DropletPiece.cs deleted file mode 100644 index c90407ae15..0000000000 --- a/osu.Game.Rulesets.Catch/Objects/Drawables/Pieces/DropletPiece.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Framework.Allocation; -using osu.Framework.Bindables; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Game.Rulesets.Objects.Drawables; -using osuTK; - -namespace osu.Game.Rulesets.Catch.Objects.Drawables.Pieces -{ - public class DropletPiece : CompositeDrawable - { - public readonly Bindable HyperDash = new Bindable(); - - public DropletPiece() - { - Size = new Vector2(CatchHitObject.OBJECT_RADIUS / 2); - } - - [BackgroundDependencyLoader] - private void load(DrawableHitObject drawableObject) - { - InternalChild = new Pulp - { - RelativeSizeAxes = Axes.Both, - AccentColour = { BindTarget = drawableObject.AccentColour } - }; - - if (HyperDash.Value) - { - AddInternal(new HyperDropletBorderPiece()); - } - } - } -} diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/Pieces/FruitPiece.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/Pieces/FruitPiece.cs deleted file mode 100644 index 31487ee407..0000000000 --- a/osu.Game.Rulesets.Catch/Objects/Drawables/Pieces/FruitPiece.cs +++ /dev/null @@ -1,79 +0,0 @@ -// 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 JetBrains.Annotations; -using osu.Framework.Allocation; -using osu.Framework.Bindables; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Game.Rulesets.Objects.Drawables; - -namespace osu.Game.Rulesets.Catch.Objects.Drawables.Pieces -{ - internal class FruitPiece : CompositeDrawable - { - /// - /// Because we're adding a border around the fruit, we need to scale down some. - /// - public const float RADIUS_ADJUST = 1.1f; - - public readonly Bindable VisualRepresentation = new Bindable(); - public readonly Bindable HyperDash = new Bindable(); - - [CanBeNull] - private DrawableCatchHitObject drawableHitObject; - - [CanBeNull] - private BorderPiece borderPiece; - - public FruitPiece() - { - RelativeSizeAxes = Axes.Both; - } - - [BackgroundDependencyLoader(permitNulls: true)] - private void load([CanBeNull] DrawableHitObject drawable) - { - drawableHitObject = (DrawableCatchHitObject)drawable; - - AddInternal(getFruitFor(VisualRepresentation.Value)); - - // if it is not part of a DHO, the border is always invisible. - if (drawableHitObject != null) - AddInternal(borderPiece = new BorderPiece()); - - if (HyperDash.Value) - AddInternal(new HyperBorderPiece()); - } - - protected override void Update() - { - if (borderPiece != null && drawableHitObject?.HitObject != null) - borderPiece.Alpha = (float)Math.Clamp((drawableHitObject.HitObject.StartTime - Time.Current) / 500, 0, 1); - } - - private Drawable getFruitFor(FruitVisualRepresentation representation) - { - switch (representation) - { - case FruitVisualRepresentation.Pear: - return new PearPiece(); - - case FruitVisualRepresentation.Grape: - return new GrapePiece(); - - case FruitVisualRepresentation.Pineapple: - return new PineapplePiece(); - - case FruitVisualRepresentation.Banana: - return new BananaPiece(); - - case FruitVisualRepresentation.Raspberry: - return new RaspberryPiece(); - } - - return Empty(); - } - } -} diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/Pieces/GrapePiece.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/Pieces/GrapePiece.cs deleted file mode 100644 index 15349c18d5..0000000000 --- a/osu.Game.Rulesets.Catch/Objects/Drawables/Pieces/GrapePiece.cs +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Framework.Graphics; -using osuTK; - -namespace osu.Game.Rulesets.Catch.Objects.Drawables.Pieces -{ - public class GrapePiece : PulpFormation - { - public GrapePiece() - { - InternalChildren = new Drawable[] - { - new Pulp - { - AccentColour = { BindTarget = AccentColour }, - Size = new Vector2(SMALL_PULP), - Y = -0.25f, - }, - new Pulp - { - AccentColour = { BindTarget = AccentColour }, - Size = new Vector2(LARGE_PULP_3), - Position = PositionAt(0, DISTANCE_FROM_CENTRE_3), - }, - new Pulp - { - AccentColour = { BindTarget = AccentColour }, - Size = new Vector2(LARGE_PULP_3), - Position = PositionAt(120, DISTANCE_FROM_CENTRE_3), - }, - new Pulp - { - Size = new Vector2(LARGE_PULP_3), - AccentColour = { BindTarget = AccentColour }, - Position = PositionAt(240, DISTANCE_FROM_CENTRE_3), - }, - }; - } - } -} diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/Pieces/PearPiece.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/Pieces/PearPiece.cs deleted file mode 100644 index 3372a06996..0000000000 --- a/osu.Game.Rulesets.Catch/Objects/Drawables/Pieces/PearPiece.cs +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Framework.Graphics; -using osuTK; - -namespace osu.Game.Rulesets.Catch.Objects.Drawables.Pieces -{ - public class PearPiece : PulpFormation - { - public PearPiece() - { - InternalChildren = new Drawable[] - { - new Pulp - { - AccentColour = { BindTarget = AccentColour }, - Size = new Vector2(SMALL_PULP), - Y = -0.33f, - }, - new Pulp - { - AccentColour = { BindTarget = AccentColour }, - Size = new Vector2(LARGE_PULP_3), - Position = PositionAt(60, DISTANCE_FROM_CENTRE_3), - }, - new Pulp - { - AccentColour = { BindTarget = AccentColour }, - Size = new Vector2(LARGE_PULP_3), - Position = PositionAt(180, DISTANCE_FROM_CENTRE_3), - }, - new Pulp - { - Size = new Vector2(LARGE_PULP_3), - AccentColour = { BindTarget = AccentColour }, - Position = PositionAt(300, DISTANCE_FROM_CENTRE_3), - }, - }; - } - } -} diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/Pieces/PineapplePiece.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/Pieces/PineapplePiece.cs deleted file mode 100644 index 7f80c58178..0000000000 --- a/osu.Game.Rulesets.Catch/Objects/Drawables/Pieces/PineapplePiece.cs +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Framework.Graphics; -using osuTK; - -namespace osu.Game.Rulesets.Catch.Objects.Drawables.Pieces -{ - public class PineapplePiece : PulpFormation - { - public PineapplePiece() - { - InternalChildren = new Drawable[] - { - new Pulp - { - AccentColour = { BindTarget = AccentColour }, - Size = new Vector2(SMALL_PULP), - Y = -0.3f, - }, - new Pulp - { - AccentColour = { BindTarget = AccentColour }, - Size = new Vector2(LARGE_PULP_4), - Position = PositionAt(45, DISTANCE_FROM_CENTRE_4), - }, - new Pulp - { - AccentColour = { BindTarget = AccentColour }, - Size = new Vector2(LARGE_PULP_4), - Position = PositionAt(135, DISTANCE_FROM_CENTRE_4), - }, - new Pulp - { - AccentColour = { BindTarget = AccentColour }, - Size = new Vector2(LARGE_PULP_4), - Position = PositionAt(225, DISTANCE_FROM_CENTRE_4), - }, - new Pulp - { - Size = new Vector2(LARGE_PULP_4), - AccentColour = { BindTarget = AccentColour }, - Position = PositionAt(315, DISTANCE_FROM_CENTRE_4), - }, - }; - } - } -} diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/Pieces/RaspberryPiece.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/Pieces/RaspberryPiece.cs deleted file mode 100644 index 288ece95b2..0000000000 --- a/osu.Game.Rulesets.Catch/Objects/Drawables/Pieces/RaspberryPiece.cs +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Framework.Graphics; -using osuTK; - -namespace osu.Game.Rulesets.Catch.Objects.Drawables.Pieces -{ - public class RaspberryPiece : PulpFormation - { - public RaspberryPiece() - { - InternalChildren = new Drawable[] - { - new Pulp - { - AccentColour = { BindTarget = AccentColour }, - Size = new Vector2(SMALL_PULP), - Y = -0.34f, - }, - new Pulp - { - AccentColour = { BindTarget = AccentColour }, - Size = new Vector2(LARGE_PULP_4), - Position = PositionAt(0, DISTANCE_FROM_CENTRE_4), - }, - new Pulp - { - AccentColour = { BindTarget = AccentColour }, - Size = new Vector2(LARGE_PULP_4), - Position = PositionAt(90, DISTANCE_FROM_CENTRE_4), - }, - new Pulp - { - AccentColour = { BindTarget = AccentColour }, - Size = new Vector2(LARGE_PULP_4), - Position = PositionAt(180, DISTANCE_FROM_CENTRE_4), - }, - new Pulp - { - Size = new Vector2(LARGE_PULP_4), - AccentColour = { BindTarget = AccentColour }, - Position = PositionAt(270, DISTANCE_FROM_CENTRE_4), - }, - }; - } - } -} diff --git a/osu.Game.Rulesets.Catch/Skinning/Default/BananaPiece.cs b/osu.Game.Rulesets.Catch/Skinning/Default/BananaPiece.cs new file mode 100644 index 0000000000..8da18a668a --- /dev/null +++ b/osu.Game.Rulesets.Catch/Skinning/Default/BananaPiece.cs @@ -0,0 +1,26 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Graphics; + +namespace osu.Game.Rulesets.Catch.Skinning.Default +{ + public class BananaPiece : CatchHitObjectPiece + { + protected override BorderPiece BorderPiece { get; } + + public BananaPiece() + { + RelativeSizeAxes = Axes.Both; + + InternalChildren = new Drawable[] + { + new BananaPulpFormation + { + AccentColour = { BindTarget = AccentColour }, + }, + BorderPiece = new BorderPiece(), + }; + } + } +} diff --git a/osu.Game.Rulesets.Catch/Skinning/Default/BananaPulpFormation.cs b/osu.Game.Rulesets.Catch/Skinning/Default/BananaPulpFormation.cs new file mode 100644 index 0000000000..ee1cc68f7d --- /dev/null +++ b/osu.Game.Rulesets.Catch/Skinning/Default/BananaPulpFormation.cs @@ -0,0 +1,16 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osuTK; + +namespace osu.Game.Rulesets.Catch.Skinning.Default +{ + public class BananaPulpFormation : PulpFormation + { + public BananaPulpFormation() + { + AddPulp(new Vector2(0, -0.3f), new Vector2(SMALL_PULP)); + AddPulp(new Vector2(0, 0.05f), new Vector2(LARGE_PULP_4 * 0.8f, LARGE_PULP_4 * 2.5f)); + } + } +} diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/Pieces/BorderPiece.cs b/osu.Game.Rulesets.Catch/Skinning/Default/BorderPiece.cs similarity index 90% rename from osu.Game.Rulesets.Catch/Objects/Drawables/Pieces/BorderPiece.cs rename to osu.Game.Rulesets.Catch/Skinning/Default/BorderPiece.cs index 1e7a0b0685..7308d6b499 100644 --- a/osu.Game.Rulesets.Catch/Objects/Drawables/Pieces/BorderPiece.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Default/BorderPiece.cs @@ -3,10 +3,11 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Shapes; +using osu.Game.Rulesets.Catch.Objects; using osuTK; using osuTK.Graphics; -namespace osu.Game.Rulesets.Catch.Objects.Drawables.Pieces +namespace osu.Game.Rulesets.Catch.Skinning.Default { public class BorderPiece : Circle { diff --git a/osu.Game.Rulesets.Catch/Skinning/Default/CatchHitObjectPiece.cs b/osu.Game.Rulesets.Catch/Skinning/Default/CatchHitObjectPiece.cs new file mode 100644 index 0000000000..51c06c8e37 --- /dev/null +++ b/osu.Game.Rulesets.Catch/Skinning/Default/CatchHitObjectPiece.cs @@ -0,0 +1,54 @@ +// 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 JetBrains.Annotations; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics.Containers; +using osu.Game.Rulesets.Catch.Objects.Drawables; +using osuTK.Graphics; + +namespace osu.Game.Rulesets.Catch.Skinning.Default +{ + public abstract class CatchHitObjectPiece : CompositeDrawable + { + public readonly Bindable AccentColour = new Bindable(); + public readonly Bindable HyperDash = new Bindable(); + + [Resolved] + protected IHasCatchObjectState ObjectState { get; private set; } + + /// + /// A part of this piece that will be faded out while falling in the playfield. + /// + [CanBeNull] + protected virtual BorderPiece BorderPiece => null; + + /// + /// A part of this piece that will be only visible when is true. + /// + [CanBeNull] + protected virtual HyperBorderPiece HyperBorderPiece => null; + + protected override void LoadComplete() + { + base.LoadComplete(); + + AccentColour.BindTo(ObjectState.AccentColour); + HyperDash.BindTo(ObjectState.HyperDash); + + HyperDash.BindValueChanged(hyper => + { + if (HyperBorderPiece != null) + HyperBorderPiece.Alpha = hyper.NewValue ? 1 : 0; + }, true); + } + + protected override void Update() + { + if (BorderPiece != null) + BorderPiece.Alpha = (float)Math.Clamp((ObjectState.HitObject.StartTime - Time.Current) / 500, 0, 1); + } + } +} diff --git a/osu.Game.Rulesets.Catch/Skinning/Default/DropletPiece.cs b/osu.Game.Rulesets.Catch/Skinning/Default/DropletPiece.cs new file mode 100644 index 0000000000..8b1052dfe2 --- /dev/null +++ b/osu.Game.Rulesets.Catch/Skinning/Default/DropletPiece.cs @@ -0,0 +1,29 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Graphics; +using osu.Game.Rulesets.Catch.Objects; +using osuTK; + +namespace osu.Game.Rulesets.Catch.Skinning.Default +{ + public class DropletPiece : CatchHitObjectPiece + { + protected override HyperBorderPiece HyperBorderPiece { get; } + + public DropletPiece() + { + Size = new Vector2(CatchHitObject.OBJECT_RADIUS / 2); + + InternalChildren = new Drawable[] + { + new Pulp + { + RelativeSizeAxes = Axes.Both, + AccentColour = { BindTarget = AccentColour } + }, + HyperBorderPiece = new HyperDropletBorderPiece() + }; + } + } +} diff --git a/osu.Game.Rulesets.Catch/Skinning/Default/FruitPiece.cs b/osu.Game.Rulesets.Catch/Skinning/Default/FruitPiece.cs new file mode 100644 index 0000000000..49f128c960 --- /dev/null +++ b/osu.Game.Rulesets.Catch/Skinning/Default/FruitPiece.cs @@ -0,0 +1,46 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Game.Rulesets.Catch.Objects.Drawables; + +namespace osu.Game.Rulesets.Catch.Skinning.Default +{ + internal class FruitPiece : CatchHitObjectPiece + { + /// + /// Because we're adding a border around the fruit, we need to scale down some. + /// + public const float RADIUS_ADJUST = 1.1f; + + public readonly Bindable VisualRepresentation = new Bindable(); + + protected override BorderPiece BorderPiece { get; } + protected override HyperBorderPiece HyperBorderPiece { get; } + + public FruitPiece() + { + RelativeSizeAxes = Axes.Both; + + InternalChildren = new Drawable[] + { + new FruitPulpFormation + { + AccentColour = { BindTarget = AccentColour }, + VisualRepresentation = { BindTarget = VisualRepresentation } + }, + BorderPiece = new BorderPiece(), + HyperBorderPiece = new HyperBorderPiece() + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + var fruitState = (IHasFruitState)ObjectState; + VisualRepresentation.BindTo(fruitState.VisualRepresentation); + } + } +} diff --git a/osu.Game.Rulesets.Catch/Skinning/Default/FruitPulpFormation.cs b/osu.Game.Rulesets.Catch/Skinning/Default/FruitPulpFormation.cs new file mode 100644 index 0000000000..88e0b5133a --- /dev/null +++ b/osu.Game.Rulesets.Catch/Skinning/Default/FruitPulpFormation.cs @@ -0,0 +1,59 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Bindables; +using osu.Game.Rulesets.Catch.Objects.Drawables; +using osuTK; + +namespace osu.Game.Rulesets.Catch.Skinning.Default +{ + public class FruitPulpFormation : PulpFormation + { + public readonly Bindable VisualRepresentation = new Bindable(); + + protected override void LoadComplete() + { + base.LoadComplete(); + + VisualRepresentation.BindValueChanged(setFormation, true); + } + + private void setFormation(ValueChangedEvent visualRepresentation) + { + Clear(); + + switch (visualRepresentation.NewValue) + { + case FruitVisualRepresentation.Pear: + AddPulp(new Vector2(0, -0.33f), new Vector2(SMALL_PULP)); + AddPulp(PositionAt(60, DISTANCE_FROM_CENTRE_3), new Vector2(LARGE_PULP_3)); + AddPulp(PositionAt(180, DISTANCE_FROM_CENTRE_3), new Vector2(LARGE_PULP_3)); + AddPulp(PositionAt(300, DISTANCE_FROM_CENTRE_3), new Vector2(LARGE_PULP_3)); + break; + + case FruitVisualRepresentation.Grape: + AddPulp(new Vector2(0, -0.25f), new Vector2(SMALL_PULP)); + AddPulp(PositionAt(0, DISTANCE_FROM_CENTRE_3), new Vector2(LARGE_PULP_3)); + AddPulp(PositionAt(120, DISTANCE_FROM_CENTRE_3), new Vector2(LARGE_PULP_3)); + AddPulp(PositionAt(240, DISTANCE_FROM_CENTRE_3), new Vector2(LARGE_PULP_3)); + break; + + case FruitVisualRepresentation.Pineapple: + AddPulp(new Vector2(0, -0.3f), new Vector2(SMALL_PULP)); + AddPulp(PositionAt(45, DISTANCE_FROM_CENTRE_4), new Vector2(LARGE_PULP_4)); + AddPulp(PositionAt(135, DISTANCE_FROM_CENTRE_4), new Vector2(LARGE_PULP_4)); + AddPulp(PositionAt(225, DISTANCE_FROM_CENTRE_4), new Vector2(LARGE_PULP_4)); + AddPulp(PositionAt(315, DISTANCE_FROM_CENTRE_4), new Vector2(LARGE_PULP_4)); + break; + + case FruitVisualRepresentation.Raspberry: + AddPulp(new Vector2(0, -0.34f), new Vector2(SMALL_PULP)); + AddPulp(PositionAt(0, DISTANCE_FROM_CENTRE_4), new Vector2(LARGE_PULP_4)); + AddPulp(PositionAt(90, DISTANCE_FROM_CENTRE_4), new Vector2(LARGE_PULP_4)); + AddPulp(PositionAt(180, DISTANCE_FROM_CENTRE_4), new Vector2(LARGE_PULP_4)); + AddPulp(PositionAt(270, DISTANCE_FROM_CENTRE_4), new Vector2(LARGE_PULP_4)); + break; + } + } + } +} diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/Pieces/HyperBorderPiece.cs b/osu.Game.Rulesets.Catch/Skinning/Default/HyperBorderPiece.cs similarity index 91% rename from osu.Game.Rulesets.Catch/Objects/Drawables/Pieces/HyperBorderPiece.cs rename to osu.Game.Rulesets.Catch/Skinning/Default/HyperBorderPiece.cs index 60bb07e89d..d160956a6e 100644 --- a/osu.Game.Rulesets.Catch/Objects/Drawables/Pieces/HyperBorderPiece.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Default/HyperBorderPiece.cs @@ -4,7 +4,7 @@ using osu.Framework.Graphics; using osu.Game.Rulesets.Catch.UI; -namespace osu.Game.Rulesets.Catch.Objects.Drawables.Pieces +namespace osu.Game.Rulesets.Catch.Skinning.Default { public class HyperBorderPiece : BorderPiece { diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/Pieces/HyperDropletBorderPiece.cs b/osu.Game.Rulesets.Catch/Skinning/Default/HyperDropletBorderPiece.cs similarity index 85% rename from osu.Game.Rulesets.Catch/Objects/Drawables/Pieces/HyperDropletBorderPiece.cs rename to osu.Game.Rulesets.Catch/Skinning/Default/HyperDropletBorderPiece.cs index 1bd9fd6bb2..53a487b97f 100644 --- a/osu.Game.Rulesets.Catch/Objects/Drawables/Pieces/HyperDropletBorderPiece.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Default/HyperDropletBorderPiece.cs @@ -1,7 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -namespace osu.Game.Rulesets.Catch.Objects.Drawables.Pieces +namespace osu.Game.Rulesets.Catch.Skinning.Default { public class HyperDropletBorderPiece : HyperBorderPiece { diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/Pieces/Pulp.cs b/osu.Game.Rulesets.Catch/Skinning/Default/Pulp.cs similarity index 95% rename from osu.Game.Rulesets.Catch/Objects/Drawables/Pieces/Pulp.cs rename to osu.Game.Rulesets.Catch/Skinning/Default/Pulp.cs index d3e4945611..96c6233b41 100644 --- a/osu.Game.Rulesets.Catch/Objects/Drawables/Pieces/Pulp.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Default/Pulp.cs @@ -8,10 +8,12 @@ using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Shapes; using osuTK.Graphics; -namespace osu.Game.Rulesets.Catch.Objects.Drawables.Pieces +namespace osu.Game.Rulesets.Catch.Skinning.Default { public class Pulp : Circle { + public readonly Bindable AccentColour = new Bindable(); + public Pulp() { RelativePositionAxes = Axes.Both; @@ -22,8 +24,6 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables.Pieces Colour = Color4.White.Opacity(0.9f); } - public readonly Bindable AccentColour = new Bindable(); - protected override void LoadComplete() { base.LoadComplete(); diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/Pieces/PulpFormation.cs b/osu.Game.Rulesets.Catch/Skinning/Default/PulpFormation.cs similarity index 59% rename from osu.Game.Rulesets.Catch/Objects/Drawables/Pieces/PulpFormation.cs rename to osu.Game.Rulesets.Catch/Skinning/Default/PulpFormation.cs index 1df548e70a..8753aa4077 100644 --- a/osu.Game.Rulesets.Catch/Objects/Drawables/Pieces/PulpFormation.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Default/PulpFormation.cs @@ -2,19 +2,17 @@ // 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.Game.Rulesets.Objects.Drawables; using osuTK; using osuTK.Graphics; -namespace osu.Game.Rulesets.Catch.Objects.Drawables.Pieces +namespace osu.Game.Rulesets.Catch.Skinning.Default { public abstract class PulpFormation : CompositeDrawable { - protected readonly IBindable AccentColour = new Bindable(); + public readonly Bindable AccentColour = new Bindable(); protected const float LARGE_PULP_3 = 16f * FruitPiece.RADIUS_ADJUST; protected const float DISTANCE_FROM_CENTRE_3 = 0.15f; @@ -24,6 +22,8 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables.Pieces protected const float SMALL_PULP = LARGE_PULP_3 / 2; + private int pulpsInUse; + protected PulpFormation() { RelativeSizeAxes = Axes.Both; @@ -33,11 +33,24 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables.Pieces distance * MathF.Sin(angle * MathF.PI / 180), distance * MathF.Cos(angle * MathF.PI / 180)); - [BackgroundDependencyLoader] - private void load(DrawableHitObject drawableObject) + protected void Clear() { - DrawableCatchHitObject drawableCatchObject = (DrawableCatchHitObject)drawableObject; - AccentColour.BindTo(drawableCatchObject.AccentColour); + for (int i = 0; i < pulpsInUse; i++) + InternalChildren[i].Alpha = 0; + pulpsInUse = 0; + } + + protected void AddPulp(Vector2 position, Vector2 size) + { + if (pulpsInUse == InternalChildren.Count) + AddInternal(new Pulp { AccentColour = { BindTarget = AccentColour } }); + + var pulp = InternalChildren[pulpsInUse]; + pulp.Position = position; + pulp.Size = size; + pulp.Alpha = 1; + + pulpsInUse++; } } } diff --git a/osu.Game.Rulesets.Catch/Skinning/CatchLegacySkinTransformer.cs b/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs similarity index 83% rename from osu.Game.Rulesets.Catch/Skinning/CatchLegacySkinTransformer.cs rename to osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs index 22db147e32..41fd0fe776 100644 --- a/osu.Game.Rulesets.Catch/Skinning/CatchLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs @@ -1,15 +1,13 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using Humanizer; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Game.Skinning; -using osuTK; using osuTK.Graphics; using static osu.Game.Skinning.LegacySkinConfiguration; -namespace osu.Game.Rulesets.Catch.Skinning +namespace osu.Game.Rulesets.Catch.Skinning.Legacy { public class CatchLegacySkinTransformer : LegacySkinTransformer { @@ -40,20 +38,21 @@ namespace osu.Game.Rulesets.Catch.Skinning switch (catchSkinComponent.Component) { - case CatchSkinComponents.FruitApple: - case CatchSkinComponents.FruitBananas: - case CatchSkinComponents.FruitOrange: - case CatchSkinComponents.FruitGrapes: - case CatchSkinComponents.FruitPear: - var lookupName = catchSkinComponent.Component.ToString().Kebaberize(); - if (GetTexture(lookupName) != null) - return new LegacyFruitPiece(lookupName); + case CatchSkinComponents.Fruit: + if (GetTexture("fruit-pear") != null) + return new LegacyFruitPiece(); + + break; + + case CatchSkinComponents.Banana: + if (GetTexture("fruit-bananas") != null) + return new LegacyBananaPiece(); break; case CatchSkinComponents.Droplet: if (GetTexture("fruit-drop") != null) - return new LegacyFruitPiece("fruit-drop") { Scale = new Vector2(0.8f) }; + return new LegacyDropletPiece(); break; diff --git a/osu.Game.Rulesets.Catch/Skinning/LegacyCatchComboCounter.cs b/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyCatchComboCounter.cs similarity index 98% rename from osu.Game.Rulesets.Catch/Skinning/LegacyCatchComboCounter.cs rename to osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyCatchComboCounter.cs index 34608b07ff..f797ae75c2 100644 --- a/osu.Game.Rulesets.Catch/Skinning/LegacyCatchComboCounter.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyCatchComboCounter.cs @@ -9,7 +9,7 @@ using osuTK; using osuTK.Graphics; using static osu.Game.Skinning.LegacySkinConfiguration; -namespace osu.Game.Rulesets.Catch.Skinning +namespace osu.Game.Rulesets.Catch.Skinning.Legacy { /// /// A combo counter implementation that visually behaves almost similar to stable's osu!catch combo counter. diff --git a/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyFruitPiece.cs b/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyFruitPiece.cs new file mode 100644 index 0000000000..969cc38e5b --- /dev/null +++ b/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyFruitPiece.cs @@ -0,0 +1,45 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Bindables; +using osu.Game.Rulesets.Catch.Objects.Drawables; + +namespace osu.Game.Rulesets.Catch.Skinning.Legacy +{ + internal class LegacyFruitPiece : LegacyCatchHitObjectPiece + { + public readonly Bindable VisualRepresentation = new Bindable(); + + protected override void LoadComplete() + { + base.LoadComplete(); + + var fruitState = (IHasFruitState)ObjectState; + VisualRepresentation.BindTo(fruitState.VisualRepresentation); + + VisualRepresentation.BindValueChanged(visual => setTexture(visual.NewValue), true); + } + + private void setTexture(FruitVisualRepresentation visualRepresentation) + { + switch (visualRepresentation) + { + case FruitVisualRepresentation.Pear: + SetTexture(Skin.GetTexture("fruit-pear"), Skin.GetTexture("fruit-pear-overlay")); + break; + + case FruitVisualRepresentation.Grape: + SetTexture(Skin.GetTexture("fruit-grapes"), Skin.GetTexture("fruit-grapes-overlay")); + break; + + case FruitVisualRepresentation.Pineapple: + SetTexture(Skin.GetTexture("fruit-apple"), Skin.GetTexture("fruit-apple-overlay")); + break; + + case FruitVisualRepresentation.Raspberry: + SetTexture(Skin.GetTexture("fruit-orange"), Skin.GetTexture("fruit-orange-overlay")); + break; + } + } + } +} diff --git a/osu.Game.Rulesets.Catch/Skinning/LegacyBananaPiece.cs b/osu.Game.Rulesets.Catch/Skinning/LegacyBananaPiece.cs new file mode 100644 index 0000000000..f80e50c8c0 --- /dev/null +++ b/osu.Game.Rulesets.Catch/Skinning/LegacyBananaPiece.cs @@ -0,0 +1,20 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Graphics.Textures; + +namespace osu.Game.Rulesets.Catch.Skinning +{ + public class LegacyBananaPiece : LegacyCatchHitObjectPiece + { + protected override void LoadComplete() + { + base.LoadComplete(); + + Texture texture = Skin.GetTexture("fruit-bananas"); + Texture overlayTexture = Skin.GetTexture("fruit-bananas-overlay"); + + SetTexture(texture, overlayTexture); + } + } +} diff --git a/osu.Game.Rulesets.Catch/Skinning/LegacyCatchHitObjectPiece.cs b/osu.Game.Rulesets.Catch/Skinning/LegacyCatchHitObjectPiece.cs new file mode 100644 index 0000000000..4b1f5a4724 --- /dev/null +++ b/osu.Game.Rulesets.Catch/Skinning/LegacyCatchHitObjectPiece.cs @@ -0,0 +1,90 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Pooling; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.Textures; +using osu.Game.Rulesets.Catch.Objects.Drawables; +using osu.Game.Rulesets.Catch.UI; +using osu.Game.Skinning; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Rulesets.Catch.Skinning +{ + public abstract class LegacyCatchHitObjectPiece : PoolableDrawable + { + public readonly Bindable AccentColour = new Bindable(); + public readonly Bindable HyperDash = new Bindable(); + + private readonly Sprite colouredSprite; + private readonly Sprite overlaySprite; + private readonly Sprite hyperSprite; + + [Resolved] + protected ISkinSource Skin { get; private set; } + + [Resolved] + protected IHasCatchObjectState ObjectState { get; private set; } + + protected LegacyCatchHitObjectPiece() + { + RelativeSizeAxes = Axes.Both; + + InternalChildren = new Drawable[] + { + colouredSprite = new Sprite + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }, + overlaySprite = new Sprite + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }, + hyperSprite = new Sprite + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Blending = BlendingParameters.Additive, + Depth = 1, + Alpha = 0, + Scale = new Vector2(1.2f), + } + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + AccentColour.BindTo(ObjectState.AccentColour); + HyperDash.BindTo(ObjectState.HyperDash); + + hyperSprite.Colour = Skin.GetConfig(CatchSkinColour.HyperDashFruit)?.Value ?? + Skin.GetConfig(CatchSkinColour.HyperDash)?.Value ?? + Catcher.DEFAULT_HYPER_DASH_COLOUR; + + AccentColour.BindValueChanged(colour => + { + colouredSprite.Colour = LegacyColourCompatibility.DisallowZeroAlpha(colour.NewValue); + }, true); + + HyperDash.BindValueChanged(hyper => + { + hyperSprite.Alpha = hyper.NewValue ? 0.7f : 0; + }, true); + } + + protected void SetTexture(Texture texture, Texture overlayTexture) + { + colouredSprite.Texture = texture; + overlaySprite.Texture = overlayTexture; + hyperSprite.Texture = texture; + } + } +} diff --git a/osu.Game.Rulesets.Catch/Skinning/LegacyDropletPiece.cs b/osu.Game.Rulesets.Catch/Skinning/LegacyDropletPiece.cs new file mode 100644 index 0000000000..8f4331d2a3 --- /dev/null +++ b/osu.Game.Rulesets.Catch/Skinning/LegacyDropletPiece.cs @@ -0,0 +1,26 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Graphics.Textures; +using osuTK; + +namespace osu.Game.Rulesets.Catch.Skinning +{ + public class LegacyDropletPiece : LegacyCatchHitObjectPiece + { + public LegacyDropletPiece() + { + Scale = new Vector2(0.8f); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + Texture texture = Skin.GetTexture("fruit-drop"); + Texture overlayTexture = Skin.GetTexture("fruit-drop-overlay"); + + SetTexture(texture, overlayTexture); + } + } +} diff --git a/osu.Game.Rulesets.Catch/Skinning/LegacyFruitPiece.cs b/osu.Game.Rulesets.Catch/Skinning/LegacyFruitPiece.cs deleted file mode 100644 index b8648f46f0..0000000000 --- a/osu.Game.Rulesets.Catch/Skinning/LegacyFruitPiece.cs +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Framework.Allocation; -using osu.Framework.Bindables; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Sprites; -using osu.Game.Rulesets.Catch.Objects.Drawables; -using osu.Game.Rulesets.Catch.UI; -using osu.Game.Rulesets.Objects.Drawables; -using osu.Game.Skinning; -using osuTK; -using osuTK.Graphics; - -namespace osu.Game.Rulesets.Catch.Skinning -{ - internal class LegacyFruitPiece : CompositeDrawable - { - private readonly string lookupName; - - private readonly Bindable accentColour = new Bindable(); - private readonly Bindable hyperDash = new Bindable(); - private Sprite colouredSprite; - - public LegacyFruitPiece(string lookupName) - { - this.lookupName = lookupName; - RelativeSizeAxes = Axes.Both; - } - - [BackgroundDependencyLoader] - private void load(DrawableHitObject drawableObject, ISkinSource skin) - { - var drawableCatchObject = (DrawablePalpableCatchHitObject)drawableObject; - - accentColour.BindTo(drawableCatchObject.AccentColour); - hyperDash.BindTo(drawableCatchObject.HyperDash); - - InternalChildren = new Drawable[] - { - colouredSprite = new Sprite - { - Texture = skin.GetTexture(lookupName), - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - }, - new Sprite - { - Texture = skin.GetTexture($"{lookupName}-overlay"), - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - }, - }; - - if (hyperDash.Value) - { - var hyperDashOverlay = new Sprite - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Blending = BlendingParameters.Additive, - Depth = 1, - Alpha = 0.7f, - Scale = new Vector2(1.2f), - Texture = skin.GetTexture(lookupName), - Colour = skin.GetConfig(CatchSkinColour.HyperDashFruit)?.Value ?? - skin.GetConfig(CatchSkinColour.HyperDash)?.Value ?? - Catcher.DEFAULT_HYPER_DASH_COLOUR, - }; - - AddInternal(hyperDashOverlay); - } - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - accentColour.BindValueChanged(colour => colouredSprite.Colour = LegacyColourCompatibility.DisallowZeroAlpha(colour.NewValue), true); - } - } -} diff --git a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs index df87359ed6..73420a9eda 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs @@ -36,7 +36,7 @@ namespace osu.Game.Rulesets.Catch.UI public CatchPlayfield(BeatmapDifficulty difficulty, Func> createDrawableRepresentation) { - var droppedObjectContainer = new Container + var droppedObjectContainer = new Container { RelativeSizeAxes = Axes.Both, }; @@ -81,7 +81,7 @@ namespace osu.Game.Rulesets.Catch.UI ((DrawableCatchHitObject)d).CheckPosition = checkIfWeCanCatch; } - private bool checkIfWeCanCatch(CatchHitObject obj) => CatcherArea.AttemptCatch(obj); + private bool checkIfWeCanCatch(CatchHitObject obj) => CatcherArea.MovableCatcher.CanCatch(obj); private void onNewResult(DrawableHitObject judgedObject, JudgementResult result) => CatcherArea.OnNewResult((DrawableCatchHitObject)judgedObject, result); diff --git a/osu.Game.Rulesets.Catch/UI/Catcher.cs b/osu.Game.Rulesets.Catch/UI/Catcher.cs index 2a3447c80a..f164c2655a 100644 --- a/osu.Game.Rulesets.Catch/UI/Catcher.cs +++ b/osu.Game.Rulesets.Catch/UI/Catcher.cs @@ -14,9 +14,11 @@ using osu.Framework.Input.Bindings; using osu.Framework.Utils; using osu.Game.Beatmaps; using osu.Game.Configuration; +using osu.Game.Rulesets.Catch.Judgements; using osu.Game.Rulesets.Catch.Objects; using osu.Game.Rulesets.Catch.Objects.Drawables; using osu.Game.Rulesets.Catch.Skinning; +using osu.Game.Rulesets.Judgements; using osu.Game.Skinning; using osuTK; using osuTK.Graphics; @@ -51,9 +53,15 @@ namespace osu.Game.Rulesets.Catch.UI private CatcherTrailDisplay trails; - private readonly Container droppedObjectTarget; + /// + /// Contains caught objects on the plate. + /// + private readonly Container caughtObjectContainer; - private readonly Container caughtFruitContainer; + /// + /// Contains objects dropped from the plate. + /// + private readonly Container droppedObjectTarget; public CatcherAnimationState CurrentState { get; private set; } @@ -106,7 +114,11 @@ namespace osu.Game.Rulesets.Catch.UI private readonly DrawablePool hitExplosionPool; private readonly Container hitExplosionContainer; - public Catcher([NotNull] Container trailsTarget, [NotNull] Container droppedObjectTarget, BeatmapDifficulty difficulty = null) + private readonly DrawablePool caughtFruitPool; + private readonly DrawablePool caughtBananaPool; + private readonly DrawablePool caughtDropletPool; + + public Catcher([NotNull] Container trailsTarget, [NotNull] Container droppedObjectTarget, BeatmapDifficulty difficulty = null) { this.trailsTarget = trailsTarget; this.droppedObjectTarget = droppedObjectTarget; @@ -122,7 +134,11 @@ namespace osu.Game.Rulesets.Catch.UI InternalChildren = new Drawable[] { hitExplosionPool = new DrawablePool(10), - caughtFruitContainer = new Container + caughtFruitPool = new DrawablePool(50), + caughtBananaPool = new DrawablePool(100), + // less capacity is needed compared to fruit because droplet is not stacked + caughtDropletPool = new DrawablePool(25), + caughtObjectContainer = new Container { Anchor = Anchor.TopCentre, Origin = Anchor.BottomCentre, @@ -170,7 +186,7 @@ namespace osu.Game.Rulesets.Catch.UI /// /// Creates proxied content to be displayed beneath hitobjects. /// - public Drawable CreateProxiedContent() => caughtFruitContainer.CreateProxy(); + public Drawable CreateProxiedContent() => caughtObjectContainer.CreateProxy(); /// /// Calculates the scale of the catcher based off the provided beatmap difficulty. @@ -190,11 +206,9 @@ namespace osu.Game.Rulesets.Catch.UI internal static float CalculateCatchWidth(BeatmapDifficulty difficulty) => CalculateCatchWidth(calculateScale(difficulty)); /// - /// Let the catcher attempt to catch a fruit. + /// Determine if this catcher can catch a in the current position. /// - /// The fruit to catch. - /// Whether the catch is possible. - public bool AttemptCatch(CatchHitObject hitObject) + public bool CanCatch(CatchHitObject hitObject) { if (!(hitObject is PalpableCatchHitObject fruit)) return false; @@ -205,21 +219,38 @@ namespace osu.Game.Rulesets.Catch.UI var catchObjectPosition = fruit.X; var catcherPosition = Position.X; - var validCatch = - catchObjectPosition >= catcherPosition - halfCatchWidth && - catchObjectPosition <= catcherPosition + halfCatchWidth; + return catchObjectPosition >= catcherPosition - halfCatchWidth && + catchObjectPosition <= catcherPosition + halfCatchWidth; + } - if (validCatch) - placeCaughtObject(fruit); + public void OnNewResult(DrawableCatchHitObject drawableObject, JudgementResult result) + { + var catchResult = (CatchJudgementResult)result; + catchResult.CatcherAnimationState = CurrentState; + catchResult.CatcherHyperDash = HyperDashing; + + if (!(drawableObject is DrawablePalpableCatchHitObject palpableObject)) return; + + var hitObject = palpableObject.HitObject; + + if (result.IsHit) + { + var positionInStack = computePositionInStack(new Vector2(palpableObject.X - X, 0), palpableObject.DisplaySize.X / 2); + + placeCaughtObject(palpableObject, positionInStack); + + if (hitLighting.Value) + addLighting(hitObject, positionInStack.X, drawableObject.AccentColour.Value); + } // droplet doesn't affect the catcher state - if (fruit is TinyDroplet) return validCatch; + if (hitObject is TinyDroplet) return; - if (validCatch && fruit.HyperDash) + if (result.IsHit && hitObject.HyperDash) { - var target = fruit.HyperDashTarget; - var timeDifference = target.StartTime - fruit.StartTime; - double positionDifference = target.X - catcherPosition; + var target = hitObject.HyperDashTarget; + var timeDifference = target.StartTime - hitObject.StartTime; + double positionDifference = target.X - X; var velocity = positionDifference / Math.Max(1.0, timeDifference - 1000.0 / 60.0); SetHyperDashState(Math.Abs(velocity), target.X); @@ -227,12 +258,30 @@ namespace osu.Game.Rulesets.Catch.UI else SetHyperDashState(); - if (validCatch) - updateState(fruit.Kiai ? CatcherAnimationState.Kiai : CatcherAnimationState.Idle); - else if (!(fruit is Banana)) + if (result.IsHit) + updateState(hitObject.Kiai ? CatcherAnimationState.Kiai : CatcherAnimationState.Idle); + else if (!(hitObject is Banana)) updateState(CatcherAnimationState.Fail); + } - return validCatch; + public void OnRevertResult(DrawableCatchHitObject drawableObject, JudgementResult result) + { + var catchResult = (CatchJudgementResult)result; + + if (CurrentState != catchResult.CatcherAnimationState) + updateState(catchResult.CatcherAnimationState); + + if (HyperDashing != catchResult.CatcherHyperDash) + { + if (catchResult.CatcherHyperDash) + SetHyperDashState(2); + else + SetHyperDashState(); + } + + caughtObjectContainer.RemoveAll(d => d.HitObject == drawableObject.HitObject); + droppedObjectTarget.RemoveAll(d => d.HitObject == drawableObject.HitObject); + hitExplosionContainer.RemoveAll(d => d.HitObject == drawableObject.HitObject); } /// @@ -415,137 +464,121 @@ namespace osu.Game.Rulesets.Catch.UI updateCatcher(); } - private void placeCaughtObject(PalpableCatchHitObject source) + private void placeCaughtObject(DrawablePalpableCatchHitObject drawableObject, Vector2 position) { - var caughtObject = createCaughtObject(source); + var caughtObject = getCaughtObject(drawableObject.HitObject); if (caughtObject == null) return; - caughtObject.RelativePositionAxes = Axes.None; - caughtObject.X = source.X - X; - caughtObject.IsOnPlate = true; - + caughtObject.CopyStateFrom(drawableObject); caughtObject.Anchor = Anchor.TopCentre; - caughtObject.Origin = Anchor.Centre; - caughtObject.Scale *= 0.5f; - caughtObject.LifetimeStart = source.StartTime; - caughtObject.LifetimeEnd = double.MaxValue; + caughtObject.Position = position; + caughtObject.Scale /= 2; - adjustPositionInStack(caughtObject); - - caughtFruitContainer.Add(caughtObject); - - addLighting(caughtObject); + caughtObjectContainer.Add(caughtObject); if (!caughtObject.StaysOnPlate) removeFromPlate(caughtObject, DroppedObjectAnimation.Explode); } - private void adjustPositionInStack(DrawablePalpableCatchHitObject caughtObject) + private Vector2 computePositionInStack(Vector2 position, float displayRadius) { const float radius_div_2 = CatchHitObject.OBJECT_RADIUS / 2; const float allowance = 10; - float caughtObjectRadius = caughtObject.DisplayRadius; - - while (caughtFruitContainer.Any(f => Vector2Extensions.Distance(f.Position, caughtObject.Position) < (caughtObjectRadius + radius_div_2) / (allowance / 2))) + while (caughtObjectContainer.Any(f => Vector2Extensions.Distance(f.Position, position) < (displayRadius + radius_div_2) / (allowance / 2))) { - float diff = (caughtObjectRadius + radius_div_2) / allowance; + float diff = (displayRadius + radius_div_2) / allowance; - caughtObject.X += (RNG.NextSingle() - 0.5f) * diff * 2; - caughtObject.Y -= RNG.NextSingle() * diff; + position.X += (RNG.NextSingle() - 0.5f) * diff * 2; + position.Y -= RNG.NextSingle() * diff; } - caughtObject.X = Math.Clamp(caughtObject.X, -CatcherArea.CATCHER_SIZE / 2, CatcherArea.CATCHER_SIZE / 2); + position.X = Math.Clamp(position.X, -CatcherArea.CATCHER_SIZE / 2, CatcherArea.CATCHER_SIZE / 2); + + return position; } - private void addLighting(DrawablePalpableCatchHitObject caughtObject) + private void addLighting(CatchHitObject hitObject, float x, Color4 colour) { - if (!hitLighting.Value) return; - HitExplosion hitExplosion = hitExplosionPool.Get(); - hitExplosion.X = caughtObject.X; - hitExplosion.Scale = new Vector2(caughtObject.HitObject.Scale); - hitExplosion.ObjectColour = caughtObject.AccentColour.Value; + hitExplosion.HitObject = hitObject; + hitExplosion.X = x; + hitExplosion.Scale = new Vector2(hitObject.Scale); + hitExplosion.ObjectColour = colour; hitExplosionContainer.Add(hitExplosion); } - private DrawablePalpableCatchHitObject createCaughtObject(PalpableCatchHitObject source) + private CaughtObject getCaughtObject(PalpableCatchHitObject source) { switch (source) { - case Banana banana: - return new DrawableBanana(banana); + case Fruit _: + return caughtFruitPool.Get(); - case Fruit fruit: - return new DrawableFruit(fruit); + case Banana _: + return caughtBananaPool.Get(); - case TinyDroplet tiny: - return new DrawableTinyDroplet(tiny); - - case Droplet droplet: - return new DrawableDroplet(droplet); + case Droplet _: + return caughtDropletPool.Get(); default: return null; } } + private CaughtObject getDroppedObject(CaughtObject caughtObject) + { + var droppedObject = getCaughtObject(caughtObject.HitObject); + + droppedObject.CopyStateFrom(caughtObject); + droppedObject.Anchor = Anchor.TopLeft; + droppedObject.Position = caughtObjectContainer.ToSpaceOfOtherDrawable(caughtObject.DrawPosition, droppedObjectTarget); + + return droppedObject; + } + private void clearPlate(DroppedObjectAnimation animation) { - var caughtObjects = caughtFruitContainer.Children.ToArray(); - caughtFruitContainer.Clear(false); + var droppedObjects = caughtObjectContainer.Children.Select(getDroppedObject).ToArray(); - droppedObjectTarget.AddRange(caughtObjects); + caughtObjectContainer.Clear(false); - foreach (var caughtObject in caughtObjects) - drop(caughtObject, animation); + droppedObjectTarget.AddRange(droppedObjects); + + foreach (var droppedObject in droppedObjects) + applyDropAnimation(droppedObject, animation); } - private void removeFromPlate(DrawablePalpableCatchHitObject caughtObject, DroppedObjectAnimation animation) + private void removeFromPlate(CaughtObject caughtObject, DroppedObjectAnimation animation) { - if (!caughtFruitContainer.Remove(caughtObject)) - throw new InvalidOperationException("Can only drop a caught object on the plate"); + var droppedObject = getDroppedObject(caughtObject); - droppedObjectTarget.Add(caughtObject); + caughtObjectContainer.Remove(caughtObject); - drop(caughtObject, animation); + droppedObjectTarget.Add(droppedObject); + + applyDropAnimation(droppedObject, animation); } - private void drop(DrawablePalpableCatchHitObject d, DroppedObjectAnimation animation) + private void applyDropAnimation(Drawable d, DroppedObjectAnimation animation) { - var originalX = d.X * Scale.X; - var startTime = Clock.CurrentTime; - - d.Anchor = Anchor.TopLeft; - d.Position = caughtFruitContainer.ToSpaceOfOtherDrawable(d.DrawPosition, droppedObjectTarget); - - // we cannot just apply the transforms because DHO clears transforms when state is updated - d.ApplyCustomUpdateState += (o, state) => animate(o, animation, originalX, startTime); - if (d.IsLoaded) - animate(d, animation, originalX, startTime); - } - - private void animate(Drawable d, DroppedObjectAnimation animation, float originalX, double startTime) - { - using (d.BeginAbsoluteSequence(startTime)) + switch (animation) { - switch (animation) - { - case DroppedObjectAnimation.Drop: - d.MoveToY(d.Y + 75, 750, Easing.InSine); - d.FadeOut(750); - break; + case DroppedObjectAnimation.Drop: + d.MoveToY(d.Y + 75, 750, Easing.InSine); + d.FadeOut(750); + break; - case DroppedObjectAnimation.Explode: - d.MoveToY(d.Y - 50, 250, Easing.OutSine).Then().MoveToY(d.Y + 50, 500, Easing.InSine); - d.MoveToX(d.X + originalX * 6, 1000); - d.FadeOut(750); - break; - } - - d.Expire(); + case DroppedObjectAnimation.Explode: + var originalX = droppedObjectTarget.ToSpaceOfOtherDrawable(d.DrawPosition, caughtObjectContainer).X * Scale.X; + d.MoveToY(d.Y - 50, 250, Easing.OutSine).Then().MoveToY(d.Y + 50, 500, Easing.InSine); + d.MoveToX(d.X + originalX * 6, 1000); + d.FadeOut(750); + break; } + + d.Expire(); } private enum DroppedObjectAnimation diff --git a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs index 539776354c..44adbd5512 100644 --- a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs +++ b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs @@ -5,7 +5,6 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Beatmaps; using osu.Game.Rulesets.Catch.Judgements; -using osu.Game.Rulesets.Catch.Objects; using osu.Game.Rulesets.Catch.Objects.Drawables; using osu.Game.Rulesets.Catch.Replays; using osu.Game.Rulesets.Judgements; @@ -22,7 +21,7 @@ namespace osu.Game.Rulesets.Catch.UI public readonly Catcher MovableCatcher; private readonly CatchComboDisplay comboDisplay; - public CatcherArea(Container droppedObjectContainer, BeatmapDifficulty difficulty = null) + public CatcherArea(Container droppedObjectContainer, BeatmapDifficulty difficulty = null) { Size = new Vector2(CatchPlayfield.WIDTH, CATCHER_SIZE); Children = new Drawable[] @@ -42,6 +41,8 @@ namespace osu.Game.Rulesets.Catch.UI public void OnNewResult(DrawableCatchHitObject hitObject, JudgementResult result) { + MovableCatcher.OnNewResult(hitObject, result); + if (!result.Type.IsScorable()) return; @@ -56,12 +57,10 @@ namespace osu.Game.Rulesets.Catch.UI comboDisplay.OnNewResult(hitObject, result); } - public void OnRevertResult(DrawableCatchHitObject fruit, JudgementResult result) - => comboDisplay.OnRevertResult(fruit, result); - - public bool AttemptCatch(CatchHitObject obj) + public void OnRevertResult(DrawableCatchHitObject hitObject, JudgementResult result) { - return MovableCatcher.AttemptCatch(obj); + comboDisplay.OnRevertResult(hitObject, result); + MovableCatcher.OnRevertResult(hitObject, result); } protected override void UpdateAfterChildren() diff --git a/osu.Game.Rulesets.Catch/UI/CatcherTrailDisplay.cs b/osu.Game.Rulesets.Catch/UI/CatcherTrailDisplay.cs index f7e9fd19a7..fa65190032 100644 --- a/osu.Game.Rulesets.Catch/UI/CatcherTrailDisplay.cs +++ b/osu.Game.Rulesets.Catch/UI/CatcherTrailDisplay.cs @@ -6,6 +6,7 @@ using JetBrains.Annotations; using osu.Framework.Graphics; using osu.Framework.Graphics.Animations; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Pooling; using osu.Framework.Graphics.Sprites; using osuTK; using osuTK.Graphics; @@ -20,6 +21,8 @@ namespace osu.Game.Rulesets.Catch.UI { private readonly Catcher catcher; + private readonly DrawablePool trailPool; + private readonly Container dashTrails; private readonly Container hyperDashTrails; private readonly Container endGlowSprites; @@ -80,8 +83,9 @@ namespace osu.Game.Rulesets.Catch.UI RelativeSizeAxes = Axes.Both; - InternalChildren = new[] + InternalChildren = new Drawable[] { + trailPool = new DrawablePool(30), dashTrails = new Container { RelativeSizeAxes = Axes.Both }, hyperDashTrails = new Container { RelativeSizeAxes = Axes.Both, Colour = Catcher.DEFAULT_HYPER_DASH_COLOUR }, endGlowSprites = new Container { RelativeSizeAxes = Axes.Both, Colour = Catcher.DEFAULT_HYPER_DASH_COLOUR }, @@ -118,14 +122,14 @@ namespace osu.Game.Rulesets.Catch.UI { var texture = (catcher.CurrentDrawableCatcher as TextureAnimation)?.CurrentFrame ?? ((Sprite)catcher.CurrentDrawableCatcher).Texture; - var sprite = new CatcherTrailSprite(texture) - { - Anchor = catcher.Anchor, - Scale = catcher.Scale, - Blending = BlendingParameters.Additive, - RelativePositionAxes = catcher.RelativePositionAxes, - Position = catcher.Position - }; + CatcherTrailSprite sprite = trailPool.Get(); + + sprite.Texture = texture; + sprite.Anchor = catcher.Anchor; + sprite.Scale = catcher.Scale; + sprite.Blending = BlendingParameters.Additive; + sprite.RelativePositionAxes = catcher.RelativePositionAxes; + sprite.Position = catcher.Position; target.Add(sprite); diff --git a/osu.Game.Rulesets.Catch/UI/CatcherTrailSprite.cs b/osu.Game.Rulesets.Catch/UI/CatcherTrailSprite.cs index 56cb7dbfda..0e3e409fac 100644 --- a/osu.Game.Rulesets.Catch/UI/CatcherTrailSprite.cs +++ b/osu.Game.Rulesets.Catch/UI/CatcherTrailSprite.cs @@ -1,22 +1,40 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using osu.Framework.Graphics; +using osu.Framework.Graphics.Pooling; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; using osuTK; namespace osu.Game.Rulesets.Catch.UI { - public class CatcherTrailSprite : Sprite + public class CatcherTrailSprite : PoolableDrawable { - public CatcherTrailSprite(Texture texture) + public Texture Texture { - Texture = texture; + set => sprite.Texture = value; + } + + private readonly Sprite sprite; + + public CatcherTrailSprite() + { + InternalChild = sprite = new Sprite + { + RelativeSizeAxes = Axes.Both + }; Size = new Vector2(CatcherArea.CATCHER_SIZE); // Sets the origin roughly to the centre of the catcher's plate to allow for correct scaling. OriginPosition = new Vector2(0.5f, 0.06f) * CatcherArea.CATCHER_SIZE; } + + protected override void FreeAfterUse() + { + ClearTransforms(); + base.FreeAfterUse(); + } } } diff --git a/osu.Game.Rulesets.Catch/UI/HitExplosion.cs b/osu.Game.Rulesets.Catch/UI/HitExplosion.cs index 24ca778248..26627422e1 100644 --- a/osu.Game.Rulesets.Catch/UI/HitExplosion.cs +++ b/osu.Game.Rulesets.Catch/UI/HitExplosion.cs @@ -7,6 +7,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Pooling; using osu.Framework.Utils; +using osu.Game.Rulesets.Catch.Objects; using osuTK; using osuTK.Graphics; @@ -15,6 +16,7 @@ namespace osu.Game.Rulesets.Catch.UI public class HitExplosion : PoolableDrawable { private Color4 objectColour; + public CatchHitObject HitObject; public Color4 ObjectColour { diff --git a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaHitObjectComposer.cs b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaHitObjectComposer.cs index c9551ee79e..aaf96c63a6 100644 --- a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaHitObjectComposer.cs +++ b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaHitObjectComposer.cs @@ -15,7 +15,7 @@ using osu.Game.Rulesets.Mania.Edit; using osu.Game.Rulesets.Mania.Edit.Blueprints; using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.Objects.Drawables; -using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces; +using osu.Game.Rulesets.Mania.Skinning.Default; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.UI.Scrolling; using osu.Game.Screens.Edit; diff --git a/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneHitExplosion.cs b/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneHitExplosion.cs index 0c56f7bcf4..4dc6700786 100644 --- a/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneHitExplosion.cs +++ b/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneHitExplosion.cs @@ -10,7 +10,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Pooling; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Mania.Judgements; -using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces; +using osu.Game.Rulesets.Mania.Skinning.Default; using osu.Game.Rulesets.Mania.UI; using osu.Game.Rulesets.Objects; using osuTK; diff --git a/osu.Game.Rulesets.Mania/Edit/Blueprints/Components/EditBodyPiece.cs b/osu.Game.Rulesets.Mania/Edit/Blueprints/Components/EditBodyPiece.cs index 5fa687298a..f5067ea366 100644 --- a/osu.Game.Rulesets.Mania/Edit/Blueprints/Components/EditBodyPiece.cs +++ b/osu.Game.Rulesets.Mania/Edit/Blueprints/Components/EditBodyPiece.cs @@ -4,7 +4,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Game.Graphics; -using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces; +using osu.Game.Rulesets.Mania.Skinning.Default; namespace osu.Game.Rulesets.Mania.Edit.Blueprints.Components { diff --git a/osu.Game.Rulesets.Mania/Edit/Blueprints/Components/EditNotePiece.cs b/osu.Game.Rulesets.Mania/Edit/Blueprints/Components/EditNotePiece.cs index 8773a39939..9c9273de3a 100644 --- a/osu.Game.Rulesets.Mania/Edit/Blueprints/Components/EditNotePiece.cs +++ b/osu.Game.Rulesets.Mania/Edit/Blueprints/Components/EditNotePiece.cs @@ -4,7 +4,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics.Containers; using osu.Game.Graphics; -using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces; +using osu.Game.Rulesets.Mania.Skinning.Default; namespace osu.Game.Rulesets.Mania.Edit.Blueprints.Components { diff --git a/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs b/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs index 01d572447b..324670c4b2 100644 --- a/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs +++ b/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs @@ -9,7 +9,7 @@ using System.Collections.Generic; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Input; -using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces; +using osu.Game.Rulesets.Mania.Skinning.Default; using osu.Game.Rulesets.Mania.UI; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Objects; diff --git a/osu.Game.Rulesets.Mania/ManiaRuleset.cs b/osu.Game.Rulesets.Mania/ManiaRuleset.cs index 906f7382c5..59c766fd84 100644 --- a/osu.Game.Rulesets.Mania/ManiaRuleset.cs +++ b/osu.Game.Rulesets.Mania/ManiaRuleset.cs @@ -26,7 +26,7 @@ using osu.Game.Rulesets.Mania.Configuration; using osu.Game.Rulesets.Mania.Difficulty; using osu.Game.Rulesets.Mania.Edit; using osu.Game.Rulesets.Mania.Scoring; -using osu.Game.Rulesets.Mania.Skinning; +using osu.Game.Rulesets.Mania.Skinning.Legacy; using osu.Game.Rulesets.Scoring; using osu.Game.Skinning; using osu.Game.Scoring; diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs index a64cc6dc67..4f062753a6 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs @@ -4,9 +4,9 @@ using System; using osu.Framework.Bindables; using osu.Framework.Graphics; -using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces; using osu.Framework.Graphics.Containers; using osu.Framework.Input.Bindings; +using osu.Game.Rulesets.Mania.Skinning.Default; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Scoring; diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs index b3402d13e4..b512986ccb 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs @@ -5,7 +5,7 @@ using System.Diagnostics; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Input.Bindings; -using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces; +using osu.Game.Rulesets.Mania.Skinning.Default; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.UI.Scrolling; using osu.Game.Skinning; diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/DefaultBodyPiece.cs b/osu.Game.Rulesets.Mania/Skinning/Default/DefaultBodyPiece.cs similarity index 98% rename from osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/DefaultBodyPiece.cs rename to osu.Game.Rulesets.Mania/Skinning/Default/DefaultBodyPiece.cs index 9999983af5..db1ac6da88 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/DefaultBodyPiece.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Default/DefaultBodyPiece.cs @@ -5,16 +5,17 @@ using System; using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Bindables; -using osuTK.Graphics; 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.Framework.Layout; +using osu.Game.Rulesets.Mania.Objects.Drawables; using osu.Game.Rulesets.Objects.Drawables; +using osuTK.Graphics; -namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces +namespace osu.Game.Rulesets.Mania.Skinning.Default { /// /// Represents length-wise portion of a hold note. diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/DefaultNotePiece.cs b/osu.Game.Rulesets.Mania/Skinning/Default/DefaultNotePiece.cs similarity index 97% rename from osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/DefaultNotePiece.cs rename to osu.Game.Rulesets.Mania/Skinning/Default/DefaultNotePiece.cs index 29f5217fd8..c9c3cff799 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/DefaultNotePiece.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Default/DefaultNotePiece.cs @@ -4,7 +4,6 @@ using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Bindables; -using osuTK.Graphics; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -12,8 +11,9 @@ using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Shapes; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.UI.Scrolling; +using osuTK.Graphics; -namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces +namespace osu.Game.Rulesets.Mania.Skinning.Default { /// /// Represents the static hit markers of notes. diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/IHoldNoteBody.cs b/osu.Game.Rulesets.Mania/Skinning/Default/IHoldNoteBody.cs similarity index 88% rename from osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/IHoldNoteBody.cs rename to osu.Game.Rulesets.Mania/Skinning/Default/IHoldNoteBody.cs index ac3792c01d..1f290f1f1c 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/IHoldNoteBody.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Default/IHoldNoteBody.cs @@ -1,7 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces +namespace osu.Game.Rulesets.Mania.Skinning.Default { /// /// Interface for mania hold note bodies. diff --git a/osu.Game.Rulesets.Mania/Skinning/HitTargetInsetContainer.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/HitTargetInsetContainer.cs similarity index 96% rename from osu.Game.Rulesets.Mania/Skinning/HitTargetInsetContainer.cs rename to osu.Game.Rulesets.Mania/Skinning/Legacy/HitTargetInsetContainer.cs index c8b05ed2f8..3c89e2c04a 100644 --- a/osu.Game.Rulesets.Mania/Skinning/HitTargetInsetContainer.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/HitTargetInsetContainer.cs @@ -9,7 +9,7 @@ using osu.Game.Rulesets.Mania.UI; using osu.Game.Rulesets.UI.Scrolling; using osu.Game.Skinning; -namespace osu.Game.Rulesets.Mania.Skinning +namespace osu.Game.Rulesets.Mania.Skinning.Legacy { public class HitTargetInsetContainer : Container { diff --git a/osu.Game.Rulesets.Mania/Skinning/LegacyBodyPiece.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyBodyPiece.cs similarity index 99% rename from osu.Game.Rulesets.Mania/Skinning/LegacyBodyPiece.cs rename to osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyBodyPiece.cs index 8902d82f33..31db08ce2f 100644 --- a/osu.Game.Rulesets.Mania/Skinning/LegacyBodyPiece.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyBodyPiece.cs @@ -14,7 +14,7 @@ using osu.Game.Rulesets.UI.Scrolling; using osu.Game.Skinning; using osuTK; -namespace osu.Game.Rulesets.Mania.Skinning +namespace osu.Game.Rulesets.Mania.Skinning.Legacy { public class LegacyBodyPiece : LegacyManiaColumnElement { diff --git a/osu.Game.Rulesets.Mania/Skinning/LegacyColumnBackground.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyColumnBackground.cs similarity index 98% rename from osu.Game.Rulesets.Mania/Skinning/LegacyColumnBackground.cs rename to osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyColumnBackground.cs index 3bf51b3073..661e7f66f4 100644 --- a/osu.Game.Rulesets.Mania/Skinning/LegacyColumnBackground.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyColumnBackground.cs @@ -12,7 +12,7 @@ using osu.Game.Skinning; using osuTK; using osuTK.Graphics; -namespace osu.Game.Rulesets.Mania.Skinning +namespace osu.Game.Rulesets.Mania.Skinning.Legacy { public class LegacyColumnBackground : LegacyManiaColumnElement, IKeyBindingHandler { diff --git a/osu.Game.Rulesets.Mania/Skinning/LegacyHitExplosion.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyHitExplosion.cs similarity index 98% rename from osu.Game.Rulesets.Mania/Skinning/LegacyHitExplosion.cs rename to osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyHitExplosion.cs index 7c5d41efcf..73aece1ed4 100644 --- a/osu.Game.Rulesets.Mania/Skinning/LegacyHitExplosion.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyHitExplosion.cs @@ -13,7 +13,7 @@ using osu.Game.Rulesets.UI.Scrolling; using osu.Game.Skinning; using osuTK; -namespace osu.Game.Rulesets.Mania.Skinning +namespace osu.Game.Rulesets.Mania.Skinning.Legacy { public class LegacyHitExplosion : LegacyManiaColumnElement, IHitExplosion { diff --git a/osu.Game.Rulesets.Mania/Skinning/LegacyHitTarget.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyHitTarget.cs similarity index 98% rename from osu.Game.Rulesets.Mania/Skinning/LegacyHitTarget.cs rename to osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyHitTarget.cs index 6eced571d2..490a03d11a 100644 --- a/osu.Game.Rulesets.Mania/Skinning/LegacyHitTarget.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyHitTarget.cs @@ -12,7 +12,7 @@ using osu.Game.Skinning; using osuTK; using osuTK.Graphics; -namespace osu.Game.Rulesets.Mania.Skinning +namespace osu.Game.Rulesets.Mania.Skinning.Legacy { public class LegacyHitTarget : CompositeDrawable { diff --git a/osu.Game.Rulesets.Mania/Skinning/LegacyHoldNoteHeadPiece.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyHoldNoteHeadPiece.cs similarity index 92% rename from osu.Game.Rulesets.Mania/Skinning/LegacyHoldNoteHeadPiece.cs rename to osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyHoldNoteHeadPiece.cs index c5aa062d0f..21e5bdd5d6 100644 --- a/osu.Game.Rulesets.Mania/Skinning/LegacyHoldNoteHeadPiece.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyHoldNoteHeadPiece.cs @@ -4,7 +4,7 @@ using osu.Framework.Graphics.Textures; using osu.Game.Skinning; -namespace osu.Game.Rulesets.Mania.Skinning +namespace osu.Game.Rulesets.Mania.Skinning.Legacy { public class LegacyHoldNoteHeadPiece : LegacyNotePiece { diff --git a/osu.Game.Rulesets.Mania/Skinning/LegacyHoldNoteTailPiece.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyHoldNoteTailPiece.cs similarity index 96% rename from osu.Game.Rulesets.Mania/Skinning/LegacyHoldNoteTailPiece.cs rename to osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyHoldNoteTailPiece.cs index 2e8259f10a..232b47ae27 100644 --- a/osu.Game.Rulesets.Mania/Skinning/LegacyHoldNoteTailPiece.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyHoldNoteTailPiece.cs @@ -6,7 +6,7 @@ using osu.Framework.Graphics.Textures; using osu.Game.Rulesets.UI.Scrolling; using osu.Game.Skinning; -namespace osu.Game.Rulesets.Mania.Skinning +namespace osu.Game.Rulesets.Mania.Skinning.Legacy { public class LegacyHoldNoteTailPiece : LegacyNotePiece { diff --git a/osu.Game.Rulesets.Mania/Skinning/LegacyKeyArea.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyKeyArea.cs similarity index 98% rename from osu.Game.Rulesets.Mania/Skinning/LegacyKeyArea.cs rename to osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyKeyArea.cs index b269ea25d4..78ccb83a8c 100644 --- a/osu.Game.Rulesets.Mania/Skinning/LegacyKeyArea.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyKeyArea.cs @@ -12,7 +12,7 @@ using osu.Game.Rulesets.UI.Scrolling; using osu.Game.Skinning; using osuTK; -namespace osu.Game.Rulesets.Mania.Skinning +namespace osu.Game.Rulesets.Mania.Skinning.Legacy { public class LegacyKeyArea : LegacyManiaColumnElement, IKeyBindingHandler { diff --git a/osu.Game.Rulesets.Mania/Skinning/LegacyManiaColumnElement.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyManiaColumnElement.cs similarity index 96% rename from osu.Game.Rulesets.Mania/Skinning/LegacyManiaColumnElement.cs rename to osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyManiaColumnElement.cs index 3c0c632c14..eb5514ba43 100644 --- a/osu.Game.Rulesets.Mania/Skinning/LegacyManiaColumnElement.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyManiaColumnElement.cs @@ -8,7 +8,7 @@ using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Mania.UI; using osu.Game.Skinning; -namespace osu.Game.Rulesets.Mania.Skinning +namespace osu.Game.Rulesets.Mania.Skinning.Legacy { /// /// A which is placed somewhere within a . diff --git a/osu.Game.Rulesets.Mania/Skinning/LegacyNotePiece.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyNotePiece.cs similarity index 98% rename from osu.Game.Rulesets.Mania/Skinning/LegacyNotePiece.cs rename to osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyNotePiece.cs index 283b04373b..31279796ce 100644 --- a/osu.Game.Rulesets.Mania/Skinning/LegacyNotePiece.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyNotePiece.cs @@ -12,7 +12,7 @@ using osu.Game.Rulesets.UI.Scrolling; using osu.Game.Skinning; using osuTK; -namespace osu.Game.Rulesets.Mania.Skinning +namespace osu.Game.Rulesets.Mania.Skinning.Legacy { public class LegacyNotePiece : LegacyManiaColumnElement { diff --git a/osu.Game.Rulesets.Mania/Skinning/LegacyStageBackground.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyStageBackground.cs similarity index 99% rename from osu.Game.Rulesets.Mania/Skinning/LegacyStageBackground.cs rename to osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyStageBackground.cs index b0bab8e760..fec3e9493e 100644 --- a/osu.Game.Rulesets.Mania/Skinning/LegacyStageBackground.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyStageBackground.cs @@ -12,7 +12,7 @@ using osu.Game.Skinning; using osuTK; using osuTK.Graphics; -namespace osu.Game.Rulesets.Mania.Skinning +namespace osu.Game.Rulesets.Mania.Skinning.Legacy { public class LegacyStageBackground : CompositeDrawable { diff --git a/osu.Game.Rulesets.Mania/Skinning/LegacyStageForeground.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyStageForeground.cs similarity index 97% rename from osu.Game.Rulesets.Mania/Skinning/LegacyStageForeground.cs rename to osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyStageForeground.cs index 4609fcc849..4e1952a670 100644 --- a/osu.Game.Rulesets.Mania/Skinning/LegacyStageForeground.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyStageForeground.cs @@ -9,7 +9,7 @@ using osu.Game.Rulesets.UI.Scrolling; using osu.Game.Skinning; using osuTK; -namespace osu.Game.Rulesets.Mania.Skinning +namespace osu.Game.Rulesets.Mania.Skinning.Legacy { public class LegacyStageForeground : CompositeDrawable { diff --git a/osu.Game.Rulesets.Mania/Skinning/ManiaLegacySkinTransformer.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs similarity index 99% rename from osu.Game.Rulesets.Mania/Skinning/ManiaLegacySkinTransformer.cs rename to osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs index 3724269f4d..89f639e2fe 100644 --- a/osu.Game.Rulesets.Mania/Skinning/ManiaLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs @@ -2,19 +2,19 @@ // See the LICENCE file in the repository root for full licence text. using System; -using osu.Framework.Graphics; -using osu.Framework.Bindables; -using osu.Game.Rulesets.Scoring; -using osu.Game.Beatmaps; -using osu.Game.Rulesets.Mania.Beatmaps; -using osu.Game.Skinning; using System.Collections.Generic; using System.Diagnostics; using osu.Framework.Audio.Sample; +using osu.Framework.Bindables; +using osu.Framework.Graphics; using osu.Game.Audio; +using osu.Game.Beatmaps; +using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Objects.Legacy; +using osu.Game.Rulesets.Scoring; +using osu.Game.Skinning; -namespace osu.Game.Rulesets.Mania.Skinning +namespace osu.Game.Rulesets.Mania.Skinning.Legacy { public class ManiaLegacySkinTransformer : LegacySkinTransformer { diff --git a/osu.Game.Rulesets.Mania/UI/Components/DefaultHitTarget.cs b/osu.Game.Rulesets.Mania/UI/Components/DefaultHitTarget.cs index e0b099ab9b..ec6c377a2e 100644 --- a/osu.Game.Rulesets.Mania/UI/Components/DefaultHitTarget.cs +++ b/osu.Game.Rulesets.Mania/UI/Components/DefaultHitTarget.cs @@ -8,7 +8,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Shapes; -using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces; +using osu.Game.Rulesets.Mania.Skinning.Default; using osu.Game.Rulesets.UI.Scrolling; using osuTK.Graphics; diff --git a/osu.Game.Rulesets.Mania/UI/DefaultHitExplosion.cs b/osu.Game.Rulesets.Mania/UI/DefaultHitExplosion.cs index 225269cf48..69b81d6d5c 100644 --- a/osu.Game.Rulesets.Mania/UI/DefaultHitExplosion.cs +++ b/osu.Game.Rulesets.Mania/UI/DefaultHitExplosion.cs @@ -10,7 +10,7 @@ using osu.Framework.Graphics.Effects; using osu.Framework.Utils; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Mania.Judgements; -using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces; +using osu.Game.Rulesets.Mania.Skinning.Default; using osu.Game.Rulesets.UI.Scrolling; using osuTK; using osuTK.Graphics; diff --git a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModSpunOut.cs b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModSpunOut.cs index 7b909d2907..7df5ca0f7c 100644 --- a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModSpunOut.cs +++ b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModSpunOut.cs @@ -13,7 +13,7 @@ using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Osu.Mods; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; -using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; +using osu.Game.Rulesets.Osu.Skinning.Default; using osuTK; namespace osu.Game.Rulesets.Osu.Tests.Mods diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneCursorTrail.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneCursorTrail.cs index dde02e873b..fefe983f97 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneCursorTrail.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneCursorTrail.cs @@ -12,7 +12,7 @@ using osu.Framework.Graphics.OpenGL.Textures; using osu.Framework.Graphics.Textures; using osu.Framework.Testing.Input; using osu.Game.Audio; -using osu.Game.Rulesets.Osu.Skinning; +using osu.Game.Rulesets.Osu.Skinning.Legacy; using osu.Game.Rulesets.Osu.UI.Cursor; using osu.Game.Skinning; using osu.Game.Tests.Visual; diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSliderApplication.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSliderApplication.cs index 084af7dafe..aac6db60fe 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneSliderApplication.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSliderApplication.cs @@ -12,7 +12,7 @@ using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; -using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; +using osu.Game.Rulesets.Osu.Skinning.Default; using osu.Game.Skinning; using osu.Game.Tests.Visual; using osuTK; diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSliderSnaking.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSliderSnaking.cs index b71400b71d..e111bb1054 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneSliderSnaking.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSliderSnaking.cs @@ -19,7 +19,7 @@ using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Osu.Configuration; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; -using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; +using osu.Game.Rulesets.Osu.Skinning.Default; using osu.Game.Storyboards; using osuTK; diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs index fff033357d..e8ac60bc5e 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs @@ -12,5 +12,6 @@ namespace osu.Game.Rulesets.Osu.Difficulty public double ApproachRate; public double OverallDifficulty; public int HitCircleCount; + public int SpinnerCount; } } diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs index 6027635b75..6a7d76151c 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs @@ -48,6 +48,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty maxCombo += beatmap.HitObjects.OfType().Sum(s => s.NestedHitObjects.Count - 1); int hitCirclesCount = beatmap.HitObjects.Count(h => h is HitCircle); + int spinnerCount = beatmap.HitObjects.Count(h => h is Spinner); return new OsuDifficultyAttributes { @@ -59,6 +60,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty OverallDifficulty = (80 - hitWindowGreat) / 6, MaxCombo = maxCombo, HitCircleCount = hitCirclesCount, + SpinnerCount = spinnerCount, Skills = skills }; } diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs index 063cde8747..030b0cf6d1 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -52,7 +52,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty multiplier *= 0.90; if (mods.Any(m => m is OsuModSpunOut)) - multiplier *= 0.95; + multiplier *= 1.0 - Math.Pow((double)Attributes.SpinnerCount / totalHits, 0.85); double aimValue = computeAimValue(); double speedValue = computeSpeedValue(); @@ -99,16 +99,13 @@ namespace osu.Game.Rulesets.Osu.Difficulty if (Attributes.MaxCombo > 0) aimValue *= Math.Min(Math.Pow(scoreMaxCombo, 0.8) / Math.Pow(Attributes.MaxCombo, 0.8), 1.0); - double approachRateFactor = 1.0; - + double approachRateFactor = 0.0; if (Attributes.ApproachRate > 10.33) - approachRateFactor += 0.3 * (Attributes.ApproachRate - 10.33); + approachRateFactor += 0.4 * (Attributes.ApproachRate - 10.33); else if (Attributes.ApproachRate < 8.0) - { - approachRateFactor += 0.01 * (8.0 - Attributes.ApproachRate); - } + approachRateFactor += 0.1 * (8.0 - Attributes.ApproachRate); - aimValue *= approachRateFactor; + aimValue *= 1.0 + Math.Min(approachRateFactor, approachRateFactor * (totalHits / 1000.0)); // We want to give more reward for lower AR when it comes to aim and HD. This nerfs high AR and buffs lower AR. if (mods.Any(h => h is OsuModHidden)) @@ -137,8 +134,9 @@ namespace osu.Game.Rulesets.Osu.Difficulty double speedValue = Math.Pow(5.0 * Math.Max(1.0, Attributes.SpeedStrain / 0.0675) - 4.0, 3.0) / 100000.0; // Longer maps are worth more - speedValue *= 0.95 + 0.4 * Math.Min(1.0, totalHits / 2000.0) + - (totalHits > 2000 ? Math.Log10(totalHits / 2000.0) * 0.5 : 0.0); + double lengthBonus = 0.95 + 0.4 * Math.Min(1.0, totalHits / 2000.0) + + (totalHits > 2000 ? Math.Log10(totalHits / 2000.0) * 0.5 : 0.0); + speedValue *= lengthBonus; // Penalize misses exponentially. This mainly fixes tag4 maps and the likes until a per-hitobject solution is available speedValue *= Math.Pow(0.97, countMiss); @@ -147,11 +145,11 @@ namespace osu.Game.Rulesets.Osu.Difficulty if (Attributes.MaxCombo > 0) speedValue *= Math.Min(Math.Pow(scoreMaxCombo, 0.8) / Math.Pow(Attributes.MaxCombo, 0.8), 1.0); - double approachRateFactor = 1.0; + double approachRateFactor = 0.0; if (Attributes.ApproachRate > 10.33) - approachRateFactor += 0.3 * (Attributes.ApproachRate - 10.33); + approachRateFactor += 0.4 * (Attributes.ApproachRate - 10.33); - speedValue *= approachRateFactor; + speedValue *= 1.0 + Math.Min(approachRateFactor, approachRateFactor * (totalHits / 1000.0)); if (mods.Any(m => m is OsuModHidden)) speedValue *= 1.0 + 0.04 * (12.0 - Attributes.ApproachRate); diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCirclePiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCirclePiece.cs index 2868ddeaa4..0cfc67cedb 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCirclePiece.cs @@ -5,7 +5,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Game.Graphics; using osu.Game.Rulesets.Osu.Objects; -using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; +using osu.Game.Rulesets.Osu.Skinning.Default; using osuTK; namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs index 5581ce4bfd..1c3d270c95 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs @@ -5,7 +5,7 @@ using System.Collections.Generic; using osu.Framework.Allocation; using osu.Game.Graphics; using osu.Game.Rulesets.Osu.Objects; -using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; +using osu.Game.Rulesets.Osu.Skinning.Default; using osuTK; using osuTK.Graphics; diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/Components/SpinnerPiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/Components/SpinnerPiece.cs index 2347d8a34c..92961b40bc 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/Components/SpinnerPiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/Components/SpinnerPiece.cs @@ -7,7 +7,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; using osu.Game.Rulesets.Osu.Objects; -using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; +using osu.Game.Rulesets.Osu.Skinning.Default; using osuTK; namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners.Components diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs b/osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs index b7e60295cb..df0a41455f 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs @@ -7,7 +7,7 @@ using osu.Framework.Graphics; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Osu.Objects.Drawables; -using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; +using osu.Game.Rulesets.Osu.Skinning.Default; namespace osu.Game.Rulesets.Osu.Mods { diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs index abb51ae420..3c0260f5f5 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs @@ -12,7 +12,7 @@ using osu.Framework.Input.Bindings; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Osu.Judgements; -using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; +using osu.Game.Rulesets.Osu.Skinning.Default; using osu.Game.Rulesets.Scoring; using osu.Game.Skinning; using osuTK; diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs index af5b609ec8..511cbc2347 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs @@ -7,13 +7,13 @@ using JetBrains.Annotations; using osuTK; using osu.Framework.Graphics; using osu.Game.Rulesets.Objects.Drawables; -using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics.Containers; using osu.Game.Audio; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Osu.Skinning; +using osu.Game.Rulesets.Osu.Skinning.Default; using osu.Game.Rulesets.Osu.UI; using osuTK.Graphics; using osu.Game.Skinning; diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderRepeat.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderRepeat.cs index a684df98cb..76490e0de1 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderRepeat.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderRepeat.cs @@ -9,7 +9,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Utils; using osu.Game.Rulesets.Objects.Drawables; -using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; +using osu.Game.Rulesets.Osu.Skinning.Default; using osu.Game.Skinning; using osuTK; diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs index aea37acf6f..1f3bcece0c 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs @@ -15,8 +15,8 @@ using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Osu.Judgements; -using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; using osu.Game.Rulesets.Osu.Skinning; +using osu.Game.Rulesets.Osu.Skinning.Default; using osu.Game.Rulesets.Scoring; using osu.Game.Screens.Ranking; using osu.Game.Skinning; diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs index d8180b0e58..cba0c5be14 100644 --- a/osu.Game.Rulesets.Osu/OsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs @@ -24,13 +24,13 @@ using osu.Game.Rulesets.Osu.Beatmaps; using osu.Game.Rulesets.Osu.Configuration; using osu.Game.Rulesets.Osu.Difficulty; using osu.Game.Rulesets.Osu.Scoring; -using osu.Game.Rulesets.Osu.Skinning; using osu.Game.Rulesets.Scoring; using osu.Game.Scoring; using osu.Game.Skinning; using System; using System.Linq; using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Osu.Skinning.Legacy; using osu.Game.Rulesets.Osu.Statistics; using osu.Game.Screens.Ranking.Statistics; diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ApproachCircle.cs b/osu.Game.Rulesets.Osu/Skinning/Default/ApproachCircle.cs similarity index 96% rename from osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ApproachCircle.cs rename to osu.Game.Rulesets.Osu/Skinning/Default/ApproachCircle.cs index 1b474f265c..62f00a2b49 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ApproachCircle.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/ApproachCircle.cs @@ -8,7 +8,7 @@ using osu.Framework.Graphics.Textures; using osu.Game.Skinning; using osuTK; -namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces +namespace osu.Game.Rulesets.Osu.Skinning.Default { public class ApproachCircle : Container { diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/CirclePiece.cs b/osu.Game.Rulesets.Osu/Skinning/Default/CirclePiece.cs similarity index 95% rename from osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/CirclePiece.cs rename to osu.Game.Rulesets.Osu/Skinning/Default/CirclePiece.cs index d0e1055dce..ba41ebd445 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/CirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/CirclePiece.cs @@ -7,9 +7,10 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.Osu.Objects; using osuTK; -namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces +namespace osu.Game.Rulesets.Osu.Skinning.Default { public class CirclePiece : CompositeDrawable { diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/DefaultSpinnerDisc.cs b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultSpinnerDisc.cs similarity index 98% rename from osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/DefaultSpinnerDisc.cs rename to osu.Game.Rulesets.Osu/Skinning/Default/DefaultSpinnerDisc.cs index 14ce3b014d..667fee1495 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/DefaultSpinnerDisc.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultSpinnerDisc.cs @@ -10,10 +10,12 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Utils; using osu.Game.Graphics; using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Osu.Objects.Drawables; using osuTK; using osuTK.Graphics; -namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces +namespace osu.Game.Rulesets.Osu.Skinning.Default { public class DefaultSpinnerDisc : CompositeDrawable { diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/DrawableSliderPath.cs b/osu.Game.Rulesets.Osu/Skinning/Default/DrawableSliderPath.cs similarity index 96% rename from osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/DrawableSliderPath.cs rename to osu.Game.Rulesets.Osu/Skinning/Default/DrawableSliderPath.cs index c31d6beb01..db077f009d 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/DrawableSliderPath.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/DrawableSliderPath.cs @@ -4,7 +4,7 @@ using osu.Framework.Graphics.Lines; using osuTK.Graphics; -namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces +namespace osu.Game.Rulesets.Osu.Skinning.Default { public abstract class DrawableSliderPath : SmoothPath { diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ExplodePiece.cs b/osu.Game.Rulesets.Osu/Skinning/Default/ExplodePiece.cs similarity index 94% rename from osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ExplodePiece.cs rename to osu.Game.Rulesets.Osu/Skinning/Default/ExplodePiece.cs index 09299a3622..510ed225a8 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ExplodePiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/ExplodePiece.cs @@ -5,9 +5,10 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.Osu.Objects; using osuTK; -namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces +namespace osu.Game.Rulesets.Osu.Skinning.Default { public class ExplodePiece : Container { diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/FlashPiece.cs b/osu.Game.Rulesets.Osu/Skinning/Default/FlashPiece.cs similarity index 90% rename from osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/FlashPiece.cs rename to osu.Game.Rulesets.Osu/Skinning/Default/FlashPiece.cs index 038a2299e9..06ee64d8b3 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/FlashPiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/FlashPiece.cs @@ -3,10 +3,11 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osuTK; using osu.Framework.Graphics.Shapes; +using osu.Game.Rulesets.Osu.Objects; +using osuTK; -namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces +namespace osu.Game.Rulesets.Osu.Skinning.Default { public class FlashPiece : Container { diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/GlowPiece.cs b/osu.Game.Rulesets.Osu/Skinning/Default/GlowPiece.cs similarity index 94% rename from osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/GlowPiece.cs rename to osu.Game.Rulesets.Osu/Skinning/Default/GlowPiece.cs index 30937313fd..f5e01b802e 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/GlowPiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/GlowPiece.cs @@ -7,7 +7,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; -namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces +namespace osu.Game.Rulesets.Osu.Skinning.Default { public class GlowPiece : Container { diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/MainCirclePiece.cs b/osu.Game.Rulesets.Osu/Skinning/Default/MainCirclePiece.cs similarity index 96% rename from osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/MainCirclePiece.cs rename to osu.Game.Rulesets.Osu/Skinning/Default/MainCirclePiece.cs index 102166f8dd..fcbe4c1b28 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/MainCirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/MainCirclePiece.cs @@ -6,10 +6,12 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Osu.Objects.Drawables; using osuTK; using osuTK.Graphics; -namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces +namespace osu.Game.Rulesets.Osu.Skinning.Default { public class MainCirclePiece : CompositeDrawable { diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ManualSliderBody.cs b/osu.Game.Rulesets.Osu/Skinning/Default/ManualSliderBody.cs similarity index 90% rename from osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ManualSliderBody.cs rename to osu.Game.Rulesets.Osu/Skinning/Default/ManualSliderBody.cs index d69df1d5c2..d73c94eb9b 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ManualSliderBody.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/ManualSliderBody.cs @@ -4,7 +4,7 @@ using System.Collections.Generic; using osuTK; -namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces +namespace osu.Game.Rulesets.Osu.Skinning.Default { /// /// A with the ability to set the drawn vertices manually. diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/NumberPiece.cs b/osu.Game.Rulesets.Osu/Skinning/Default/NumberPiece.cs similarity index 96% rename from osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/NumberPiece.cs rename to osu.Game.Rulesets.Osu/Skinning/Default/NumberPiece.cs index 7c94568835..bea6186501 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/NumberPiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/NumberPiece.cs @@ -5,12 +5,12 @@ using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Effects; -using osu.Game.Graphics.Sprites; -using osuTK.Graphics; using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; using osu.Game.Skinning; +using osuTK.Graphics; -namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces +namespace osu.Game.Rulesets.Osu.Skinning.Default { public class NumberPiece : Container { diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/PlaySliderBody.cs b/osu.Game.Rulesets.Osu/Skinning/Default/PlaySliderBody.cs similarity index 93% rename from osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/PlaySliderBody.cs rename to osu.Game.Rulesets.Osu/Skinning/Default/PlaySliderBody.cs index 29dff53f54..e77c93c721 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/PlaySliderBody.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/PlaySliderBody.cs @@ -5,11 +5,12 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Osu.Configuration; -using osu.Game.Rulesets.Osu.Skinning; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Skinning; using osuTK.Graphics; -namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces +namespace osu.Game.Rulesets.Osu.Skinning.Default { public abstract class PlaySliderBody : SnakingSliderBody { diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ReverseArrowPiece.cs b/osu.Game.Rulesets.Osu/Skinning/Default/ReverseArrowPiece.cs similarity index 94% rename from osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ReverseArrowPiece.cs rename to osu.Game.Rulesets.Osu/Skinning/Default/ReverseArrowPiece.cs index ae43006e76..0009ffc586 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ReverseArrowPiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/ReverseArrowPiece.cs @@ -1,17 +1,18 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using osu.Framework.Allocation; using osu.Framework.Audio.Track; using osu.Framework.Graphics; -using osuTK; using osu.Framework.Graphics.Sprites; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Graphics.Containers; -using osu.Game.Skinning; -using osu.Framework.Allocation; using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Skinning; +using osuTK; -namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces +namespace osu.Game.Rulesets.Osu.Skinning.Default { public class ReverseArrowPiece : BeatSyncedContainer { diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/RingPiece.cs b/osu.Game.Rulesets.Osu/Skinning/Default/RingPiece.cs similarity index 91% rename from osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/RingPiece.cs rename to osu.Game.Rulesets.Osu/Skinning/Default/RingPiece.cs index 619fea73bc..7f10a7bf56 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/RingPiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/RingPiece.cs @@ -3,11 +3,12 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Game.Rulesets.Osu.Objects; using osuTK; using osuTK.Graphics; -using osu.Framework.Graphics.Shapes; -namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces +namespace osu.Game.Rulesets.Osu.Skinning.Default { public class RingPiece : CircularContainer { diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBall.cs b/osu.Game.Rulesets.Osu/Skinning/Default/SliderBall.cs similarity index 98% rename from osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBall.cs rename to osu.Game.Rulesets.Osu/Skinning/Default/SliderBall.cs index ca5ca7ac59..a96beb66d4 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBall.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/SliderBall.cs @@ -10,15 +10,16 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Input; using osu.Framework.Input.Events; +using osu.Game.Graphics; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Types; -using osu.Game.Rulesets.Osu.Skinning; -using osuTK.Graphics; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Skinning; using osuTK; -using osu.Game.Graphics; +using osuTK.Graphics; -namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces +namespace osu.Game.Rulesets.Osu.Skinning.Default { public class SliderBall : CircularContainer, ISliderProgress, IRequireHighFrequencyMousePosition, IHasAccentColour { diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBody.cs b/osu.Game.Rulesets.Osu/Skinning/Default/SliderBody.cs similarity index 98% rename from osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBody.cs rename to osu.Game.Rulesets.Osu/Skinning/Default/SliderBody.cs index 8758a4a066..7e6df759f8 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBody.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/SliderBody.cs @@ -9,7 +9,7 @@ using osu.Framework.Graphics.Lines; using osuTK; using osuTK.Graphics; -namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces +namespace osu.Game.Rulesets.Osu.Skinning.Default { public abstract class SliderBody : CompositeDrawable { diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SnakingSliderBody.cs b/osu.Game.Rulesets.Osu/Skinning/Default/SnakingSliderBody.cs similarity index 97% rename from osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SnakingSliderBody.cs rename to osu.Game.Rulesets.Osu/Skinning/Default/SnakingSliderBody.cs index 8835a0d84a..ed4e04184b 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SnakingSliderBody.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/SnakingSliderBody.cs @@ -8,9 +8,11 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Types; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Osu.Objects.Drawables; using osuTK; -namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces +namespace osu.Game.Rulesets.Osu.Skinning.Default { /// /// A which changes its curve depending on the snaking progress. diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/SpinnerBackgroundLayer.cs b/osu.Game.Rulesets.Osu/Skinning/Default/SpinnerBackgroundLayer.cs similarity index 85% rename from osu.Game.Rulesets.Osu/Objects/Drawables/SpinnerBackgroundLayer.cs rename to osu.Game.Rulesets.Osu/Skinning/Default/SpinnerBackgroundLayer.cs index 3cd2454706..f8a6e1d3c9 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/SpinnerBackgroundLayer.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/SpinnerBackgroundLayer.cs @@ -5,9 +5,8 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Game.Graphics; using osu.Game.Rulesets.Objects.Drawables; -using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; -namespace osu.Game.Rulesets.Osu.Objects.Drawables +namespace osu.Game.Rulesets.Osu.Skinning.Default { public class SpinnerBackgroundLayer : SpinnerFill { diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerBonusDisplay.cs b/osu.Game.Rulesets.Osu/Skinning/Default/SpinnerBonusDisplay.cs similarity index 94% rename from osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerBonusDisplay.cs rename to osu.Game.Rulesets.Osu/Skinning/Default/SpinnerBonusDisplay.cs index f483bb1b26..c0db6228ef 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerBonusDisplay.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/SpinnerBonusDisplay.cs @@ -5,8 +5,9 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; +using osu.Game.Rulesets.Osu.Objects; -namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces +namespace osu.Game.Rulesets.Osu.Skinning.Default { /// /// Shows incremental bonus score achieved for a spinner. diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/SpinnerCentreLayer.cs b/osu.Game.Rulesets.Osu/Skinning/Default/SpinnerCentreLayer.cs similarity index 95% rename from osu.Game.Rulesets.Osu/Objects/Drawables/SpinnerCentreLayer.cs rename to osu.Game.Rulesets.Osu/Skinning/Default/SpinnerCentreLayer.cs index b62ce822f0..67b5ed5410 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/SpinnerCentreLayer.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/SpinnerCentreLayer.cs @@ -9,11 +9,11 @@ using osu.Framework.Graphics.Sprites; using osu.Framework.Utils; using osu.Game.Graphics; using osu.Game.Rulesets.Objects.Drawables; -using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; +using osu.Game.Rulesets.Osu.Objects.Drawables; using osuTK; using osuTK.Graphics; -namespace osu.Game.Rulesets.Osu.Objects.Drawables +namespace osu.Game.Rulesets.Osu.Skinning.Default { public class SpinnerCentreLayer : CompositeDrawable, IHasAccentColour { diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerFill.cs b/osu.Game.Rulesets.Osu/Skinning/Default/SpinnerFill.cs similarity index 96% rename from osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerFill.cs rename to osu.Game.Rulesets.Osu/Skinning/Default/SpinnerFill.cs index 043bc5618c..f574ae589e 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerFill.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/SpinnerFill.cs @@ -8,7 +8,7 @@ using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; using osuTK.Graphics; -namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces +namespace osu.Game.Rulesets.Osu.Skinning.Default { public class SpinnerFill : CircularContainer, IHasAccentColour { diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerRotationTracker.cs b/osu.Game.Rulesets.Osu/Skinning/Default/SpinnerRotationTracker.cs similarity index 97% rename from osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerRotationTracker.cs rename to osu.Game.Rulesets.Osu/Skinning/Default/SpinnerRotationTracker.cs index f82003edb8..9393a589eb 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerRotationTracker.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/SpinnerRotationTracker.cs @@ -9,10 +9,11 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Input.Events; using osu.Framework.Utils; using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Screens.Play; using osuTK; -namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces +namespace osu.Game.Rulesets.Osu.Skinning.Default { public class SpinnerRotationTracker : CircularContainer { diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerSpmCounter.cs b/osu.Game.Rulesets.Osu/Skinning/Default/SpinnerSpmCounter.cs similarity index 97% rename from osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerSpmCounter.cs rename to osu.Game.Rulesets.Osu/Skinning/Default/SpinnerSpmCounter.cs index 80ab03c45c..e5952ecf97 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerSpmCounter.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/SpinnerSpmCounter.cs @@ -10,7 +10,7 @@ using osu.Framework.Utils; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; -namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces +namespace osu.Game.Rulesets.Osu.Skinning.Default { public class SpinnerSpmCounter : Container { diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerTicks.cs b/osu.Game.Rulesets.Osu/Skinning/Default/SpinnerTicks.cs similarity index 97% rename from osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerTicks.cs rename to osu.Game.Rulesets.Osu/Skinning/Default/SpinnerTicks.cs index ba7e8eae6f..e518ae1da8 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerTicks.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/SpinnerTicks.cs @@ -7,12 +7,12 @@ using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Effects; -using osuTK; -using osuTK.Graphics; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; +using osuTK; +using osuTK.Graphics; -namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces +namespace osu.Game.Rulesets.Osu.Skinning.Default { public class SpinnerTicks : Container, IHasAccentColour { diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/TrianglesPiece.cs b/osu.Game.Rulesets.Osu/Skinning/Default/TrianglesPiece.cs similarity index 92% rename from osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/TrianglesPiece.cs rename to osu.Game.Rulesets.Osu/Skinning/Default/TrianglesPiece.cs index 53dc7ecea3..fa23c60d57 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/TrianglesPiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/TrianglesPiece.cs @@ -3,7 +3,7 @@ using osu.Game.Graphics.Backgrounds; -namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces +namespace osu.Game.Rulesets.Osu.Skinning.Default { public class TrianglesPiece : Triangles { diff --git a/osu.Game.Rulesets.Osu/Skinning/LegacyCursor.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursor.cs similarity index 96% rename from osu.Game.Rulesets.Osu/Skinning/LegacyCursor.cs rename to osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursor.cs index e96bd29ad5..314139d02a 100644 --- a/osu.Game.Rulesets.Osu/Skinning/LegacyCursor.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursor.cs @@ -3,11 +3,11 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; -using osu.Game.Skinning; using osu.Game.Rulesets.Osu.UI.Cursor; +using osu.Game.Skinning; using osuTK; -namespace osu.Game.Rulesets.Osu.Skinning +namespace osu.Game.Rulesets.Osu.Skinning.Legacy { public class LegacyCursor : OsuCursorSprite { diff --git a/osu.Game.Rulesets.Osu/Skinning/LegacyCursorTrail.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorTrail.cs similarity index 97% rename from osu.Game.Rulesets.Osu/Skinning/LegacyCursorTrail.cs rename to osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorTrail.cs index e6cd7bc59d..f18d3191ca 100644 --- a/osu.Game.Rulesets.Osu/Skinning/LegacyCursorTrail.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorTrail.cs @@ -10,7 +10,7 @@ using osu.Game.Configuration; using osu.Game.Rulesets.Osu.UI.Cursor; using osu.Game.Skinning; -namespace osu.Game.Rulesets.Osu.Skinning +namespace osu.Game.Rulesets.Osu.Skinning.Legacy { public class LegacyCursorTrail : CursorTrail { diff --git a/osu.Game.Rulesets.Osu/Skinning/LegacyMainCirclePiece.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs similarity index 99% rename from osu.Game.Rulesets.Osu/Skinning/LegacyMainCirclePiece.cs rename to osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs index 21af9a479e..545e80a709 100644 --- a/osu.Game.Rulesets.Osu/Skinning/LegacyMainCirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs @@ -17,7 +17,7 @@ using osuTK; using osuTK.Graphics; using static osu.Game.Skinning.LegacySkinConfiguration; -namespace osu.Game.Rulesets.Osu.Skinning +namespace osu.Game.Rulesets.Osu.Skinning.Legacy { public class LegacyMainCirclePiece : CompositeDrawable { diff --git a/osu.Game.Rulesets.Osu/Skinning/LegacyNewStyleSpinner.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyNewStyleSpinner.cs similarity index 99% rename from osu.Game.Rulesets.Osu/Skinning/LegacyNewStyleSpinner.cs rename to osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyNewStyleSpinner.cs index 05f4c8e307..efeca53969 100644 --- a/osu.Game.Rulesets.Osu/Skinning/LegacyNewStyleSpinner.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyNewStyleSpinner.cs @@ -13,7 +13,7 @@ using osu.Game.Skinning; using osuTK; using osuTK.Graphics; -namespace osu.Game.Rulesets.Osu.Skinning +namespace osu.Game.Rulesets.Osu.Skinning.Legacy { /// /// Legacy skinned spinner with two main spinning layers, one fixed overlay and one final spinning overlay. diff --git a/osu.Game.Rulesets.Osu/Skinning/LegacyOldStyleSpinner.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyOldStyleSpinner.cs similarity index 99% rename from osu.Game.Rulesets.Osu/Skinning/LegacyOldStyleSpinner.cs rename to osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyOldStyleSpinner.cs index fba802f085..4e07cb60b3 100644 --- a/osu.Game.Rulesets.Osu/Skinning/LegacyOldStyleSpinner.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyOldStyleSpinner.cs @@ -13,7 +13,7 @@ using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Skinning; using osuTK; -namespace osu.Game.Rulesets.Osu.Skinning +namespace osu.Game.Rulesets.Osu.Skinning.Legacy { /// /// Legacy skinned spinner with one main spinning layer and a background layer. diff --git a/osu.Game.Rulesets.Osu/Skinning/LegacySliderBall.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySliderBall.cs similarity index 97% rename from osu.Game.Rulesets.Osu/Skinning/LegacySliderBall.cs rename to osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySliderBall.cs index 836069013d..1a8c5ada1b 100644 --- a/osu.Game.Rulesets.Osu/Skinning/LegacySliderBall.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySliderBall.cs @@ -8,7 +8,7 @@ using osu.Framework.Graphics.Sprites; using osu.Game.Skinning; using osuTK.Graphics; -namespace osu.Game.Rulesets.Osu.Skinning +namespace osu.Game.Rulesets.Osu.Skinning.Legacy { public class LegacySliderBall : CompositeDrawable { diff --git a/osu.Game.Rulesets.Osu/Skinning/LegacySliderBody.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySliderBody.cs similarity index 96% rename from osu.Game.Rulesets.Osu/Skinning/LegacySliderBody.cs rename to osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySliderBody.cs index aad8b189d9..744ded37c9 100644 --- a/osu.Game.Rulesets.Osu/Skinning/LegacySliderBody.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySliderBody.cs @@ -5,10 +5,10 @@ using System; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Utils; using osu.Game.Rulesets.Osu.Objects; -using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; +using osu.Game.Rulesets.Osu.Skinning.Default; using osuTK.Graphics; -namespace osu.Game.Rulesets.Osu.Skinning +namespace osu.Game.Rulesets.Osu.Skinning.Legacy { public class LegacySliderBody : PlaySliderBody { diff --git a/osu.Game.Rulesets.Osu/Skinning/LegacySpinner.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySpinner.cs similarity index 98% rename from osu.Game.Rulesets.Osu/Skinning/LegacySpinner.cs rename to osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySpinner.cs index 5aa136cf7e..ec7ecb0d28 100644 --- a/osu.Game.Rulesets.Osu/Skinning/LegacySpinner.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySpinner.cs @@ -12,7 +12,7 @@ using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Skinning; using osuTK; -namespace osu.Game.Rulesets.Osu.Skinning +namespace osu.Game.Rulesets.Osu.Skinning.Legacy { public abstract class LegacySpinner : CompositeDrawable { diff --git a/osu.Game.Rulesets.Osu/Skinning/OsuLegacySkinTransformer.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs similarity index 99% rename from osu.Game.Rulesets.Osu/Skinning/OsuLegacySkinTransformer.cs rename to osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs index 78bc26eff7..d74f885573 100644 --- a/osu.Game.Rulesets.Osu/Skinning/OsuLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs @@ -7,7 +7,7 @@ using osu.Framework.Graphics; using osu.Game.Skinning; using osuTK; -namespace osu.Game.Rulesets.Osu.Skinning +namespace osu.Game.Rulesets.Osu.Skinning.Legacy { public class OsuLegacySkinTransformer : LegacySkinTransformer { diff --git a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneTaikoScroller.cs b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneTaikoScroller.cs index 114038b81c..4ae3cbd418 100644 --- a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneTaikoScroller.cs +++ b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneTaikoScroller.cs @@ -6,7 +6,7 @@ using osu.Framework.Testing; using osu.Framework.Timing; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Scoring; -using osu.Game.Rulesets.Taiko.Skinning; +using osu.Game.Rulesets.Taiko.Skinning.Legacy; using osu.Game.Skinning; namespace osu.Game.Rulesets.Taiko.Tests.Skinning diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs index c596fa2c7c..4ead4982a1 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs @@ -8,12 +8,12 @@ using osu.Framework.Utils; using osu.Game.Graphics; using osu.Game.Rulesets.Objects.Drawables; using osuTK.Graphics; -using osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Scoring; +using osu.Game.Rulesets.Taiko.Skinning.Default; using osu.Game.Skinning; using osuTK; diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRollTick.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRollTick.cs index be659f6ca5..e68e40ae1c 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRollTick.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRollTick.cs @@ -4,7 +4,7 @@ using System; using osu.Framework.Graphics; using osu.Game.Rulesets.Objects.Drawables; -using osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces; +using osu.Game.Rulesets.Taiko.Skinning.Default; using osu.Game.Skinning; namespace osu.Game.Rulesets.Taiko.Objects.Drawables diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs index 29a96a7a40..d1751d8a75 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs @@ -11,7 +11,7 @@ using osu.Framework.Graphics; using osu.Game.Audio; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Scoring; -using osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces; +using osu.Game.Rulesets.Taiko.Skinning.Default; using osu.Game.Skinning; namespace osu.Game.Rulesets.Taiko.Objects.Drawables diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs index ff0a27023d..5c6278ed08 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs @@ -13,7 +13,7 @@ using osuTK.Graphics; using osu.Framework.Graphics.Shapes; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Scoring; -using osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces; +using osu.Game.Rulesets.Taiko.Skinning.Default; using osu.Game.Skinning; namespace osu.Game.Rulesets.Taiko.Objects.Drawables diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwellTick.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwellTick.cs index 6202583494..14c86d151f 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwellTick.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwellTick.cs @@ -2,7 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Graphics; -using osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces; +using osu.Game.Rulesets.Taiko.Skinning.Default; using osu.Game.Skinning; namespace osu.Game.Rulesets.Taiko.Objects.Drawables diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/Pieces/CentreHitCirclePiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Default/CentreHitCirclePiece.cs similarity index 96% rename from osu.Game.Rulesets.Taiko/Objects/Drawables/Pieces/CentreHitCirclePiece.cs rename to osu.Game.Rulesets.Taiko/Skinning/Default/CentreHitCirclePiece.cs index 0509841ba8..f65bb54726 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/Pieces/CentreHitCirclePiece.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Default/CentreHitCirclePiece.cs @@ -4,11 +4,11 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osuTK; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; +using osuTK; -namespace osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces +namespace osu.Game.Rulesets.Taiko.Skinning.Default { public class CentreHitCirclePiece : CirclePiece { diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/Pieces/CirclePiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Default/CirclePiece.cs similarity index 98% rename from osu.Game.Rulesets.Taiko/Objects/Drawables/Pieces/CirclePiece.cs rename to osu.Game.Rulesets.Taiko/Skinning/Default/CirclePiece.cs index f515a35c18..8ca996159b 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/Pieces/CirclePiece.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Default/CirclePiece.cs @@ -5,15 +5,15 @@ using osu.Framework.Audio.Track; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Game.Graphics.Backgrounds; -using osuTK.Graphics; -using osu.Game.Beatmaps.ControlPoints; using osu.Framework.Graphics.Effects; +using osu.Framework.Graphics.Shapes; +using osu.Game.Beatmaps.ControlPoints; using osu.Game.Graphics; +using osu.Game.Graphics.Backgrounds; using osu.Game.Graphics.Containers; +using osuTK.Graphics; -namespace osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces +namespace osu.Game.Rulesets.Taiko.Skinning.Default { /// /// A circle piece which is used uniformly through osu!taiko to visualise hitobjects. diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/Pieces/ElongatedCirclePiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Default/ElongatedCirclePiece.cs similarity index 92% rename from osu.Game.Rulesets.Taiko/Objects/Drawables/Pieces/ElongatedCirclePiece.cs rename to osu.Game.Rulesets.Taiko/Skinning/Default/ElongatedCirclePiece.cs index 034ab6dd21..210841bca0 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/Pieces/ElongatedCirclePiece.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Default/ElongatedCirclePiece.cs @@ -5,7 +5,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Game.Graphics; -namespace osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces +namespace osu.Game.Rulesets.Taiko.Skinning.Default { public class ElongatedCirclePiece : CirclePiece { diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/Pieces/RimHitCirclePiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Default/RimHitCirclePiece.cs similarity index 96% rename from osu.Game.Rulesets.Taiko/Objects/Drawables/Pieces/RimHitCirclePiece.cs rename to osu.Game.Rulesets.Taiko/Skinning/Default/RimHitCirclePiece.cs index 3273ab7fa7..ca2ab301be 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/Pieces/RimHitCirclePiece.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Default/RimHitCirclePiece.cs @@ -9,7 +9,7 @@ using osu.Game.Graphics; using osuTK; using osuTK.Graphics; -namespace osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces +namespace osu.Game.Rulesets.Taiko.Skinning.Default { public class RimHitCirclePiece : CirclePiece { diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/Pieces/SwellSymbolPiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Default/SwellSymbolPiece.cs similarity index 95% rename from osu.Game.Rulesets.Taiko/Objects/Drawables/Pieces/SwellSymbolPiece.cs rename to osu.Game.Rulesets.Taiko/Skinning/Default/SwellSymbolPiece.cs index a8f9f0b94d..2f59cac3ff 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/Pieces/SwellSymbolPiece.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Default/SwellSymbolPiece.cs @@ -2,13 +2,13 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; -using osuTK; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Game.Graphics; +using osuTK; -namespace osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces +namespace osu.Game.Rulesets.Taiko.Skinning.Default { public class SwellCirclePiece : CirclePiece { diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/Pieces/TickPiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Default/TickPiece.cs similarity index 96% rename from osu.Game.Rulesets.Taiko/Objects/Drawables/Pieces/TickPiece.cs rename to osu.Game.Rulesets.Taiko/Skinning/Default/TickPiece.cs index 0648bcebcd..09c8243aac 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/Pieces/TickPiece.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Default/TickPiece.cs @@ -3,11 +3,11 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; using osuTK; using osuTK.Graphics; -using osu.Framework.Graphics.Shapes; -namespace osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces +namespace osu.Game.Rulesets.Taiko.Skinning.Default { public class TickPiece : CompositeDrawable { diff --git a/osu.Game.Rulesets.Taiko/Skinning/LegacyBarLine.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyBarLine.cs similarity index 93% rename from osu.Game.Rulesets.Taiko/Skinning/LegacyBarLine.cs rename to osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyBarLine.cs index 7d08a21ab1..2b528ae8ce 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/LegacyBarLine.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyBarLine.cs @@ -7,7 +7,7 @@ using osu.Framework.Graphics.Sprites; using osu.Game.Skinning; using osuTK; -namespace osu.Game.Rulesets.Taiko.Skinning +namespace osu.Game.Rulesets.Taiko.Skinning.Legacy { public class LegacyBarLine : Sprite { diff --git a/osu.Game.Rulesets.Taiko/Skinning/LegacyCirclePiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyCirclePiece.cs similarity index 98% rename from osu.Game.Rulesets.Taiko/Skinning/LegacyCirclePiece.cs rename to osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyCirclePiece.cs index 9b73ccd248..821ddc3c04 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/LegacyCirclePiece.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyCirclePiece.cs @@ -12,7 +12,7 @@ using osu.Game.Skinning; using osuTK; using osuTK.Graphics; -namespace osu.Game.Rulesets.Taiko.Skinning +namespace osu.Game.Rulesets.Taiko.Skinning.Legacy { public class LegacyCirclePiece : CompositeDrawable, IHasAccentColour { diff --git a/osu.Game.Rulesets.Taiko/Skinning/LegacyDrumRoll.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyDrumRoll.cs similarity index 97% rename from osu.Game.Rulesets.Taiko/Skinning/LegacyDrumRoll.cs rename to osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyDrumRoll.cs index 5ab8e3a8c8..ea6f813be8 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/LegacyDrumRoll.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyDrumRoll.cs @@ -10,7 +10,7 @@ using osu.Game.Graphics; using osu.Game.Skinning; using osuTK.Graphics; -namespace osu.Game.Rulesets.Taiko.Skinning +namespace osu.Game.Rulesets.Taiko.Skinning.Legacy { public class LegacyDrumRoll : CompositeDrawable, IHasAccentColour { diff --git a/osu.Game.Rulesets.Taiko/Skinning/LegacyHit.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyHit.cs similarity index 94% rename from osu.Game.Rulesets.Taiko/Skinning/LegacyHit.cs rename to osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyHit.cs index b11b64c22c..d93317f0e2 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/LegacyHit.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyHit.cs @@ -5,7 +5,7 @@ using osu.Framework.Allocation; using osu.Game.Skinning; using osuTK.Graphics; -namespace osu.Game.Rulesets.Taiko.Skinning +namespace osu.Game.Rulesets.Taiko.Skinning.Legacy { public class LegacyHit : LegacyCirclePiece { diff --git a/osu.Game.Rulesets.Taiko/Skinning/LegacyHitExplosion.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyHitExplosion.cs similarity index 98% rename from osu.Game.Rulesets.Taiko/Skinning/LegacyHitExplosion.cs rename to osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyHitExplosion.cs index 19493271be..651cdd6438 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/LegacyHitExplosion.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyHitExplosion.cs @@ -8,7 +8,7 @@ using osu.Framework.Graphics.Containers; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Taiko.Objects.Drawables; -namespace osu.Game.Rulesets.Taiko.Skinning +namespace osu.Game.Rulesets.Taiko.Skinning.Legacy { public class LegacyHitExplosion : CompositeDrawable { diff --git a/osu.Game.Rulesets.Taiko/Skinning/LegacyInputDrum.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyInputDrum.cs similarity index 99% rename from osu.Game.Rulesets.Taiko/Skinning/LegacyInputDrum.cs rename to osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyInputDrum.cs index b7b55b9ae0..795885d4b9 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/LegacyInputDrum.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyInputDrum.cs @@ -11,7 +11,7 @@ using osu.Game.Rulesets.Taiko.Audio; using osu.Game.Skinning; using osuTK; -namespace osu.Game.Rulesets.Taiko.Skinning +namespace osu.Game.Rulesets.Taiko.Skinning.Legacy { /// /// A component of the playfield that captures input and displays input as a drum. diff --git a/osu.Game.Rulesets.Taiko/Skinning/LegacyTaikoScroller.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyTaikoScroller.cs similarity index 98% rename from osu.Game.Rulesets.Taiko/Skinning/LegacyTaikoScroller.cs rename to osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyTaikoScroller.cs index e029040ef3..eb92097204 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/LegacyTaikoScroller.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyTaikoScroller.cs @@ -13,7 +13,7 @@ using osu.Game.Screens.Play; using osu.Game.Skinning; using osuTK; -namespace osu.Game.Rulesets.Taiko.Skinning +namespace osu.Game.Rulesets.Taiko.Skinning.Legacy { public class LegacyTaikoScroller : CompositeDrawable { diff --git a/osu.Game.Rulesets.Taiko/Skinning/TaikoLegacyHitTarget.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacyHitTarget.cs similarity index 97% rename from osu.Game.Rulesets.Taiko/Skinning/TaikoLegacyHitTarget.cs rename to osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacyHitTarget.cs index e522fb7c10..9feb2054da 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/TaikoLegacyHitTarget.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacyHitTarget.cs @@ -9,7 +9,7 @@ using osu.Game.Rulesets.Taiko.UI; using osu.Game.Skinning; using osuTK; -namespace osu.Game.Rulesets.Taiko.Skinning +namespace osu.Game.Rulesets.Taiko.Skinning.Legacy { public class TaikoLegacyHitTarget : CompositeDrawable { diff --git a/osu.Game.Rulesets.Taiko/Skinning/TaikoLegacyPlayfieldBackgroundRight.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacyPlayfieldBackgroundRight.cs similarity index 97% rename from osu.Game.Rulesets.Taiko/Skinning/TaikoLegacyPlayfieldBackgroundRight.cs rename to osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacyPlayfieldBackgroundRight.cs index 4bbb6be6b1..02756d57a4 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/TaikoLegacyPlayfieldBackgroundRight.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacyPlayfieldBackgroundRight.cs @@ -10,7 +10,7 @@ using osu.Game.Graphics.Containers; using osu.Game.Skinning; using osuTK; -namespace osu.Game.Rulesets.Taiko.Skinning +namespace osu.Game.Rulesets.Taiko.Skinning.Legacy { public class TaikoLegacyPlayfieldBackgroundRight : BeatSyncedContainer { diff --git a/osu.Game.Rulesets.Taiko/Skinning/TaikoLegacySkinTransformer.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacySkinTransformer.cs similarity index 99% rename from osu.Game.Rulesets.Taiko/Skinning/TaikoLegacySkinTransformer.cs rename to osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacySkinTransformer.cs index 96fb065e79..d8e3100048 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/TaikoLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacySkinTransformer.cs @@ -11,7 +11,7 @@ using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Taiko.UI; using osu.Game.Skinning; -namespace osu.Game.Rulesets.Taiko.Skinning +namespace osu.Game.Rulesets.Taiko.Skinning.Legacy { public class TaikoLegacySkinTransformer : LegacySkinTransformer { diff --git a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs index 2a49dd655c..f2b5d195b4 100644 --- a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs +++ b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs @@ -25,7 +25,7 @@ using System.Linq; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Taiko.Edit; using osu.Game.Rulesets.Taiko.Objects; -using osu.Game.Rulesets.Taiko.Skinning; +using osu.Game.Rulesets.Taiko.Skinning.Legacy; using osu.Game.Screens.Ranking.Statistics; using osu.Game.Skinning; diff --git a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs index b941313103..c32e359de6 100644 --- a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs +++ b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs @@ -14,6 +14,7 @@ using osu.Framework.Allocation; using osu.Framework.Extensions; using osu.Framework.Logging; using osu.Game.Beatmaps; +using osu.Game.Database; using osu.Game.IO; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu.Objects; @@ -68,6 +69,42 @@ namespace osu.Game.Tests.Beatmaps.IO } } + [Test] + public async Task TestImportThenDeleteFromStream() + { + // unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here. + using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(ImportBeatmapTest))) + { + try + { + var osu = LoadOsuIntoHost(host); + + var tempPath = TestResources.GetTestBeatmapForImport(); + + var manager = osu.Dependencies.Get(); + + BeatmapSetInfo importedSet; + + using (var stream = File.OpenRead(tempPath)) + { + importedSet = await manager.Import(new ImportTask(stream, Path.GetFileName(tempPath))); + ensureLoaded(osu); + } + + Assert.IsTrue(File.Exists(tempPath), "Stream source file somehow went missing"); + File.Delete(tempPath); + + var imported = manager.GetAllUsableBeatmapSets().Find(beatmapSet => beatmapSet.ID == importedSet.ID); + + deleteBeatmapSet(imported, osu); + } + finally + { + host.Exit(); + } + } + } + [Test] public async Task TestImportThenImport() { @@ -127,7 +164,7 @@ namespace osu.Game.Tests.Beatmaps.IO // zip files differ because different compression or encoder. Assert.AreNotEqual(hashBefore, hashFile(temp)); - var importedSecondTime = await osu.Dependencies.Get().Import(temp); + var importedSecondTime = await osu.Dependencies.Get().Import(new ImportTask(temp)); ensureLoaded(osu); @@ -184,7 +221,7 @@ namespace osu.Game.Tests.Beatmaps.IO zip.SaveTo(temp, new ZipWriterOptions(CompressionType.Deflate)); } - var importedSecondTime = await osu.Dependencies.Get().Import(temp); + var importedSecondTime = await osu.Dependencies.Get().Import(new ImportTask(temp)); ensureLoaded(osu); @@ -235,7 +272,7 @@ namespace osu.Game.Tests.Beatmaps.IO zip.SaveTo(temp, new ZipWriterOptions(CompressionType.Deflate)); } - var importedSecondTime = await osu.Dependencies.Get().Import(temp); + var importedSecondTime = await osu.Dependencies.Get().Import(new ImportTask(temp)); ensureLoaded(osu); @@ -351,7 +388,7 @@ namespace osu.Game.Tests.Beatmaps.IO // this will trigger purging of the existing beatmap (online set id match) but should rollback due to broken osu. try { - await manager.Import(breakTemp); + await manager.Import(new ImportTask(breakTemp)); } catch { @@ -614,7 +651,7 @@ namespace osu.Game.Tests.Beatmaps.IO zip.SaveTo(temp, new ZipWriterOptions(CompressionType.Deflate)); } - var imported = await osu.Dependencies.Get().Import(temp); + var imported = await osu.Dependencies.Get().Import(new ImportTask(temp)); ensureLoaded(osu); @@ -667,7 +704,7 @@ namespace osu.Game.Tests.Beatmaps.IO zip.SaveTo(temp, new ZipWriterOptions(CompressionType.Deflate)); } - var imported = await osu.Dependencies.Get().Import(temp); + var imported = await osu.Dependencies.Get().Import(new ImportTask(temp)); ensureLoaded(osu); @@ -821,7 +858,7 @@ namespace osu.Game.Tests.Beatmaps.IO var manager = osu.Dependencies.Get(); - var importedSet = await manager.Import(temp); + var importedSet = await manager.Import(new ImportTask(temp)); ensureLoaded(osu); diff --git a/osu.Game.Tests/Input/ConfineMouseTrackerTest.cs b/osu.Game.Tests/Input/ConfineMouseTrackerTest.cs new file mode 100644 index 0000000000..b90382488f --- /dev/null +++ b/osu.Game.Tests/Input/ConfineMouseTrackerTest.cs @@ -0,0 +1,102 @@ +// 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.Framework.Allocation; +using osu.Framework.Configuration; +using osu.Framework.Input; +using osu.Framework.Testing; +using osu.Game.Configuration; +using osu.Game.Input; +using osu.Game.Tests.Visual.Navigation; + +namespace osu.Game.Tests.Input +{ + [HeadlessTest] + public class ConfineMouseTrackerTest : OsuGameTestScene + { + [Resolved] + private FrameworkConfigManager frameworkConfigManager { get; set; } + + [Resolved] + private OsuConfigManager osuConfigManager { get; set; } + + [TestCase(WindowMode.Windowed)] + [TestCase(WindowMode.Borderless)] + public void TestDisableConfining(WindowMode windowMode) + { + setWindowModeTo(windowMode); + setGameSideModeTo(OsuConfineMouseMode.Never); + + setLocalUserPlayingTo(false); + frameworkSideModeIs(ConfineMouseMode.Never); + + setLocalUserPlayingTo(true); + frameworkSideModeIs(ConfineMouseMode.Never); + } + + [TestCase(WindowMode.Windowed)] + [TestCase(WindowMode.Borderless)] + public void TestConfiningDuringGameplay(WindowMode windowMode) + { + setWindowModeTo(windowMode); + setGameSideModeTo(OsuConfineMouseMode.DuringGameplay); + + setLocalUserPlayingTo(false); + frameworkSideModeIs(ConfineMouseMode.Never); + + setLocalUserPlayingTo(true); + frameworkSideModeIs(ConfineMouseMode.Always); + } + + [TestCase(WindowMode.Windowed)] + [TestCase(WindowMode.Borderless)] + public void TestConfineAlwaysUserSetting(WindowMode windowMode) + { + setWindowModeTo(windowMode); + setGameSideModeTo(OsuConfineMouseMode.Always); + + setLocalUserPlayingTo(false); + frameworkSideModeIs(ConfineMouseMode.Always); + + setLocalUserPlayingTo(true); + frameworkSideModeIs(ConfineMouseMode.Always); + } + + [Test] + public void TestConfineAlwaysInFullscreen() + { + setGameSideModeTo(OsuConfineMouseMode.Never); + + setWindowModeTo(WindowMode.Fullscreen); + + setLocalUserPlayingTo(false); + frameworkSideModeIs(ConfineMouseMode.Fullscreen); + + setLocalUserPlayingTo(true); + frameworkSideModeIs(ConfineMouseMode.Fullscreen); + + setWindowModeTo(WindowMode.Windowed); + + // old state is restored + gameSideModeIs(OsuConfineMouseMode.Never); + frameworkSideModeIs(ConfineMouseMode.Never); + } + + private void setWindowModeTo(WindowMode mode) + // needs to go through .GetBindable().Value instead of .Set() due to default overrides + => AddStep($"make window {mode}", () => frameworkConfigManager.GetBindable(FrameworkSetting.WindowMode).Value = mode); + + private void setGameSideModeTo(OsuConfineMouseMode mode) + => AddStep($"set {mode} game-side", () => Game.LocalConfig.Set(OsuSetting.ConfineMouseMode, mode)); + + private void setLocalUserPlayingTo(bool playing) + => AddStep($"local user {(playing ? "playing" : "not playing")}", () => Game.LocalUserPlaying.Value = playing); + + private void gameSideModeIs(OsuConfineMouseMode mode) + => AddAssert($"mode is {mode} game-side", () => Game.LocalConfig.Get(OsuSetting.ConfineMouseMode) == mode); + + private void frameworkSideModeIs(ConfineMouseMode mode) + => AddAssert($"mode is {mode} framework-side", () => frameworkConfigManager.Get(FrameworkSetting.ConfineMouseMode) == mode); + } +} diff --git a/osu.Game.Tests/Visual/Menus/TestSceneMusicActionHandling.cs b/osu.Game.Tests/Visual/Menus/TestSceneMusicActionHandling.cs index b34e027e9c..aaf3323432 100644 --- a/osu.Game.Tests/Visual/Menus/TestSceneMusicActionHandling.cs +++ b/osu.Game.Tests/Visual/Menus/TestSceneMusicActionHandling.cs @@ -6,6 +6,7 @@ using System.Linq; using NUnit.Framework; using osu.Framework.Testing; using osu.Game.Beatmaps; +using osu.Game.Database; using osu.Game.Input.Bindings; using osu.Game.Overlays; using osu.Game.Tests.Resources; @@ -52,7 +53,7 @@ namespace osu.Game.Tests.Visual.Menus AddStep("import beatmap with track", () => { - var setWithTrack = Game.BeatmapManager.Import(TestResources.GetTestBeatmapForImport()).Result; + var setWithTrack = Game.BeatmapManager.Import(new ImportTask(TestResources.GetTestBeatmapForImport())).Result; Beatmap.Value = Game.BeatmapManager.GetWorkingBeatmap(setWithTrack.Beatmaps.First()); }); diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeFilterControl.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneTimeshiftFilterControl.cs similarity index 55% rename from osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeFilterControl.cs rename to osu.Game.Tests/Visual/Multiplayer/TestSceneTimeshiftFilterControl.cs index 7c0c2797f5..f635a28b5c 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeFilterControl.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneTimeshiftFilterControl.cs @@ -6,14 +6,17 @@ using osu.Game.Screens.Multi.Lounge.Components; namespace osu.Game.Tests.Visual.Multiplayer { - public class TestSceneLoungeFilterControl : OsuTestScene + public class TestSceneTimeshiftFilterControl : OsuTestScene { - public TestSceneLoungeFilterControl() + public TestSceneTimeshiftFilterControl() { - Child = new FilterControl + Child = new TimeshiftFilterControl { Anchor = Anchor.Centre, - Origin = Anchor.Centre + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.X, + Width = 0.7f, + Height = 80, }; } } diff --git a/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs index fca642ad6c..9d0be85a3a 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs @@ -208,6 +208,46 @@ namespace osu.Game.Tests.Visual.Online AddAssert("All channels closed", () => !channelManager.JoinedChannels.Any()); } + [Test] + public void TestCtrlWShortcut() + { + AddStep("Join 2 channels", () => + { + channelManager.JoinChannel(channel1); + channelManager.JoinChannel(channel2); + }); + + // Want to close channel 2 + AddStep("Select channel 2", () => clickDrawable(chatOverlay.TabMap[channel2])); + + pressControlW(); + // Channel 2 should be closed + AddAssert("channel 1 open", () => channelManager.JoinedChannels.Contains(channel1)); + AddAssert("channel 2 closed", () => !channelManager.JoinedChannels.Contains(channel2)); + + // Want to close channel 1 + AddStep("Select channel 1", () => clickDrawable(chatOverlay.TabMap[channel1])); + + pressControlW(); + // Channel 1 and channel 2 should be closed + AddAssert("All channels closed", () => !channelManager.JoinedChannels.Any()); + } + + [Test] + public void TestCtrlTShortcut() + { + AddStep("Join 2 channels", () => + { + channelManager.JoinChannel(channel1); + channelManager.JoinChannel(channel2); + }); + + // Want to join another channel + pressControlT(); + // Selector should be visible + AddAssert("Selector is visible", () => chatOverlay.SelectionOverlayState == Visibility.Visible); + } + private void pressChannelHotkey(int number) { var channelKey = Key.Number0 + number; @@ -216,6 +256,20 @@ namespace osu.Game.Tests.Visual.Online InputManager.ReleaseKey(Key.AltLeft); } + private void pressControlW() + { + AddStep("Press and hold Control", () => InputManager.PressKey(Key.ControlLeft)); + AddStep("Press W", () => InputManager.Key(Key.W)); + AddStep("Release Control", () => InputManager.ReleaseKey(Key.ControlLeft)); + } + + private void pressControlT() + { + AddStep("Press and hold Control", () => InputManager.PressKey(Key.ControlLeft)); + AddStep("Press T", () => InputManager.Key(Key.T)); + AddStep("Release Control", () => InputManager.ReleaseKey(Key.ControlLeft)); + } + private void clickDrawable(Drawable d) { InputManager.MoveMouseTo(d); diff --git a/osu.Game.Tests/Visual/Online/TestSceneDirectDownloadButton.cs b/osu.Game.Tests/Visual/Online/TestSceneDirectDownloadButton.cs index 684ce10820..63bda08c88 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneDirectDownloadButton.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneDirectDownloadButton.cs @@ -42,7 +42,7 @@ namespace osu.Game.Tests.Visual.Online ensureSoleilyRemoved(); createButtonWithBeatmap(createSoleily()); AddAssert("button state not downloaded", () => downloadButton.DownloadState == DownloadState.NotDownloaded); - AddStep("import soleily", () => beatmaps.Import(new[] { TestResources.GetTestBeatmapForImport() })); + AddStep("import soleily", () => beatmaps.Import(TestResources.GetTestBeatmapForImport())); AddUntilStep("wait for beatmap import", () => beatmaps.GetAllUsableBeatmapSets().Any(b => b.OnlineBeatmapSetID == 241526)); createButtonWithBeatmap(createSoleily()); AddAssert("button state downloaded", () => downloadButton.DownloadState == DownloadState.LocallyAvailable); diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs index e54292f7cc..81862448a8 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs @@ -12,6 +12,7 @@ using osu.Framework.Platform; using osu.Framework.Testing; using osu.Framework.Utils; using osu.Game.Beatmaps; +using osu.Game.Database; using osu.Game.Graphics.Cursor; using osu.Game.Graphics.UserInterface; using osu.Game.Online.Leaderboards; @@ -83,7 +84,7 @@ namespace osu.Game.Tests.Visual.UserInterface dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, ContextFactory, rulesetStore, null, dependencies.Get(), dependencies.Get(), Beatmap.Default)); dependencies.Cache(scoreManager = new ScoreManager(rulesetStore, () => beatmapManager, LocalStorage, null, ContextFactory)); - beatmap = beatmapManager.Import(TestResources.GetTestBeatmapForImport()).Result.Beatmaps[0]; + beatmap = beatmapManager.Import(new ImportTask(TestResources.GetTestBeatmapForImport())).Result.Beatmaps[0]; for (int i = 0; i < 50; i++) { diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModSettings.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModSettings.cs index 645b83758c..8614700b15 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModSettings.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModSettings.cs @@ -50,7 +50,7 @@ namespace osu.Game.Tests.Visual.UserInterface AddAssert("button enabled", () => modSelect.CustomiseButton.Enabled.Value); AddStep("open Customisation", () => modSelect.CustomiseButton.Click()); AddStep("deselect mod", () => modSelect.SelectMod(testCustomisableMod)); - AddAssert("controls hidden", () => modSelect.ModSettingsContainer.Alpha == 0); + AddAssert("controls hidden", () => modSelect.ModSettingsContainer.State.Value == Visibility.Hidden); } [Test] @@ -72,11 +72,11 @@ namespace osu.Game.Tests.Visual.UserInterface createModSelect(); openModSelect(); - AddAssert("Customisation closed", () => modSelect.ModSettingsContainer.Alpha == 0); + AddAssert("Customisation closed", () => modSelect.ModSettingsContainer.State.Value == Visibility.Hidden); AddStep("select mod", () => modSelect.SelectMod(testCustomisableAutoOpenMod)); - AddAssert("Customisation opened", () => modSelect.ModSettingsContainer.Alpha == 1); + AddAssert("Customisation opened", () => modSelect.ModSettingsContainer.State.Value == Visibility.Visible); AddStep("deselect mod", () => modSelect.SelectMod(testCustomisableAutoOpenMod)); - AddAssert("Customisation closed", () => modSelect.ModSettingsContainer.Alpha == 0); + AddAssert("Customisation closed", () => modSelect.ModSettingsContainer.State.Value == Visibility.Hidden); } [Test] @@ -123,7 +123,7 @@ namespace osu.Game.Tests.Visual.UserInterface AddStep("change mod settings menu width to full screen", () => modSelect.SetModSettingsWidth(1.0f)); AddStep("select cm2", () => modSelect.SelectMod(testCustomisableAutoOpenMod)); - AddAssert("Customisation opened", () => modSelect.ModSettingsContainer.Alpha == 1); + AddAssert("Customisation opened", () => modSelect.ModSettingsContainer.State.Value == Visibility.Visible); AddStep("hover over mod behind settings menu", () => InputManager.MoveMouseTo(modSelect.GetModButton(testCustomisableMod))); AddAssert("Mod is not considered hovered over", () => !modSelect.GetModButton(testCustomisableMod).IsHovered); AddStep("left click mod", () => InputManager.Click(MouseButton.Left)); @@ -153,7 +153,7 @@ namespace osu.Game.Tests.Visual.UserInterface private class TestModSelectOverlay : ModSelectOverlay { - public new Container ModSettingsContainer => base.ModSettingsContainer; + public new VisibilityContainer ModSettingsContainer => base.ModSettingsContainer; public new TriangleButton CustomiseButton => base.CustomiseButton; public bool ButtonsLoaded => ModSectionsContainer.Children.All(c => c.ModIconsLoaded); diff --git a/osu.Game/Beatmaps/BeatmapManager_BeatmapOnlineLookupQueue.cs b/osu.Game/Beatmaps/BeatmapManager_BeatmapOnlineLookupQueue.cs index c4563d5844..e90ccbb805 100644 --- a/osu.Game/Beatmaps/BeatmapManager_BeatmapOnlineLookupQueue.cs +++ b/osu.Game/Beatmaps/BeatmapManager_BeatmapOnlineLookupQueue.cs @@ -104,7 +104,7 @@ namespace osu.Game.Beatmaps string cacheFilePath = storage.GetFullPath(cache_database_name); string compressedCacheFilePath = $"{cacheFilePath}.bz2"; - cacheDownloadRequest = new FileWebRequest(compressedCacheFilePath, $"https://assets.ppy.sh/client-resources/{cache_database_name}.bz2"); + cacheDownloadRequest = new FileWebRequest(compressedCacheFilePath, $"https://assets.ppy.sh/client-resources/{cache_database_name}.bz2?{DateTimeOffset.UtcNow:yyyyMMdd}"); cacheDownloadRequest.Failed += ex => { diff --git a/osu.Game/Database/ArchiveModelManager.cs b/osu.Game/Database/ArchiveModelManager.cs index 8bdc804311..36cc4cce39 100644 --- a/osu.Game/Database/ArchiveModelManager.cs +++ b/osu.Game/Database/ArchiveModelManager.cs @@ -21,9 +21,7 @@ using osu.Game.IO; using osu.Game.IO.Archives; using osu.Game.IPC; using osu.Game.Overlays.Notifications; -using osu.Game.Utils; using SharpCompress.Archives.Zip; -using SharpCompress.Common; using FileInfo = osu.Game.IO.FileInfo; namespace osu.Game.Database @@ -114,10 +112,19 @@ namespace osu.Game.Database PostNotification?.Invoke(notification); - return Import(notification, paths); + return Import(notification, paths.Select(p => new ImportTask(p)).ToArray()); } - protected async Task> Import(ProgressNotification notification, params string[] paths) + public Task Import(Stream stream, string filename) + { + var notification = new ProgressNotification { State = ProgressNotificationState.Active }; + + PostNotification?.Invoke(notification); + + return Import(notification, new ImportTask(stream, filename)); + } + + protected async Task> Import(ProgressNotification notification, params ImportTask[] tasks) { notification.Progress = 0; notification.Text = $"{HumanisedModelName.Humanize(LetterCasing.Title)} import is initialising..."; @@ -126,13 +133,13 @@ namespace osu.Game.Database var imported = new List(); - await Task.WhenAll(paths.Select(async path => + await Task.WhenAll(tasks.Select(async task => { notification.CancellationToken.ThrowIfCancellationRequested(); try { - var model = await Import(path, notification.CancellationToken); + var model = await Import(task, notification.CancellationToken); lock (imported) { @@ -140,8 +147,8 @@ namespace osu.Game.Database imported.Add(model); current++; - notification.Text = $"Imported {current} of {paths.Length} {HumanisedModelName}s"; - notification.Progress = (float)current / paths.Length; + notification.Text = $"Imported {current} of {tasks.Length} {HumanisedModelName}s"; + notification.Progress = (float)current / tasks.Length; } } catch (TaskCanceledException) @@ -150,7 +157,7 @@ namespace osu.Game.Database } catch (Exception e) { - Logger.Error(e, $@"Could not import ({Path.GetFileName(path)})", LoggingTarget.Database); + Logger.Error(e, $@"Could not import ({task})", LoggingTarget.Database); } })); @@ -183,16 +190,17 @@ namespace osu.Game.Database /// /// Import one from the filesystem and delete the file on success. + /// Note that this bypasses the UI flow and should only be used for special cases or testing. /// - /// The archive location on disk. + /// The containing data about the to import. /// An optional cancellation token. /// The imported model, if successful. - public async Task Import(string path, CancellationToken cancellationToken = default) + internal async Task Import(ImportTask task, CancellationToken cancellationToken = default) { cancellationToken.ThrowIfCancellationRequested(); TModel import; - using (ArchiveReader reader = getReaderFrom(path)) + using (ArchiveReader reader = task.GetReader()) import = await Import(reader, cancellationToken); // We may or may not want to delete the file depending on where it is stored. @@ -201,12 +209,12 @@ namespace osu.Game.Database // TODO: Add a check to prevent files from storage to be deleted. try { - if (import != null && File.Exists(path) && ShouldDeleteArchive(path)) - File.Delete(path); + if (import != null && File.Exists(task.Path) && ShouldDeleteArchive(task.Path)) + File.Delete(task.Path); } catch (Exception e) { - LogForModel(import, $@"Could not delete original file after import ({Path.GetFileName(path)})", e); + LogForModel(import, $@"Could not delete original file after import ({task})", e); } return import; @@ -727,23 +735,6 @@ namespace osu.Game.Database protected virtual string HumanisedModelName => $"{typeof(TModel).Name.Replace("Info", "").ToLower()}"; - /// - /// Creates an from a valid storage path. - /// - /// A file or folder path resolving the archive content. - /// A reader giving access to the archive's content. - private ArchiveReader getReaderFrom(string path) - { - if (ZipUtils.IsZipArchive(path)) - return new ZipArchiveReader(File.Open(path, FileMode.Open, FileAccess.Read, FileShare.Read), Path.GetFileName(path)); - if (Directory.Exists(path)) - return new LegacyDirectoryArchiveReader(path); - if (File.Exists(path)) - return new LegacyFileArchiveReader(path); - - throw new InvalidFormatException($"{path} is not a valid archive"); - } - #region Event handling / delaying private readonly List queuedEvents = new List(); diff --git a/osu.Game/Database/DownloadableArchiveModelManager.cs b/osu.Game/Database/DownloadableArchiveModelManager.cs index 8f469ca590..50b022f9ff 100644 --- a/osu.Game/Database/DownloadableArchiveModelManager.cs +++ b/osu.Game/Database/DownloadableArchiveModelManager.cs @@ -82,7 +82,7 @@ namespace osu.Game.Database Task.Factory.StartNew(async () => { // This gets scheduled back to the update thread, but we want the import to run in the background. - var imported = await Import(notification, filename); + var imported = await Import(notification, new ImportTask(filename)); // for now a failed import will be marked as a failed download for simplicity. if (!imported.Any()) diff --git a/osu.Game/Database/ICanAcceptFiles.cs b/osu.Game/Database/ICanAcceptFiles.cs index e4d92d957c..276c284c9f 100644 --- a/osu.Game/Database/ICanAcceptFiles.cs +++ b/osu.Game/Database/ICanAcceptFiles.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Generic; +using System.IO; using System.Threading.Tasks; namespace osu.Game.Database @@ -17,6 +18,13 @@ namespace osu.Game.Database /// The files which should be imported. Task Import(params string[] paths); + /// + /// Import the provided stream as a simple item. + /// + /// The stream to import files from. Should be in a supported archive format. + /// The filename of the archive being imported. + Task Import(Stream stream, string filename); + /// /// An array of accepted file extensions (in the standard format of ".abc"). /// diff --git a/osu.Game/Database/ImportTask.cs b/osu.Game/Database/ImportTask.cs new file mode 100644 index 0000000000..1433a567a9 --- /dev/null +++ b/osu.Game/Database/ImportTask.cs @@ -0,0 +1,75 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +#nullable enable + +using System.IO; +using osu.Game.IO.Archives; +using osu.Game.Utils; +using SharpCompress.Common; + +namespace osu.Game.Database +{ + /// + /// An encapsulated import task to be imported to an . + /// + public class ImportTask + { + /// + /// The path to the file (or filename in the case a stream is provided). + /// + public string Path { get; } + + /// + /// An optional stream which provides the file content. + /// + public Stream? Stream { get; } + + /// + /// Construct a new import task from a path (on a local filesystem). + /// + public ImportTask(string path) + { + Path = path; + } + + /// + /// Construct a new import task from a stream. + /// + public ImportTask(Stream stream, string filename) + { + Path = filename; + Stream = stream; + } + + /// + /// Retrieve an archive reader from this task. + /// + public ArchiveReader GetReader() + { + if (Stream != null) + return new ZipArchiveReader(Stream, Path); + + return getReaderFrom(Path); + } + + /// + /// Creates an from a valid storage path. + /// + /// A file or folder path resolving the archive content. + /// A reader giving access to the archive's content. + private ArchiveReader getReaderFrom(string path) + { + if (ZipUtils.IsZipArchive(path)) + return new ZipArchiveReader(File.Open(path, FileMode.Open, FileAccess.Read, FileShare.Read), System.IO.Path.GetFileName(path)); + if (Directory.Exists(path)) + return new LegacyDirectoryArchiveReader(path); + if (File.Exists(path)) + return new LegacyFileArchiveReader(path); + + throw new InvalidFormatException($"{path} is not a valid archive"); + } + + public override string ToString() => System.IO.Path.GetFileName(Path); + } +} diff --git a/osu.Game/Overlays/SearchableList/SlimEnumDropdown.cs b/osu.Game/Graphics/UserInterface/SlimEnumDropdown.cs similarity index 94% rename from osu.Game/Overlays/SearchableList/SlimEnumDropdown.cs rename to osu.Game/Graphics/UserInterface/SlimEnumDropdown.cs index 9e7ff1205f..965734792c 100644 --- a/osu.Game/Overlays/SearchableList/SlimEnumDropdown.cs +++ b/osu.Game/Graphics/UserInterface/SlimEnumDropdown.cs @@ -2,14 +2,13 @@ // See the LICENCE file in the repository root for full licence text. using System; -using osuTK.Graphics; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.UserInterface; -using osu.Game.Graphics.UserInterface; using osuTK; +using osuTK.Graphics; -namespace osu.Game.Overlays.SearchableList +namespace osu.Game.Graphics.UserInterface { public class SlimEnumDropdown : OsuEnumDropdown where T : struct, Enum diff --git a/osu.Game/Online/Multiplayer/GetRoomsRequest.cs b/osu.Game/Online/Multiplayer/GetRoomsRequest.cs index 64e0386f77..a0609f77dd 100644 --- a/osu.Game/Online/Multiplayer/GetRoomsRequest.cs +++ b/osu.Game/Online/Multiplayer/GetRoomsRequest.cs @@ -11,24 +11,24 @@ namespace osu.Game.Online.Multiplayer { public class GetRoomsRequest : APIRequest> { - private readonly RoomStatusFilter statusFilter; - private readonly RoomCategoryFilter categoryFilter; + private readonly RoomStatusFilter status; + private readonly string category; - public GetRoomsRequest(RoomStatusFilter statusFilter, RoomCategoryFilter categoryFilter) + public GetRoomsRequest(RoomStatusFilter status, string category) { - this.statusFilter = statusFilter; - this.categoryFilter = categoryFilter; + this.status = status; + this.category = category; } protected override WebRequest CreateWebRequest() { var req = base.CreateWebRequest(); - if (statusFilter != RoomStatusFilter.Open) - req.AddParameter("mode", statusFilter.ToString().Underscore().ToLowerInvariant()); + if (status != RoomStatusFilter.Open) + req.AddParameter("mode", status.ToString().Underscore().ToLowerInvariant()); - if (categoryFilter != RoomCategoryFilter.Any) - req.AddParameter("category", categoryFilter.ToString().Underscore().ToLowerInvariant()); + if (!string.IsNullOrEmpty(category)) + req.AddParameter("category", category); return req; } diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index e7b5d3304d..0fc2b8d1d7 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -395,6 +395,17 @@ namespace osu.Game } } + public async Task Import(Stream stream, string filename) + { + var extension = Path.GetExtension(filename)?.ToLowerInvariant(); + + foreach (var importer in fileImporters) + { + if (importer.HandledExtensions.Contains(extension)) + await importer.Import(stream, Path.GetFileNameWithoutExtension(filename)); + } + } + public IEnumerable HandledExtensions => fileImporters.SelectMany(i => i.HandledExtensions); protected override void Dispose(bool isDisposing) diff --git a/osu.Game/Overlays/Mods/ModSelectOverlay.cs b/osu.Game/Overlays/Mods/ModSelectOverlay.cs index 31adf47456..34f5c70adb 100644 --- a/osu.Game/Overlays/Mods/ModSelectOverlay.cs +++ b/osu.Game/Overlays/Mods/ModSelectOverlay.cs @@ -158,37 +158,57 @@ namespace osu.Game.Overlays.Mods }, new Drawable[] { - // Body - new OsuScrollContainer + new Container { - ScrollbarVisible = false, - Origin = Anchor.TopCentre, - Anchor = Anchor.TopCentre, RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding + Children = new Drawable[] { - Vertical = 10, - Horizontal = OsuScreen.HORIZONTAL_OVERFLOW_PADDING - }, - Child = ModSectionsContainer = new FillFlowContainer - { - Origin = Anchor.TopCentre, - Anchor = Anchor.TopCentre, - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Spacing = new Vector2(0f, 10f), - Width = content_width, - LayoutDuration = 200, - LayoutEasing = Easing.OutQuint, - Children = new ModSection[] + // Body + new OsuScrollContainer { - new DifficultyReductionSection { Action = modButtonPressed }, - new DifficultyIncreaseSection { Action = modButtonPressed }, - new AutomationSection { Action = modButtonPressed }, - new ConversionSection { Action = modButtonPressed }, - new FunSection { Action = modButtonPressed }, - } - }, + ScrollbarVisible = false, + Origin = Anchor.TopCentre, + Anchor = Anchor.TopCentre, + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding + { + Vertical = 10, + Horizontal = OsuScreen.HORIZONTAL_OVERFLOW_PADDING + }, + Children = new Drawable[] + { + ModSectionsContainer = new FillFlowContainer + { + Origin = Anchor.TopCentre, + Anchor = Anchor.TopCentre, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Spacing = new Vector2(0f, 10f), + Width = content_width, + LayoutDuration = 200, + LayoutEasing = Easing.OutQuint, + Children = new ModSection[] + { + new DifficultyReductionSection { Action = modButtonPressed }, + new DifficultyIncreaseSection { Action = modButtonPressed }, + new AutomationSection { Action = modButtonPressed }, + new ConversionSection { Action = modButtonPressed }, + new FunSection { Action = modButtonPressed }, + } + }, + } + }, + ModSettingsContainer = new ModSettingsContainer + { + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.BottomRight, + Origin = Anchor.BottomRight, + Width = 0.3f, + Alpha = 0, + Padding = new MarginPadding(30), + SelectedMods = { BindTarget = SelectedMods }, + }, + } }, }, new Drawable[] @@ -237,7 +257,7 @@ namespace osu.Game.Overlays.Mods { Width = 180, Text = "Customisation", - Action = () => ModSettingsContainer.Alpha = ModSettingsContainer.Alpha == 1 ? 0 : 1, + Action = () => ModSettingsContainer.ToggleVisibility(), Enabled = { Value = false }, Origin = Anchor.CentreLeft, Anchor = Anchor.CentreLeft, @@ -281,16 +301,6 @@ namespace osu.Game.Overlays.Mods }, }, }, - ModSettingsContainer = new ModSettingsContainer - { - RelativeSizeAxes = Axes.Both, - Anchor = Anchor.BottomRight, - Origin = Anchor.BottomRight, - Width = 0.25f, - Alpha = 0, - X = -100, - SelectedMods = { BindTarget = SelectedMods }, - } }; ((IBindable)CustomiseButton.Enabled).BindTo(ModSettingsContainer.HasSettingsForSelection); @@ -430,7 +440,7 @@ namespace osu.Game.Overlays.Mods DeselectTypes(selectedMod.IncompatibleMods, true); - if (selectedMod.RequiresConfiguration) ModSettingsContainer.Alpha = 1; + if (selectedMod.RequiresConfiguration) ModSettingsContainer.Show(); } else { diff --git a/osu.Game/Overlays/Mods/ModSettingsContainer.cs b/osu.Game/Overlays/Mods/ModSettingsContainer.cs index b185b56ecd..1c57ff54ad 100644 --- a/osu.Game/Overlays/Mods/ModSettingsContainer.cs +++ b/osu.Game/Overlays/Mods/ModSettingsContainer.cs @@ -17,7 +17,7 @@ using osuTK.Graphics; namespace osu.Game.Overlays.Mods { - public class ModSettingsContainer : Container + public class ModSettingsContainer : VisibilityContainer { public readonly IBindable> SelectedMods = new Bindable>(Array.Empty()); @@ -27,26 +27,40 @@ namespace osu.Game.Overlays.Mods private readonly FillFlowContainer modSettingsContent; + private readonly Container content; + + private const double transition_duration = 400; + public ModSettingsContainer() { - Children = new Drawable[] + RelativeSizeAxes = Axes.Both; + + Child = content = new Container { - new Box + Masking = true, + CornerRadius = 10, + RelativeSizeAxes = Axes.Both, + RelativePositionAxes = Axes.Both, + X = 1, + Children = new Drawable[] { - RelativeSizeAxes = Axes.Both, - Colour = new Color4(0, 0, 0, 192) - }, - new OsuScrollContainer - { - RelativeSizeAxes = Axes.Both, - Child = modSettingsContent = new FillFlowContainer + new Box { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Spacing = new Vector2(0f, 10f), - Padding = new MarginPadding(20), + RelativeSizeAxes = Axes.Both, + Colour = new Color4(0, 0, 0, 192) + }, + new OsuScrollContainer + { + RelativeSizeAxes = Axes.Both, + Child = modSettingsContent = new FillFlowContainer + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Spacing = new Vector2(0f, 10f), + Padding = new MarginPadding(20), + } } } }; @@ -80,5 +94,17 @@ namespace osu.Game.Overlays.Mods protected override bool OnMouseDown(MouseDownEvent e) => true; protected override bool OnHover(HoverEvent e) => true; + + protected override void PopIn() + { + this.FadeIn(transition_duration, Easing.OutQuint); + content.MoveToX(0, transition_duration, Easing.OutQuint); + } + + protected override void PopOut() + { + this.FadeOut(transition_duration, Easing.OutQuint); + content.MoveToX(1, transition_duration, Easing.OutQuint); + } } } diff --git a/osu.Game/Overlays/SearchableList/DisplayStyleControl.cs b/osu.Game/Overlays/SearchableList/DisplayStyleControl.cs deleted file mode 100644 index ffbc1c9586..0000000000 --- a/osu.Game/Overlays/SearchableList/DisplayStyleControl.cs +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Framework.Bindables; -using osuTK; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Sprites; -using osu.Game.Graphics.Containers; - -namespace osu.Game.Overlays.SearchableList -{ - public class DisplayStyleControl : CompositeDrawable - { - public readonly Bindable DisplayStyle = new Bindable(); - - public DisplayStyleControl() - { - AutoSizeAxes = Axes.Both; - - InternalChild = new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Spacing = new Vector2(5f, 0f), - Direction = FillDirection.Horizontal, - Children = new[] - { - new DisplayStyleToggleButton(FontAwesome.Solid.ThLarge, PanelDisplayStyle.Grid, DisplayStyle), - new DisplayStyleToggleButton(FontAwesome.Solid.ListUl, PanelDisplayStyle.List, DisplayStyle), - }, - }; - - DisplayStyle.Value = PanelDisplayStyle.Grid; - } - - private class DisplayStyleToggleButton : OsuClickableContainer - { - private readonly SpriteIcon icon; - private readonly PanelDisplayStyle style; - private readonly Bindable bindable; - - public DisplayStyleToggleButton(IconUsage icon, PanelDisplayStyle style, Bindable bindable) - { - this.bindable = bindable; - this.style = style; - Size = new Vector2(25f); - - Children = new Drawable[] - { - this.icon = new SpriteIcon - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Icon = icon, - Size = new Vector2(18), - Alpha = 0.5f, - }, - }; - - bindable.ValueChanged += Bindable_ValueChanged; - Bindable_ValueChanged(new ValueChangedEvent(bindable.Value, bindable.Value)); - Action = () => bindable.Value = this.style; - } - - private void Bindable_ValueChanged(ValueChangedEvent e) - { - icon.FadeTo(e.NewValue == style ? 1.0f : 0.5f, 100); - } - - protected override void Dispose(bool isDisposing) - { - base.Dispose(isDisposing); - - bindable.ValueChanged -= Bindable_ValueChanged; - } - } - } - - public enum PanelDisplayStyle - { - Grid, - List, - } -} diff --git a/osu.Game/Overlays/SearchableList/HeaderTabControl.cs b/osu.Game/Overlays/SearchableList/HeaderTabControl.cs deleted file mode 100644 index 2087a72c54..0000000000 --- a/osu.Game/Overlays/SearchableList/HeaderTabControl.cs +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osuTK.Graphics; -using osu.Framework.Graphics.UserInterface; -using osu.Game.Graphics.UserInterface; - -namespace osu.Game.Overlays.SearchableList -{ - public class HeaderTabControl : OsuTabControl - { - protected override TabItem CreateTabItem(T value) => new HeaderTabItem(value); - - public HeaderTabControl() - { - Height = 26; - AccentColour = Color4.White; - } - - private class HeaderTabItem : OsuTabItem - { - public HeaderTabItem(T value) - : base(value) - { - Text.Font = Text.Font.With(size: 16); - } - } - } -} diff --git a/osu.Game/Overlays/SearchableList/SearchableListFilterControl.cs b/osu.Game/Overlays/SearchableList/SearchableListFilterControl.cs deleted file mode 100644 index 1990674aa9..0000000000 --- a/osu.Game/Overlays/SearchableList/SearchableListFilterControl.cs +++ /dev/null @@ -1,165 +0,0 @@ -// 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 osuTK.Graphics; -using osu.Framework.Allocation; -using osu.Framework.Extensions.Color4Extensions; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Game.Graphics; -using osu.Game.Graphics.UserInterface; -using osu.Framework.Graphics.Shapes; - -namespace osu.Game.Overlays.SearchableList -{ - public abstract class SearchableListFilterControl : Container - where TTab : struct, Enum - where TCategory : struct, Enum - { - private const float padding = 10; - - private readonly Drawable filterContainer; - private readonly Drawable rightFilterContainer; - private readonly Box tabStrip; - - public readonly SearchTextBox Search; - public readonly PageTabControl Tabs; - public readonly SlimEnumDropdown Dropdown; - public readonly DisplayStyleControl DisplayStyleControl; - - protected abstract Color4 BackgroundColour { get; } - protected abstract TTab DefaultTab { get; } - protected abstract TCategory DefaultCategory { get; } - protected virtual Drawable CreateSupplementaryControls() => null; - - /// - /// The amount of padding added to content (does not affect background or tab control strip). - /// - protected virtual float ContentHorizontalPadding => WaveOverlayContainer.WIDTH_PADDING; - - protected SearchableListFilterControl() - { - RelativeSizeAxes = Axes.X; - - var controls = CreateSupplementaryControls(); - Container controlsContainer; - Children = new[] - { - filterContainer = new Container - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = BackgroundColour, - Alpha = 0.9f, - }, - tabStrip = new Box - { - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, - RelativeSizeAxes = Axes.X, - Height = 1, - }, - new FillFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Padding = new MarginPadding - { - Top = padding, - Horizontal = ContentHorizontalPadding - }, - Children = new Drawable[] - { - Search = new FilterSearchTextBox - { - RelativeSizeAxes = Axes.X, - }, - controlsContainer = new Container - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Margin = new MarginPadding { Top = controls != null ? padding : 0 }, - }, - new Container - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Padding = new MarginPadding { Right = 225 }, - Child = Tabs = new PageTabControl - { - RelativeSizeAxes = Axes.X, - }, - }, - new Box // keep the tab strip part of autosize, but don't put it in the flow container - { - RelativeSizeAxes = Axes.X, - Height = 1, - Colour = Color4.White.Opacity(0), - }, - }, - }, - }, - }, - rightFilterContainer = new FillFlowContainer - { - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - AutoSizeAxes = Axes.Both, - Children = new Drawable[] - { - Dropdown = new SlimEnumDropdown - { - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - RelativeSizeAxes = Axes.None, - Width = 160f, - }, - DisplayStyleControl = new DisplayStyleControl - { - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - }, - } - } - }; - - if (controls != null) controlsContainer.Children = new[] { controls }; - - Tabs.Current.Value = DefaultTab; - Tabs.Current.TriggerChange(); - - Dropdown.Current.Value = DefaultCategory; - Dropdown.Current.TriggerChange(); - } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - tabStrip.Colour = colours.Yellow; - } - - protected override void Update() - { - base.Update(); - - Height = filterContainer.Height; - rightFilterContainer.Margin = new MarginPadding { Top = filterContainer.Height - 30, Right = ContentHorizontalPadding }; - } - - private class FilterSearchTextBox : SearchTextBox - { - [BackgroundDependencyLoader] - private void load() - { - BackgroundUnfocused = OsuColour.Gray(0.06f); - BackgroundFocused = OsuColour.Gray(0.12f); - } - } - } -} diff --git a/osu.Game/Overlays/Settings/Sections/Input/MouseSettings.cs b/osu.Game/Overlays/Settings/Sections/Input/MouseSettings.cs index b54ad9a641..455e13711d 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/MouseSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/MouseSettings.cs @@ -20,6 +20,9 @@ namespace osu.Game.Overlays.Settings.Sections.Input private Bindable sensitivityBindable = new BindableDouble(); private Bindable ignoredInputHandlers; + private Bindable windowMode; + private SettingsEnumDropdown confineMouseModeSetting; + [BackgroundDependencyLoader] private void load(OsuConfigManager osuConfig, FrameworkConfigManager config) { @@ -47,7 +50,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input LabelText = "Map absolute input to window", Current = config.GetBindable(FrameworkSetting.MapAbsoluteInputToWindow) }, - new SettingsEnumDropdown + confineMouseModeSetting = new SettingsEnumDropdown { LabelText = "Confine mouse cursor to window", Current = osuConfig.GetBindable(OsuSetting.ConfineMouseMode) @@ -64,6 +67,9 @@ namespace osu.Game.Overlays.Settings.Sections.Input }, }; + windowMode = config.GetBindable(FrameworkSetting.WindowMode); + windowMode.BindValueChanged(mode => confineMouseModeSetting.Alpha = mode.NewValue == WindowMode.Fullscreen ? 0 : 1, true); + if (RuntimeInfo.OS != RuntimeInfo.Platform.Windows) { rawInputToggle.Disabled = true; diff --git a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs index 3a5e3c098f..289578f3d8 100644 --- a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs +++ b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs @@ -225,10 +225,19 @@ namespace osu.Game.Rulesets.UI.Scrolling hitObject.LifetimeStart = computeOriginAdjustedLifetimeStart(hitObject); toComputeLifetime.Clear(); + } - // only AliveObjects need to be considered for layout (reduces overhead in the case of scroll speed changes). + protected override void UpdateAfterChildrenLife() + { + base.UpdateAfterChildrenLife(); + + // We need to calculate hit object positions (including nested hit objects) as soon as possible after lifetimes + // to prevent hit objects displayed in a wrong position for one frame. + // Only AliveObjects need to be considered for layout (reduces overhead in the case of scroll speed changes). foreach (var obj in AliveObjects) { + updatePosition(obj, Time.Current); + if (layoutComputed.Contains(obj)) continue; @@ -293,15 +302,6 @@ namespace osu.Game.Rulesets.UI.Scrolling } } - protected override void UpdateAfterChildrenLife() - { - base.UpdateAfterChildrenLife(); - - // We need to calculate hitobject positions as soon as possible after lifetimes so that hitobjects get the final say in their positions - foreach (var obj in AliveObjects) - updatePosition(obj, Time.Current); - } - private void updatePosition(DrawableHitObject hitObject, double currentTime) { switch (direction.Value) diff --git a/osu.Game/Screens/Edit/Setup/ResourcesSection.cs b/osu.Game/Screens/Edit/Setup/ResourcesSection.cs index 17ecfdd52e..0c957b80af 100644 --- a/osu.Game/Screens/Edit/Setup/ResourcesSection.cs +++ b/osu.Game/Screens/Edit/Setup/ResourcesSection.cs @@ -1,6 +1,7 @@ // 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 System.IO; using System.Linq; @@ -99,6 +100,8 @@ namespace osu.Game.Screens.Edit.Setup return Task.CompletedTask; } + Task ICanAcceptFiles.Import(Stream stream, string filename) => throw new NotImplementedException(); + protected override void LoadComplete() { base.LoadComplete(); diff --git a/osu.Game/Screens/Multi/Lounge/Components/FilterControl.cs b/osu.Game/Screens/Multi/Lounge/Components/FilterControl.cs index 3fc1359006..896c215c42 100644 --- a/osu.Game/Screens/Multi/Lounge/Components/FilterControl.cs +++ b/osu.Game/Screens/Multi/Lounge/Components/FilterControl.cs @@ -1,24 +1,23 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System.ComponentModel; 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.Shapes; using osu.Framework.Threading; -using osu.Game.Overlays.SearchableList; +using osu.Game.Graphics; +using osu.Game.Graphics.UserInterface; using osu.Game.Rulesets; using osuTK.Graphics; namespace osu.Game.Screens.Multi.Lounge.Components { - public class FilterControl : SearchableListFilterControl + public abstract class FilterControl : CompositeDrawable { - protected override Color4 BackgroundColour => Color4.Black.Opacity(0.5f); - protected override RoomStatusFilter DefaultTab => RoomStatusFilter.Open; - protected override RoomCategoryFilter DefaultCategory => RoomCategoryFilter.Any; - - protected override float ContentHorizontalPadding => base.ContentHorizontalPadding + OsuScreen.HORIZONTAL_OVERFLOW_PADDING; + protected const float VERTICAL_PADDING = 10; + protected const float HORIZONTAL_PADDING = 80; [Resolved(CanBeNull = true)] private Bindable filter { get; set; } @@ -26,66 +25,109 @@ namespace osu.Game.Screens.Multi.Lounge.Components [Resolved] private IBindable ruleset { get; set; } - public FilterControl() + private readonly Box tabStrip; + private readonly SearchTextBox search; + private readonly PageTabControl tabs; + + protected FilterControl() { - DisplayStyleControl.Hide(); + InternalChildren = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black, + Alpha = 0.25f, + }, + tabStrip = new Box + { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + RelativeSizeAxes = Axes.X, + Height = 1, + }, + new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding + { + Top = VERTICAL_PADDING, + Horizontal = HORIZONTAL_PADDING + }, + Children = new Drawable[] + { + search = new FilterSearchTextBox + { + RelativeSizeAxes = Axes.X, + }, + tabs = new PageTabControl + { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + RelativeSizeAxes = Axes.X, + }, + } + } + }; + + tabs.Current.Value = RoomStatusFilter.Open; + tabs.Current.TriggerChange(); } [BackgroundDependencyLoader] - private void load() + private void load(OsuColour colours) { filter ??= new Bindable(); + tabStrip.Colour = colours.Yellow; } protected override void LoadComplete() { base.LoadComplete(); - ruleset.BindValueChanged(_ => updateFilter()); - Search.Current.BindValueChanged(_ => scheduleUpdateFilter()); - Dropdown.Current.BindValueChanged(_ => updateFilter()); - Tabs.Current.BindValueChanged(_ => updateFilter(), true); + search.Current.BindValueChanged(_ => updateFilterDebounced()); + ruleset.BindValueChanged(_ => UpdateFilter()); + tabs.Current.BindValueChanged(_ => UpdateFilter(), true); } private ScheduledDelegate scheduledFilterUpdate; - private void scheduleUpdateFilter() + private void updateFilterDebounced() { scheduledFilterUpdate?.Cancel(); - scheduledFilterUpdate = Scheduler.AddDelayed(updateFilter, 200); + scheduledFilterUpdate = Scheduler.AddDelayed(UpdateFilter, 200); } - private void updateFilter() + protected void UpdateFilter() { scheduledFilterUpdate?.Cancel(); - if (filter == null) - return; + var criteria = CreateCriteria(); + criteria.SearchString = search.Current.Value; + criteria.Status = tabs.Current.Value; + criteria.Ruleset = ruleset.Value; - filter.Value = new FilterCriteria + filter.Value = criteria; + } + + protected virtual FilterCriteria CreateCriteria() => new FilterCriteria(); + + public bool HoldFocus + { + get => search.HoldFocus; + set => search.HoldFocus = value; + } + + public void TakeFocus() => search.TakeFocus(); + + private class FilterSearchTextBox : SearchTextBox + { + [BackgroundDependencyLoader] + private void load() { - SearchString = Search.Current.Value ?? string.Empty, - StatusFilter = Tabs.Current.Value, - RoomCategoryFilter = Dropdown.Current.Value, - Ruleset = ruleset.Value - }; + BackgroundUnfocused = OsuColour.Gray(0.06f); + BackgroundFocused = OsuColour.Gray(0.12f); + } } } - - public enum RoomStatusFilter - { - Open, - - [Description("Recently Ended")] - Ended, - Participated, - Owned, - } - - public enum RoomCategoryFilter - { - Any, - Normal, - Spotlight - } } diff --git a/osu.Game/Screens/Multi/Lounge/Components/FilterCriteria.cs b/osu.Game/Screens/Multi/Lounge/Components/FilterCriteria.cs index 6d70225eec..7b04be86b1 100644 --- a/osu.Game/Screens/Multi/Lounge/Components/FilterCriteria.cs +++ b/osu.Game/Screens/Multi/Lounge/Components/FilterCriteria.cs @@ -8,8 +8,8 @@ namespace osu.Game.Screens.Multi.Lounge.Components public class FilterCriteria { public string SearchString; - public RoomStatusFilter StatusFilter; - public RoomCategoryFilter RoomCategoryFilter; + public RoomStatusFilter Status; + public string Category; public RulesetInfo Ruleset; } } diff --git a/osu.Game/Screens/Multi/Lounge/Components/RoomStatusFilter.cs b/osu.Game/Screens/Multi/Lounge/Components/RoomStatusFilter.cs new file mode 100644 index 0000000000..9da938ac8b --- /dev/null +++ b/osu.Game/Screens/Multi/Lounge/Components/RoomStatusFilter.cs @@ -0,0 +1,17 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.ComponentModel; + +namespace osu.Game.Screens.Multi.Lounge.Components +{ + public enum RoomStatusFilter + { + Open, + + [Description("Recently Ended")] + Ended, + Participated, + Owned, + } +} diff --git a/osu.Game/Screens/Multi/Lounge/Components/TimeshiftFilterControl.cs b/osu.Game/Screens/Multi/Lounge/Components/TimeshiftFilterControl.cs new file mode 100644 index 0000000000..68cab283a0 --- /dev/null +++ b/osu.Game/Screens/Multi/Lounge/Components/TimeshiftFilterControl.cs @@ -0,0 +1,59 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Graphics; +using osu.Framework.Graphics.UserInterface; +using osu.Game.Graphics.UserInterface; + +namespace osu.Game.Screens.Multi.Lounge.Components +{ + public class TimeshiftFilterControl : FilterControl + { + private readonly Dropdown dropdown; + + public TimeshiftFilterControl() + { + AddInternal(dropdown = new SlimEnumDropdown + { + Anchor = Anchor.BottomRight, + Origin = Anchor.TopRight, + RelativeSizeAxes = Axes.None, + Width = 160, + X = -HORIZONTAL_PADDING, + Y = -30 + }); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + dropdown.Current.BindValueChanged(_ => UpdateFilter()); + } + + protected override FilterCriteria CreateCriteria() + { + var criteria = base.CreateCriteria(); + + switch (dropdown.Current.Value) + { + case TimeshiftCategory.Normal: + criteria.Category = "normal"; + break; + + case TimeshiftCategory.Spotlight: + criteria.Category = "spotlight"; + break; + } + + return criteria; + } + + private enum TimeshiftCategory + { + Any, + Normal, + Spotlight + } + } +} diff --git a/osu.Game/Screens/Multi/Lounge/LoungeSubScreen.cs b/osu.Game/Screens/Multi/Lounge/LoungeSubScreen.cs index 4dc9ba549b..a26a64d86d 100644 --- a/osu.Game/Screens/Multi/Lounge/LoungeSubScreen.cs +++ b/osu.Game/Screens/Multi/Lounge/LoungeSubScreen.cs @@ -48,7 +48,6 @@ namespace osu.Game.Screens.Multi.Lounge InternalChildren = new Drawable[] { - Filter = new FilterControl { Depth = -1 }, content = new Container { RelativeSizeAxes = Axes.Both, @@ -79,6 +78,11 @@ namespace osu.Game.Screens.Multi.Lounge }, }, }, + Filter = new TimeshiftFilterControl + { + RelativeSizeAxes = Axes.X, + Height = 80, + }, }; // scroll selected room into view on selection. @@ -112,7 +116,7 @@ namespace osu.Game.Screens.Multi.Lounge protected override void OnFocus(FocusEvent e) { - Filter.Search.TakeFocus(); + Filter.TakeFocus(); } public override void OnEntering(IScreen last) @@ -136,19 +140,19 @@ namespace osu.Game.Screens.Multi.Lounge private void onReturning() { - Filter.Search.HoldFocus = true; + Filter.HoldFocus = true; } public override bool OnExiting(IScreen next) { - Filter.Search.HoldFocus = false; + Filter.HoldFocus = false; return base.OnExiting(next); } public override void OnSuspending(IScreen next) { base.OnSuspending(next); - Filter.Search.HoldFocus = false; + Filter.HoldFocus = false; } private void joinRequested(Room room) diff --git a/osu.Game/Screens/Multi/Match/Components/MatchSettingsOverlay.cs b/osu.Game/Screens/Multi/Match/Components/MatchSettingsOverlay.cs index 668a373d80..b8003b9774 100644 --- a/osu.Game/Screens/Multi/Match/Components/MatchSettingsOverlay.cs +++ b/osu.Game/Screens/Multi/Match/Components/MatchSettingsOverlay.cs @@ -135,6 +135,7 @@ namespace osu.Game.Screens.Multi.Match.Components { RelativeSizeAxes = Axes.X, TabbableContentContainer = this, + LengthLimit = 100 }, }, new Section("Duration") diff --git a/osu.Game/Screens/Multi/RoomManager.cs b/osu.Game/Screens/Multi/RoomManager.cs index 2a96fa536d..fb0cf73bb9 100644 --- a/osu.Game/Screens/Multi/RoomManager.cs +++ b/osu.Game/Screens/Multi/RoomManager.cs @@ -317,7 +317,7 @@ namespace osu.Game.Screens.Multi var tcs = new TaskCompletionSource(); pollReq?.Cancel(); - pollReq = new GetRoomsRequest(currentFilter.Value.StatusFilter, currentFilter.Value.RoomCategoryFilter); + pollReq = new GetRoomsRequest(currentFilter.Value.Status, currentFilter.Value.Category); pollReq.Success += result => { diff --git a/osu.Game/Screens/Play/GameplayClockContainer.cs b/osu.Game/Screens/Play/GameplayClockContainer.cs index 2c83161614..0248432917 100644 --- a/osu.Game/Screens/Play/GameplayClockContainer.cs +++ b/osu.Game/Screens/Play/GameplayClockContainer.cs @@ -95,6 +95,16 @@ namespace osu.Game.Screens.Play localGameplayClock = new LocalGameplayClock(userOffsetClock); GameplayClock.IsPaused.BindTo(IsPaused); + + IsPaused.BindValueChanged(onPauseChanged); + } + + private void onPauseChanged(ValueChangedEvent isPaused) + { + if (isPaused.NewValue) + this.TransformBindableTo(pauseFreqAdjust, 0, 200, Easing.Out).OnComplete(_ => adjustableClock.Stop()); + else + this.TransformBindableTo(pauseFreqAdjust, 1, 200, Easing.In); } private double totalOffset => userOffsetClock.Offset + platformOffsetClock.Offset; @@ -154,13 +164,16 @@ namespace osu.Game.Screens.Play public void Start() { - // Seeking the decoupled clock to its current time ensures that its source clock will be seeked to the same time - // This accounts for the audio clock source potentially taking time to enter a completely stopped state - Seek(GameplayClock.CurrentTime); - adjustableClock.Start(); - IsPaused.Value = false; + if (!adjustableClock.IsRunning) + { + // Seeking the decoupled clock to its current time ensures that its source clock will be seeked to the same time + // This accounts for the audio clock source potentially taking time to enter a completely stopped state + Seek(GameplayClock.CurrentTime); - this.TransformBindableTo(pauseFreqAdjust, 1, 200, Easing.In); + adjustableClock.Start(); + } + + IsPaused.Value = false; } /// @@ -199,8 +212,6 @@ namespace osu.Game.Screens.Play public void Stop() { - this.TransformBindableTo(pauseFreqAdjust, 0, 200, Easing.Out).OnComplete(_ => adjustableClock.Stop()); - IsPaused.Value = true; } diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index 42074ac241..729119fa36 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Diagnostics; using System.Linq; using System.Threading.Tasks; using JetBrains.Annotations; @@ -71,8 +72,9 @@ namespace osu.Game.Screens.Play } private bool readyForPush => + !playerConsumed // don't push unless the player is completely loaded - player?.LoadState == LoadState.Ready + && player?.LoadState == LoadState.Ready // don't push if the user is hovering one of the panes, unless they are idle. && (IsHovered || idleTracker.IsIdle.Value) // don't push if the user is dragging a slider or otherwise. @@ -84,6 +86,11 @@ namespace osu.Game.Screens.Play private Player player; + /// + /// Whether the curent player instance has been consumed via . + /// + private bool playerConsumed; + private LogoTrackingContainer content; private bool hideOverlays; @@ -179,7 +186,10 @@ namespace osu.Game.Screens.Play contentIn(); MetadataInfo.Delay(750).FadeIn(500); - this.Delay(1800).Schedule(pushWhenLoaded); + + // after an initial delay, start the debounced load check. + // this will continue to execute even after resuming back on restart. + Scheduler.Add(new ScheduledDelegate(pushWhenLoaded, 1800, 0)); showMuteWarningIfNeeded(); } @@ -188,17 +198,18 @@ namespace osu.Game.Screens.Play { base.OnResuming(last); - contentIn(); + // prepare for a retry. + player = null; + playerConsumed = false; + cancelLoad(); - this.Delay(400).Schedule(pushWhenLoaded); + contentIn(); } public override void OnSuspending(IScreen next) { base.OnSuspending(next); - cancelLoad(); - BackgroundBrightnessReduction = false; // we're moving to player, so a period of silence is upcoming. @@ -274,6 +285,14 @@ namespace osu.Game.Screens.Play } } + private Player consumePlayer() + { + Debug.Assert(!playerConsumed); + + playerConsumed = true; + return player; + } + private void prepareNewPlayer() { if (!this.IsCurrentScreen()) @@ -315,64 +334,62 @@ namespace osu.Game.Screens.Play { if (!this.IsCurrentScreen()) return; - try + if (!readyForPush) { - if (!readyForPush) + // as the pushDebounce below has a delay, we need to keep checking and cancel a future debounce + // if we become unready for push during the delay. + cancelLoad(); + return; + } + + // if a push has already been scheduled, no further action is required. + // this value is reset via cancelLoad() to allow a second usage of the same PlayerLoader screen. + if (scheduledPushPlayer != null) + return; + + scheduledPushPlayer = Scheduler.AddDelayed(() => + { + // ensure that once we have reached this "point of no return", readyForPush will be false for all future checks (until a new player instance is prepared). + var consumedPlayer = consumePlayer(); + + contentOut(); + + TransformSequence pushSequence = this.Delay(250); + + // only show if the warning was created (i.e. the beatmap needs it) + // and this is not a restart of the map (the warning expires after first load). + if (epilepsyWarning?.IsAlive == true) { - // as the pushDebounce below has a delay, we need to keep checking and cancel a future debounce - // if we become unready for push during the delay. - cancelLoad(); - return; + const double epilepsy_display_length = 3000; + + pushSequence + .Schedule(() => epilepsyWarning.State.Value = Visibility.Visible) + .TransformBindableTo(volumeAdjustment, 0.25, EpilepsyWarning.FADE_DURATION, Easing.OutQuint) + .Delay(epilepsy_display_length) + .Schedule(() => + { + epilepsyWarning.Hide(); + epilepsyWarning.Expire(); + }) + .Delay(EpilepsyWarning.FADE_DURATION); } - if (scheduledPushPlayer != null) - return; - - scheduledPushPlayer = Scheduler.AddDelayed(() => + pushSequence.Schedule(() => { - contentOut(); + if (!this.IsCurrentScreen()) return; - TransformSequence pushSequence = this.Delay(250); + LoadTask = null; - // only show if the warning was created (i.e. the beatmap needs it) - // and this is not a restart of the map (the warning expires after first load). - if (epilepsyWarning?.IsAlive == true) - { - const double epilepsy_display_length = 3000; + // By default, we want to load the player and never be returned to. + // Note that this may change if the player we load requested a re-run. + ValidForResume = false; - pushSequence - .Schedule(() => epilepsyWarning.State.Value = Visibility.Visible) - .TransformBindableTo(volumeAdjustment, 0.25, EpilepsyWarning.FADE_DURATION, Easing.OutQuint) - .Delay(epilepsy_display_length) - .Schedule(() => - { - epilepsyWarning.Hide(); - epilepsyWarning.Expire(); - }) - .Delay(EpilepsyWarning.FADE_DURATION); - } - - pushSequence.Schedule(() => - { - if (!this.IsCurrentScreen()) return; - - LoadTask = null; - - // By default, we want to load the player and never be returned to. - // Note that this may change if the player we load requested a re-run. - ValidForResume = false; - - if (player.LoadedBeatmapSuccessfully) - this.Push(player); - else - this.Exit(); - }); - }, 500); - } - finally - { - Schedule(pushWhenLoaded); - } + if (consumedPlayer.LoadedBeatmapSuccessfully) + this.Push(consumedPlayer); + else + this.Exit(); + }); + }, 500); } private void cancelLoad() @@ -390,7 +407,7 @@ namespace osu.Game.Screens.Play if (isDisposing) { // if the player never got pushed, we should explicitly dispose it. - DisposalTask = LoadTask?.ContinueWith(_ => player.Dispose()); + DisposalTask = LoadTask?.ContinueWith(_ => player?.Dispose()); } } diff --git a/osu.Game/Skinning/PoolableSkinnableSample.cs b/osu.Game/Skinning/PoolableSkinnableSample.cs index 19b96d6c60..cc6b85a13e 100644 --- a/osu.Game/Skinning/PoolableSkinnableSample.cs +++ b/osu.Game/Skinning/PoolableSkinnableSample.cs @@ -102,7 +102,7 @@ namespace osu.Game.Skinning sampleContainer.Add(Sample = new DrawableSample(ch) { Looping = Looping }); // Start playback internally for the new sample if the previous one was playing beforehand. - if (wasPlaying) + if (wasPlaying && Looping) Play(); } diff --git a/osu.Game/Skinning/SkinnableSound.cs b/osu.Game/Skinning/SkinnableSound.cs index 23159e4fe1..645c08cd00 100644 --- a/osu.Game/Skinning/SkinnableSound.cs +++ b/osu.Game/Skinning/SkinnableSound.cs @@ -159,7 +159,7 @@ namespace osu.Game.Skinning samplesContainer.Add(sample); } - if (wasPlaying) + if (wasPlaying && Looping) Play(); } diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 9d37ceee6c..b4c7dca12f 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -26,7 +26,7 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index ab03393836..7542aded86 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -70,7 +70,7 @@ - + @@ -88,7 +88,7 @@ - +