Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add convert to stream functionality for juice streams #30763

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Input.Bindings;
using osu.Framework.Input.Events;
using osu.Framework.Utils;
using osu.Game.Graphics.UserInterface;
using osu.Game.Rulesets.Catch.Edit.Blueprints.Components;
using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Types;
using osu.Game.Screens.Edit;
using osuTK;
using osuTK.Input;
Expand Down Expand Up @@ -54,6 +56,12 @@ public partial class JuiceStreamSelectionBlueprint : CatchSelectionBlueprint<Jui
[Resolved]
private EditorBeatmap? editorBeatmap { get; set; }

[Resolved]
private IEditorChangeHandler? changeHandler { get; set; }

[Resolved]
private BindableBeatDivisor? beatDivisor { get; set; }

public JuiceStreamSelectionBlueprint(JuiceStream hitObject)
: base(hitObject)
{
Expand Down Expand Up @@ -119,6 +127,20 @@ protected override bool OnMouseDown(MouseDownEvent e)
return base.OnMouseDown(e);
}

protected override bool OnKeyDown(KeyDownEvent e)
{
if (!IsSelected)
return false;

if (e.Key == Key.F && e.ControlPressed && e.ShiftPressed)
{
convertToStream();
return true;
}

return false;
}

private void onDefaultsApplied(HitObject _)
{
computeObjectBounds();
Expand Down Expand Up @@ -168,6 +190,48 @@ private void updateHitObjectFromPath()
lastSliderPathVersion = HitObject.Path.Version.Value;
}

private void convertToStream()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure how to feel about this being a nigh carbon-copy of the osu! implementation. Especially so that I've heard osu! mappers call the current implementation of slider-to-stream "kneecapped" and wish for the stable one that could do more to be restored.

Probably would have preferred this was split to some common method in light of that, so that once that gets implemented, both rulesets reap the benefit. Or at the minimum link back both copies of the logic to each other.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure how to feel about this being a nigh carbon-copy of the osu! implementation. Especially so that I've heard osu! mappers call the current implementation of slider-to-stream "kneecapped" and wish for the stable one that could do more to be restored.

I wasn't aware that the current implementation was subpar; My intention for this PR was to have something in place instead of nothing at all. So might be better to have an improved version of this (and the osu version improved) in a follow-up PR.

Probably would have preferred this was split to some common method in light of that, so that once that gets implemented, both rulesets reap the benefit. Or at the minimum link back both copies of the logic to each other.

Good point. I'll rework it a bit so we have a shared implementation for the duplicate logic 👍
I initially didn't want to do this as I wasn't sure how overlapping the catch and osu logic would be, but it ended up almost the same...

{
if (editorBeatmap == null || beatDivisor == null)
return;

var timingPoint = editorBeatmap.ControlPointInfo.TimingPointAt(HitObject.StartTime);
double streamSpacing = timingPoint.BeatLength / beatDivisor.Value;

changeHandler?.BeginChange();

int i = 0;
double time = HitObject.StartTime;

while (!Precision.DefinitelyBigger(time, HitObject.GetEndTime(), 1))
{
// positionWithRepeats is a fractional number in the range of [0, HitObject.SpanCount()]
// and indicates how many fractional spans of a slider have passed up to time.
double positionWithRepeats = (time - HitObject.StartTime) / HitObject.Duration * HitObject.SpanCount();
double pathPosition = positionWithRepeats - (int)positionWithRepeats;
// every second span is in the reverse direction - need to reverse the path position.
if (positionWithRepeats % 2 >= 1)
pathPosition = 1 - pathPosition;

float fruitXValue = HitObject.OriginalX + HitObject.Path.PositionAt(pathPosition).X;

editorBeatmap.Add(new Fruit
{
StartTime = time,
OriginalX = fruitXValue,
NewCombo = i == 0 && HitObject.NewCombo,
Samples = HitObject.Samples.Select(s => s.With()).ToList()
});

i += 1;
time = HitObject.StartTime + i * streamSpacing;
}

editorBeatmap.Remove(HitObject);

changeHandler?.EndChange();
}

private IEnumerable<MenuItem> getContextMenuItems()
{
yield return new OsuMenuItem("Add vertex", MenuItemType.Standard, () =>
Expand All @@ -177,6 +241,11 @@ private IEnumerable<MenuItem> getContextMenuItems()
{
Hotkey = new Hotkey(new KeyCombination(InputKey.Control, InputKey.MouseLeft))
};

yield return new OsuMenuItem("Convert to stream", MenuItemType.Destructive, convertToStream)
{
Hotkey = new Hotkey(new KeyCombination(InputKey.Control, InputKey.Shift, InputKey.F))
};
}

protected override void Dispose(bool isDisposing)
Expand Down
Loading