From af1de01ed61d258a4d579ec0f7354163e9a24e58 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 29 Oct 2018 18:23:23 +0900 Subject: [PATCH 1/8] Add a spinner selection mask --- .../TestCaseSpinnerSelectionMask.cs | 50 ++++++++++++++ .../SpinnerMasks/Components/SpinnerPiece.cs | 65 +++++++++++++++++++ .../SpinnerMasks/SpinnerSelectionMask.cs | 24 +++++++ .../Edit/OsuHitObjectComposer.cs | 3 + .../Objects/Drawables/DrawableSpinner.cs | 4 +- 5 files changed, 145 insertions(+), 1 deletion(-) create mode 100644 osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerSelectionMask.cs create mode 100644 osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/Components/SpinnerPiece.cs create mode 100644 osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/SpinnerSelectionMask.cs diff --git a/osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerSelectionMask.cs b/osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerSelectionMask.cs new file mode 100644 index 0000000000..b436ff0e9f --- /dev/null +++ b/osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerSelectionMask.cs @@ -0,0 +1,50 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using System.Collections.Generic; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Beatmaps; +using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Rulesets.Edit; +using osu.Game.Rulesets.Osu.Edit.Masks.SpinnerMasks; +using osu.Game.Rulesets.Osu.Edit.Masks.SpinnerMasks.Components; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Osu.Objects.Drawables; +using osu.Game.Tests.Visual; +using OpenTK; + +namespace osu.Game.Rulesets.Osu.Tests +{ + public class TestCaseSpinnerSelectionMask : HitObjectSelectionMaskTestCase + { + public override IReadOnlyList RequiredTypes => new[] + { + typeof(SpinnerSelectionMask), + typeof(SpinnerPiece) + }; + + private readonly DrawableSpinner drawableSpinner; + + public TestCaseSpinnerSelectionMask() + { + var spinner = new Spinner + { + Position = new Vector2(256, 256), + StartTime = -1000, + EndTime = 2000 + }; + spinner.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty { CircleSize = 2 }); + + Add(new Container + { + RelativeSizeAxes = Axes.Both, + Size = new Vector2(0.5f), + Child = drawableSpinner = new DrawableSpinner(spinner) + }); + } + + protected override SelectionMask CreateMask() => new SpinnerSelectionMask(drawableSpinner) { Size = new Vector2(0.5f) }; + } +} diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/Components/SpinnerPiece.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/Components/SpinnerPiece.cs new file mode 100644 index 0000000000..ce2b5cd1d6 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/Components/SpinnerPiece.cs @@ -0,0 +1,65 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +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 OpenTK; + +namespace osu.Game.Rulesets.Osu.Edit.Masks.SpinnerMasks.Components +{ + public class SpinnerPiece : CompositeDrawable + { + private readonly Spinner spinner; + private readonly CircularContainer circle; + + public SpinnerPiece(Spinner spinner) + { + this.spinner = spinner; + + Origin = Anchor.Centre; + + RelativeSizeAxes = Axes.Both; + FillMode = FillMode.Fit; + Size = new Vector2(1.3f); + + RingPiece ring; + InternalChildren = new Drawable[] + { + circle = new CircularContainer + { + RelativeSizeAxes = Axes.Both, + Masking = true, + Alpha = 0.5f, + Child = new Box { RelativeSizeAxes = Axes.Both } + }, + ring = new RingPiece + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre + } + }; + + ring.Scale = new Vector2(spinner.Scale); + + spinner.PositionChanged += _ => updatePosition(); + spinner.StackHeightChanged += _ => updatePosition(); + + updatePosition(); + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + Colour = colours.Yellow; + } + + private void updatePosition() => Position = spinner.Position; + + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => circle.ReceivePositionalInputAt(screenSpacePos); + } +} diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/SpinnerSelectionMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/SpinnerSelectionMask.cs new file mode 100644 index 0000000000..0e47bd2a8b --- /dev/null +++ b/osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/SpinnerSelectionMask.cs @@ -0,0 +1,24 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Game.Rulesets.Edit; +using osu.Game.Rulesets.Osu.Edit.Masks.SpinnerMasks.Components; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Osu.Objects.Drawables; +using OpenTK; + +namespace osu.Game.Rulesets.Osu.Edit.Masks.SpinnerMasks +{ + public class SpinnerSelectionMask : SelectionMask + { + private readonly SpinnerPiece piece; + + public SpinnerSelectionMask(DrawableSpinner spinner) + : base(spinner) + { + InternalChild = piece = new SpinnerPiece((Spinner)spinner.HitObject); + } + + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => piece.ReceivePositionalInputAt(screenSpacePos); + } +} diff --git a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs index ac41d6ef27..386665ab7c 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs @@ -10,6 +10,7 @@ using osu.Game.Rulesets.Edit.Tools; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Osu.Edit.Masks.HitCircleMasks; using osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks; +using osu.Game.Rulesets.Osu.Edit.Masks.SpinnerMasks; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Rulesets.Osu.UI; @@ -42,6 +43,8 @@ namespace osu.Game.Rulesets.Osu.Edit return new HitCircleSelectionMask(circle); case DrawableSlider slider: return new SliderSelectionMask(slider); + case DrawableSpinner spinner: + return new SpinnerSelectionMask(spinner); } return base.CreateMaskFor(hitObject); diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs index 51b1990a21..f3846bd52f 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs @@ -112,6 +112,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables Alpha = 0 } }; + + s.PositionChanged += _ => Position = s.Position; } public float Progress => MathHelper.Clamp(Disc.RotationAbsolute / 360 / Spinner.SpinsRequired, 0, 1); @@ -167,7 +169,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables protected override void Update() { - Disc.Tracking = OsuActionInputManager.PressedActions.Any(x => x == OsuAction.LeftButton || x == OsuAction.RightButton); + Disc.Tracking = OsuActionInputManager?.PressedActions.Any(x => x == OsuAction.LeftButton || x == OsuAction.RightButton) ?? false; if (!spmCounter.IsPresent && Disc.Tracking) spmCounter.FadeIn(HitObject.TimeFadeIn); From e04ad8357d1e32b849e059a65c71e10e0cecc97a Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 29 Oct 2018 18:37:12 +0900 Subject: [PATCH 2/8] Make spinner piece respond to scale changes --- .../Edit/Masks/SpinnerMasks/Components/SpinnerPiece.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/Components/SpinnerPiece.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/Components/SpinnerPiece.cs index ce2b5cd1d6..0d9609facf 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/Components/SpinnerPiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/Components/SpinnerPiece.cs @@ -48,6 +48,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks.SpinnerMasks.Components spinner.PositionChanged += _ => updatePosition(); spinner.StackHeightChanged += _ => updatePosition(); + spinner.ScaleChanged += _ => ring.Scale = new Vector2(spinner.Scale); updatePosition(); } From aec1d95f045ce65b5b5ef0fe0efaa4416cffd4f6 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 29 Oct 2018 18:35:46 +0900 Subject: [PATCH 3/8] Implement spinner placement --- .../TestCaseSpinnerPlacementMask.cs | 20 +++++++ .../SpinnerMasks/SpinnerPlacementMask.cs | 59 +++++++++++++++++++ .../Edit/OsuHitObjectComposer.cs | 3 +- .../Edit/SpinnerCompositionTool.cs | 20 +++++++ 4 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerPlacementMask.cs create mode 100644 osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/SpinnerPlacementMask.cs create mode 100644 osu.Game.Rulesets.Osu/Edit/SpinnerCompositionTool.cs diff --git a/osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerPlacementMask.cs b/osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerPlacementMask.cs new file mode 100644 index 0000000000..c2c7942c57 --- /dev/null +++ b/osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerPlacementMask.cs @@ -0,0 +1,20 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Game.Rulesets.Edit; +using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.Osu.Edit.Masks.SpinnerMasks; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Osu.Objects.Drawables; +using osu.Game.Tests.Visual; + +namespace osu.Game.Rulesets.Osu.Tests +{ + public class TestCaseSpinnerPlacementMask : HitObjectPlacementMaskTestCase + { + protected override DrawableHitObject CreateHitObject(HitObject hitObject) => new DrawableSpinner((Spinner)hitObject); + + protected override PlacementMask CreateMask() => new SpinnerPlacementMask(); + } +} diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/SpinnerPlacementMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/SpinnerPlacementMask.cs new file mode 100644 index 0000000000..97356fa8b6 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/SpinnerPlacementMask.cs @@ -0,0 +1,59 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Graphics; +using osu.Framework.Input.Events; +using osu.Game.Rulesets.Edit; +using osu.Game.Rulesets.Osu.Edit.Masks.SpinnerMasks.Components; +using osu.Game.Rulesets.Osu.Objects; + +namespace osu.Game.Rulesets.Osu.Edit.Masks.SpinnerMasks +{ + public class SpinnerPlacementMask : PlacementMask + { + public new Spinner HitObject => (Spinner)base.HitObject; + + private readonly SpinnerPiece piece; + + private bool isPlacingEnd; + + public SpinnerPlacementMask() + : base(new Spinner()) + { + InternalChild = piece = new SpinnerPiece(HitObject) { Alpha = 0.5f }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + // Fixes a 1-frame position discrpancy due to the first mouse move event happening in the next frame + HitObject.Position = GetContainingInputManager().CurrentState.Mouse.Position; + } + + protected override bool OnClick(ClickEvent e) + { + if (isPlacingEnd) + { + HitObject.EndTime = EditorClock.CurrentTime; + EndPlacement(); + } + else + { + HitObject.StartTime = EditorClock.CurrentTime; + + isPlacingEnd = true; + piece.FadeTo(1f, 150, Easing.OutQuint); + } + + return true; + } + + protected override bool OnMouseMove(MouseMoveEvent e) + { + if (!isPlacingEnd) + HitObject.Position = e.MousePosition; + return true; + } + } +} diff --git a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs index 386665ab7c..a1629803c0 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs @@ -28,9 +28,10 @@ namespace osu.Game.Rulesets.Osu.Edit protected override RulesetContainer CreateRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap) => new OsuEditRulesetContainer(ruleset, beatmap); - protected override IReadOnlyList CompositionTools => new[] + protected override IReadOnlyList CompositionTools => new HitObjectCompositionTool[] { new HitCircleCompositionTool(), + new SpinnerCompositionTool() }; protected override Container CreateLayerContainer() => new PlayfieldAdjustmentContainer { RelativeSizeAxes = Axes.Both }; diff --git a/osu.Game.Rulesets.Osu/Edit/SpinnerCompositionTool.cs b/osu.Game.Rulesets.Osu/Edit/SpinnerCompositionTool.cs new file mode 100644 index 0000000000..a1419fe281 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Edit/SpinnerCompositionTool.cs @@ -0,0 +1,20 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Game.Rulesets.Edit; +using osu.Game.Rulesets.Edit.Tools; +using osu.Game.Rulesets.Osu.Edit.Masks.SpinnerMasks; +using osu.Game.Rulesets.Osu.Objects; + +namespace osu.Game.Rulesets.Osu.Edit +{ + public class SpinnerCompositionTool : HitObjectCompositionTool + { + public SpinnerCompositionTool() + : base(nameof(Spinner)) + { + } + + public override PlacementMask CreatePlacementMask() => new SpinnerPlacementMask(); + } +} From 29a1d092fad67cd2bdbc65c36ce0fca08dbfd6c6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 31 Oct 2018 16:43:35 +0900 Subject: [PATCH 4/8] Don't log disk space related IO errors --- osu.Game/Utils/RavenLogger.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game/Utils/RavenLogger.cs b/osu.Game/Utils/RavenLogger.cs index b28dd1fb73..6679ff94a9 100644 --- a/osu.Game/Utils/RavenLogger.cs +++ b/osu.Game/Utils/RavenLogger.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.IO; using System.Threading.Tasks; using osu.Framework.Logging; using SharpRaven; @@ -35,6 +36,9 @@ namespace osu.Game.Utils if (exception != null) { + if (exception is IOException ioe && ioe.Message.StartsWith("There is not enough space on the disk")) + return; + // since we let unhandled exceptions go ignored at times, we want to ensure they don't get submitted on subsequent reports. if (lastException != null && lastException.Message == exception.Message && exception.StackTrace.StartsWith(lastException.StackTrace)) From 9aa88293e2509a9f9a3f3426647519e505e94992 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 31 Oct 2018 17:07:05 +0900 Subject: [PATCH 5/8] Use HResult --- osu.Game/Utils/RavenLogger.cs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/osu.Game/Utils/RavenLogger.cs b/osu.Game/Utils/RavenLogger.cs index 6679ff94a9..c6e6d1e9d7 100644 --- a/osu.Game/Utils/RavenLogger.cs +++ b/osu.Game/Utils/RavenLogger.cs @@ -36,8 +36,15 @@ namespace osu.Game.Utils if (exception != null) { - if (exception is IOException ioe && ioe.Message.StartsWith("There is not enough space on the disk")) - return; + if (exception is IOException ioe) + { + // disk full exceptions, see https://stackoverflow.com/a/9294382 + const int hr_error_handle_disk_full = unchecked((int)0x80070027); + const int hr_error_disk_full = unchecked((int)0x80070070); + + if (ioe.HResult == hr_error_handle_disk_full || ioe.HResult == hr_error_disk_full) + return; + } // since we let unhandled exceptions go ignored at times, we want to ensure they don't get submitted on subsequent reports. if (lastException != null && From 2ac4f2b6af4c101e968441fd94ed6dcf4ca70e10 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 1 Nov 2018 19:24:58 +0900 Subject: [PATCH 6/8] Lock spinners to centre of screen --- .../Masks/SpinnerMasks/SpinnerPlacementMask.cs | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/SpinnerPlacementMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/SpinnerPlacementMask.cs index 97356fa8b6..cd5d6cff04 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/SpinnerPlacementMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/SpinnerPlacementMask.cs @@ -6,6 +6,7 @@ using osu.Framework.Input.Events; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Osu.Edit.Masks.SpinnerMasks.Components; using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Osu.UI; namespace osu.Game.Rulesets.Osu.Edit.Masks.SpinnerMasks { @@ -18,19 +19,11 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks.SpinnerMasks private bool isPlacingEnd; public SpinnerPlacementMask() - : base(new Spinner()) + : base(new Spinner { Position = OsuPlayfield.BASE_SIZE / 2 }) { InternalChild = piece = new SpinnerPiece(HitObject) { Alpha = 0.5f }; } - protected override void LoadComplete() - { - base.LoadComplete(); - - // Fixes a 1-frame position discrpancy due to the first mouse move event happening in the next frame - HitObject.Position = GetContainingInputManager().CurrentState.Mouse.Position; - } - protected override bool OnClick(ClickEvent e) { if (isPlacingEnd) @@ -48,12 +41,5 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks.SpinnerMasks return true; } - - protected override bool OnMouseMove(MouseMoveEvent e) - { - if (!isPlacingEnd) - HitObject.Position = e.MousePosition; - return true; - } } } From 0a0023920fd5268a748134489a87a315b9c02e15 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 2 Nov 2018 04:09:33 +0900 Subject: [PATCH 7/8] Fix not being able to drag control points mid-snake --- .../Screens/Edit/Screens/Compose/Layers/HitObjectMaskLayer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Screens/Compose/Layers/HitObjectMaskLayer.cs b/osu.Game/Screens/Edit/Screens/Compose/Layers/HitObjectMaskLayer.cs index 3e33ceefcd..0392cb5952 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Layers/HitObjectMaskLayer.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Layers/HitObjectMaskLayer.cs @@ -52,7 +52,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers AddMaskFor(obj); } - protected override bool OnMouseDown(MouseDownEvent e) + protected override bool OnClick(ClickEvent e) { maskContainer.DeselectAll(); return true; From 7f1ee3bcb478303719a2c8f8476e1d33083e16dd Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 2 Nov 2018 12:06:53 +0900 Subject: [PATCH 8/8] Disallow spinner movement for now --- osu.Game.Rulesets.Osu/Objects/Spinner.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/osu.Game.Rulesets.Osu/Objects/Spinner.cs b/osu.Game.Rulesets.Osu/Objects/Spinner.cs index 1c60fd4831..1270685ab5 100644 --- a/osu.Game.Rulesets.Osu/Objects/Spinner.cs +++ b/osu.Game.Rulesets.Osu/Objects/Spinner.cs @@ -7,6 +7,7 @@ using osu.Game.Rulesets.Objects.Types; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Osu.Judgements; +using OpenTK; namespace osu.Game.Rulesets.Osu.Objects { @@ -31,5 +32,10 @@ namespace osu.Game.Rulesets.Osu.Objects } public override Judgement CreateJudgement() => new OsuJudgement(); + + public override void OffsetPosition(Vector2 offset) + { + // for now we don't want to allow spinners to be moved around. + } } }