Skip to content

Commit c9db076

Browse files
authored
Merge pull request #27 from winnerspiros/autopilot-cursor-logic-improvement-10698393220144712166
Improve Autopilot cursor movement logic
2 parents 861c6d3 + e9b669a commit c9db076

2 files changed

Lines changed: 73 additions & 3 deletions

File tree

osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs

Lines changed: 72 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,11 @@
1010
using osu.Game.Graphics;
1111
using osu.Game.Rulesets.Mods;
1212
using osu.Game.Rulesets.Osu.Objects;
13+
using osu.Game.Rulesets.Osu.Objects.Drawables;
1314
using osu.Game.Rulesets.Osu.Replays;
1415
using osu.Game.Rulesets.Osu.UI;
1516
using osu.Game.Rulesets.UI;
17+
using osuTK;
1618

1719
namespace osu.Game.Rulesets.Osu.Mods
1820
{
@@ -43,12 +45,79 @@ public class OsuModAutopilot : Mod, IUpdatableByPlayfield, IApplicableToDrawable
4345

4446
public void Update(Playfield playfield)
4547
{
46-
if (currentFrame == replayFrames.Count - 1) return;
48+
if (replayFrames.Count == 0 || currentFrame == replayFrames.Count - 1) return;
4749

4850
double time = playfield.Clock.CurrentTime;
4951

50-
// Very naive implementation of autopilot based on proximity to replay frames.
52+
// Interpolate the cursor position using the replay frames.
5153
// Special case for the first frame is required to ensure the mouse is in a sane position until the actual time of the first frame is hit.
54+
while (currentFrame > 0 && Math.Abs(replayFrames[currentFrame - 1].Time - time) <= Math.Abs(replayFrames[currentFrame].Time - time))
55+
{
56+
currentFrame--;
57+
}
58+
59+
while (currentFrame < replayFrames.Count - 1 && Math.Abs(replayFrames[currentFrame + 1].Time - time) <= Math.Abs(replayFrames[currentFrame < 0 ? 0 : currentFrame].Time - time))
60+
{
61+
currentFrame++;
62+
}
63+
64+
if (currentFrame < 0)
65+
return;
66+
67+
Vector2 newPosition = playfield.ToScreenSpace(replayFrames[currentFrame].Position);
68+
69+
var osuPlayfield = (OsuPlayfield)playfield;
70+
71+
DrawableOsuHitObject? nextObject = null;
72+
73+
foreach (var h in osuPlayfield.HitObjectContainer.AliveObjects)
74+
{
75+
if (h is not DrawableOsuHitObject osuHitObject || osuHitObject.Result.HasResult)
76+
continue;
77+
78+
if (nextObject == null || osuHitObject.HitObject.StartTime < nextObject.HitObject.StartTime)
79+
{
80+
nextObject = osuHitObject;
81+
}
82+
}
83+
84+
if (nextObject != null)
85+
{
86+
// If we are currently "on" an object (in terms of time), we should check if it has been judged.
87+
// If it hasn't been judged, and we are still within the valid hit window, maybe we should clamp the cursor position to that object's position, effectively "pausing" the cursor movement along the path until the user clicks or it's too late.
88+
89+
bool shouldStay = false;
90+
Vector2 stayPosition = Vector2.Zero;
91+
92+
if (nextObject is DrawableSlider slider)
93+
{
94+
if (!slider.HeadCircle.Result.HasResult)
95+
{
96+
if (time >= slider.HitObject.StartTime)
97+
{
98+
shouldStay = true;
99+
stayPosition = slider.HitObject.StackedPosition;
100+
}
101+
}
102+
}
103+
else if (nextObject is DrawableHitCircle hitCircle)
104+
{
105+
if (time >= hitCircle.HitObject.StartTime)
106+
{
107+
shouldStay = true;
108+
stayPosition = hitCircle.HitObject.StackedPosition;
109+
}
110+
}
111+
112+
if (shouldStay)
113+
{
114+
newPosition = playfield.ToScreenSpace(stayPosition);
115+
}
116+
}
117+
118+
new MousePositionAbsoluteInput { Position = newPosition }.Apply(inputManager.CurrentState, inputManager);
119+
120+
// TODO: Implement the functionality to automatically spin spinners
52121
// TODO: this needs to be based on user interactions to better match stable (pausing until judgement is registered).
53122
while (currentFrame < replayFrames.Count - 1)
54123
{
@@ -74,6 +143,7 @@ public void ApplyToDrawableRuleset(DrawableRuleset<OsuHitObject> drawableRuleset
74143

75144
// Generate the replay frames the cursor should follow
76145
replayFrames = new OsuAutoGenerator(drawableRuleset.Beatmap, drawableRuleset.Mods).Generate().Frames.Cast<OsuReplayFrame>().ToList();
146+
currentFrame = -1;
77147
}
78148
}
79149
}

osu.Game/Database/BackgroundDataStoreProcessor.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ protected override void LoadComplete()
9696
convertLegacyTotalScoreToStandardised();
9797
upgradeScoreRanks();
9898
backpopulateMissingSubmissionAndRankDates();
99-
backpopulateUserTags();
99+
BackpopulateUserTags();
100100
}, TaskCreationOptions.LongRunning).ContinueWith(t =>
101101
{
102102
if (t.Exception?.InnerException is ObjectDisposedException)

0 commit comments

Comments
 (0)