1
0
mirror of https://github.com/ppy/osu.git synced 2026-05-16 19:23:11 +08:00

Emit important replay frames on every judgement

- Closes https://github.com/ppy/osu/issues/4287
- Probably closes https://github.com/ppy/osu/issues/25405 (but not
  retroactively)

Up until now, whether or not a replay frame is emitted depended solely
on the user's input, i.e. mouse movement or key presses/releases. This,
intersected with the replay playback system which is given allowance to
perform interpolation between replay frames, leads to potential
situations wherein a replay can play inaccurately when a judgement takes
place without user input meaningfully changing. One such case is slider
ends with their 36ms of judgement leniency; see
https://github.com/ppy/osu/issues/25405#issuecomment-2879031106 for
details on that.

To that end, this commit aims to counteract that issue by *forcing* an
important replay frame to be emitted on every new judgement recorded
during gameplay. This will only benefit rulesets wherein judgements can
occur that are not inherently tied to user input changing, which are
going to be osu! as mentioned above, and maybe possibly catch. I don't
foresee this doing anything relevant for taiko or mania.
This commit is contained in:
Bartłomiej Dach
2025-05-15 10:45:17 +02:00
Unverified
parent 5939f51558
commit 9f91c2e25c
4 changed files with 13 additions and 6 deletions
+4
View File
@@ -300,6 +300,7 @@ namespace osu.Game.Rulesets.UI
if (score == null)
{
NewResult -= emitImportantFrame;
recordingInputManager.Recorder = null;
return;
}
@@ -311,7 +312,10 @@ namespace osu.Game.Rulesets.UI
recorder.ScreenSpaceToGamefield = Playfield.ScreenSpaceToGamefield;
NewResult += emitImportantFrame;
recordingInputManager.Recorder = recorder;
void emitImportantFrame(JudgementResult judgementResult) => recordingInputManager.Recorder?.RecordFrame(true);
}
public override void SetReplayScore(Score replayScore)
+1 -1
View File
@@ -10,6 +10,6 @@ namespace osu.Game.Rulesets.UI
/// </summary>
public interface IHasRecordingHandler
{
public ReplayRecorder? Recorder { set; }
public ReplayRecorder? Recorder { get; set; }
}
}
+7 -5
View File
@@ -51,29 +51,29 @@ namespace osu.Game.Rulesets.UI
protected override void Update()
{
base.Update();
recordFrame(false);
RecordFrame(false);
}
protected override bool OnMouseMove(MouseMoveEvent e)
{
recordFrame(false);
RecordFrame(false);
return base.OnMouseMove(e);
}
public bool OnPressed(KeyBindingPressEvent<T> e)
{
pressedActions.Add(e.Action);
recordFrame(true);
RecordFrame(true);
return false;
}
public void OnReleased(KeyBindingReleaseEvent<T> e)
{
pressedActions.Remove(e.Action);
recordFrame(true);
RecordFrame(true);
}
private void recordFrame(bool important)
public override void RecordFrame(bool important)
{
var last = target.Replay.Frames.LastOrDefault();
@@ -98,5 +98,7 @@ namespace osu.Game.Rulesets.UI
public abstract partial class ReplayRecorder : Component
{
public Func<Vector2, Vector2> ScreenSpaceToGamefield;
public abstract void RecordFrame(bool important);
}
}
@@ -39,6 +39,7 @@ namespace osu.Game.Rulesets.UI
public ReplayRecorder? Recorder
{
get => recorder;
set
{
if (value == recorder)