Merge branch 'improve-catch-replay-frames' into key-counter-fixes

This commit is contained in:
Dean Herbert 2019-09-12 18:34:00 +09:00
commit 1dfd104690
15 changed files with 251 additions and 92 deletions

View File

@ -27,6 +27,8 @@ namespace osu.Game.Rulesets.Catch.Replays
protected Replay Replay; protected Replay Replay;
private CatchReplayFrame currentFrame;
public override Replay Generate() public override Replay Generate()
{ {
// todo: add support for HT DT // todo: add support for HT DT
@ -36,7 +38,7 @@ namespace osu.Game.Rulesets.Catch.Replays
double lastTime = 0; double lastTime = 0;
// Todo: Realistically this shouldn't be needed, but the first frame is skipped with the way replays are currently handled // Todo: Realistically this shouldn't be needed, but the first frame is skipped with the way replays are currently handled
Replay.Frames.Add(new CatchReplayFrame(-100000, lastPosition)); addFrame(-100000, lastPosition);
void moveToNext(CatchHitObject h) void moveToNext(CatchHitObject h)
{ {
@ -58,18 +60,18 @@ namespace osu.Game.Rulesets.Catch.Replays
{ {
//we are already in the correct range. //we are already in the correct range.
lastTime = h.StartTime; lastTime = h.StartTime;
Replay.Frames.Add(new CatchReplayFrame(h.StartTime, lastPosition)); addFrame(h.StartTime, lastPosition);
return; return;
} }
if (impossibleJump) if (impossibleJump)
{ {
Replay.Frames.Add(new CatchReplayFrame(h.StartTime, h.X)); addFrame(h.StartTime, h.X);
} }
else if (h.HyperDash) else if (h.HyperDash)
{ {
Replay.Frames.Add(new CatchReplayFrame(h.StartTime - timeAvailable, lastPosition)); addFrame(h.StartTime - timeAvailable, lastPosition);
Replay.Frames.Add(new CatchReplayFrame(h.StartTime, h.X)); addFrame(h.StartTime, h.X);
} }
else if (dashRequired) else if (dashRequired)
{ {
@ -81,16 +83,16 @@ namespace osu.Game.Rulesets.Catch.Replays
float midPosition = (float)Interpolation.Lerp(lastPosition, h.X, (float)timeAtDashSpeed / timeAvailable); float midPosition = (float)Interpolation.Lerp(lastPosition, h.X, (float)timeAtDashSpeed / timeAvailable);
//dash movement //dash movement
Replay.Frames.Add(new CatchReplayFrame(h.StartTime - timeAvailable + 1, lastPosition, true)); addFrame(h.StartTime - timeAvailable + 1, lastPosition, true);
Replay.Frames.Add(new CatchReplayFrame(h.StartTime - timeAvailable + timeAtDashSpeed, midPosition)); addFrame(h.StartTime - timeAvailable + timeAtDashSpeed, midPosition);
Replay.Frames.Add(new CatchReplayFrame(h.StartTime, h.X)); addFrame(h.StartTime, h.X);
} }
else else
{ {
double timeBefore = positionChange / movement_speed; double timeBefore = positionChange / movement_speed;
Replay.Frames.Add(new CatchReplayFrame(h.StartTime - timeBefore, lastPosition)); addFrame(h.StartTime - timeBefore, lastPosition);
Replay.Frames.Add(new CatchReplayFrame(h.StartTime, h.X)); addFrame(h.StartTime, h.X);
} }
lastTime = h.StartTime; lastTime = h.StartTime;
@ -122,5 +124,12 @@ namespace osu.Game.Rulesets.Catch.Replays
return Replay; return Replay;
} }
private void addFrame(double time, float? position = null, bool dashing = false)
{
var last = currentFrame;
currentFrame = new CatchReplayFrame(time, position, dashing, last);
Replay.Frames.Add(currentFrame);
}
} }
} }

View File

@ -3,6 +3,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq;
using osu.Framework.Input.StateChanges; using osu.Framework.Input.StateChanges;
using osu.Framework.MathUtils; using osu.Framework.MathUtils;
using osu.Game.Replays; using osu.Game.Replays;
@ -17,7 +18,7 @@ namespace osu.Game.Rulesets.Catch.Replays
{ {
} }
protected override bool IsImportant(CatchReplayFrame frame) => frame.Position > 0; protected override bool IsImportant(CatchReplayFrame frame) => frame.Actions.Any();
protected float? Position protected float? Position
{ {
@ -38,21 +39,11 @@ namespace osu.Game.Rulesets.Catch.Replays
{ {
if (!Position.HasValue) return new List<IInput>(); if (!Position.HasValue) return new List<IInput>();
var actions = new List<CatchAction>();
if (CurrentFrame.Dashing)
actions.Add(CatchAction.Dash);
if (Position.Value > CurrentFrame.Position)
actions.Add(CatchAction.MoveRight);
else if (Position.Value < CurrentFrame.Position)
actions.Add(CatchAction.MoveLeft);
return new List<IInput> return new List<IInput>
{ {
new CatchReplayState new CatchReplayState
{ {
PressedActions = actions, PressedActions = CurrentFrame?.Actions ?? new List<CatchAction>(),
CatcherX = Position.Value CatcherX = Position.Value
}, },
}; };

View File

@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Replays.Legacy; using osu.Game.Replays.Legacy;
using osu.Game.Rulesets.Catch.UI; using osu.Game.Rulesets.Catch.UI;
@ -11,6 +12,8 @@ namespace osu.Game.Rulesets.Catch.Replays
{ {
public class CatchReplayFrame : ReplayFrame, IConvertibleReplayFrame public class CatchReplayFrame : ReplayFrame, IConvertibleReplayFrame
{ {
public List<CatchAction> Actions = new List<CatchAction>();
public float Position; public float Position;
public bool Dashing; public bool Dashing;
@ -18,17 +21,39 @@ namespace osu.Game.Rulesets.Catch.Replays
{ {
} }
public CatchReplayFrame(double time, float? position = null, bool dashing = false) public CatchReplayFrame(double time, float? position = null, bool dashing = false, CatchReplayFrame lastFrame = null)
: base(time) : base(time)
{ {
Position = position ?? -1; Position = position ?? -1;
Dashing = dashing; Dashing = dashing;
if (Dashing)
Actions.Add(CatchAction.Dash);
if (lastFrame != null)
{
if (Position > lastFrame.Position)
Actions.Add(CatchAction.MoveRight);
else if (Position < lastFrame.Position)
Actions.Add(CatchAction.MoveLeft);
}
} }
public void ConvertFrom(LegacyReplayFrame legacyFrame, IBeatmap beatmap) public void ConvertFrom(LegacyReplayFrame currentFrame, IBeatmap beatmap, LegacyReplayFrame lastFrame = null)
{ {
Position = legacyFrame.Position.X / CatchPlayfield.BASE_WIDTH; Position = currentFrame.Position.X / CatchPlayfield.BASE_WIDTH;
Dashing = legacyFrame.ButtonState == ReplayButtonState.Left1; Dashing = currentFrame.ButtonState == ReplayButtonState.Left1;
if (Dashing)
Actions.Add(CatchAction.Dash);
if (lastFrame != null)
{
if (currentFrame.Position.X > lastFrame.Position.X)
Actions.Add(CatchAction.MoveRight);
else if (currentFrame.Position.X < lastFrame.Position.X)
Actions.Add(CatchAction.MoveLeft);
}
} }
} }
} }

View File

@ -0,0 +1,62 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System;
using System.Collections.Generic;
using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Game.Rulesets.Mania.Objects.Drawables;
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
using osu.Game.Rulesets.Mania.UI;
using osu.Game.Rulesets.UI.Scrolling;
using osu.Game.Tests.Visual;
using osuTK;
using osuTK.Graphics;
namespace osu.Game.Rulesets.Mania.Tests
{
[TestFixture]
public class TestSceneHitExplosion : OsuTestScene
{
private ScrollingTestContainer scrolling;
public override IReadOnlyList<Type> RequiredTypes => new[]
{
typeof(DrawableNote),
typeof(DrawableManiaHitObject),
};
protected override void LoadComplete()
{
base.LoadComplete();
Child = scrolling = new ScrollingTestContainer(ScrollingDirection.Down)
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativePositionAxes = Axes.Y,
Y = -0.25f,
Size = new Vector2(Column.COLUMN_WIDTH, NotePiece.NOTE_HEIGHT),
};
int runcount = 0;
AddRepeatStep("explode", () =>
{
runcount++;
if (runcount % 15 > 12)
return;
scrolling.AddRange(new Drawable[]
{
new HitExplosion((runcount / 15) % 2 == 0 ? new Color4(94, 0, 57, 255) : new Color4(6, 84, 0, 255), runcount % 6 != 0)
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
}
});
}, 100);
}
}
}

View File

@ -18,6 +18,8 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
/// </summary> /// </summary>
public class DrawableNote : DrawableManiaHitObject<Note>, IKeyBindingHandler<ManiaAction> public class DrawableNote : DrawableManiaHitObject<Note>, IKeyBindingHandler<ManiaAction>
{ {
public const float CORNER_RADIUS = NotePiece.NOTE_HEIGHT / 2;
private readonly NotePiece headPiece; private readonly NotePiece headPiece;
public DrawableNote(Note hitObject) public DrawableNote(Note hitObject)
@ -38,7 +40,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
EdgeEffect = new EdgeEffectParameters EdgeEffect = new EdgeEffectParameters
{ {
Type = EdgeEffectType.Glow, Type = EdgeEffectType.Glow,
Colour = colour.NewValue.Lighten(1f).Opacity(0.6f), Colour = colour.NewValue.Lighten(1f).Opacity(0.2f),
Radius = 10, Radius = 10,
}; };
}, true); }, true);

View File

@ -18,8 +18,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
/// </summary> /// </summary>
internal class NotePiece : Container, IHasAccentColour internal class NotePiece : Container, IHasAccentColour
{ {
public const float NOTE_HEIGHT = 10; public const float NOTE_HEIGHT = 12;
private const float head_colour_height = 6;
private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>(); private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>();
@ -39,8 +38,8 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
colouredBox = new Box colouredBox = new Box
{ {
RelativeSizeAxes = Axes.X, RelativeSizeAxes = Axes.X,
Height = head_colour_height, Height = NOTE_HEIGHT / 2,
Alpha = 0.2f Alpha = 0.1f
} }
}; };
} }

View File

@ -24,7 +24,7 @@ namespace osu.Game.Rulesets.Mania.Replays
Actions.AddRange(actions); Actions.AddRange(actions);
} }
public void ConvertFrom(LegacyReplayFrame legacyFrame, IBeatmap beatmap) public void ConvertFrom(LegacyReplayFrame legacyFrame, IBeatmap beatmap, LegacyReplayFrame lastFrame = null)
{ {
// We don't need to fully convert, just create the converter // We don't need to fully convert, just create the converter
var converter = new ManiaBeatmapConverter(beatmap); var converter = new ManiaBeatmapConverter(beatmap);

View File

@ -1,4 +1,4 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using System.Linq; using System.Linq;
@ -11,6 +11,8 @@ using osu.Framework.Allocation;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Input.Bindings; using osu.Framework.Input.Bindings;
using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Mania.Objects.Drawables;
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
using osu.Game.Rulesets.Mania.UI.Components; using osu.Game.Rulesets.Mania.UI.Components;
using osu.Game.Rulesets.UI.Scrolling; using osu.Game.Rulesets.UI.Scrolling;
using osuTK; using osuTK;
@ -19,7 +21,7 @@ namespace osu.Game.Rulesets.Mania.UI
{ {
public class Column : ScrollingPlayfield, IKeyBindingHandler<ManiaAction>, IHasAccentColour public class Column : ScrollingPlayfield, IKeyBindingHandler<ManiaAction>, IHasAccentColour
{ {
private const float column_width = 45; public const float COLUMN_WIDTH = 80;
private const float special_column_width = 70; private const float special_column_width = 70;
/// <summary> /// <summary>
@ -41,10 +43,7 @@ namespace osu.Game.Rulesets.Mania.UI
Index = index; Index = index;
RelativeSizeAxes = Axes.Y; RelativeSizeAxes = Axes.Y;
Width = column_width; Width = COLUMN_WIDTH;
Masking = true;
CornerRadius = 5;
background = new ColumnBackground { RelativeSizeAxes = Axes.Both }; background = new ColumnBackground { RelativeSizeAxes = Axes.Both };
@ -67,7 +66,7 @@ namespace osu.Game.Rulesets.Mania.UI
explosionContainer = new Container explosionContainer = new Container
{ {
Name = "Hit explosions", Name = "Hit explosions",
RelativeSizeAxes = Axes.Both RelativeSizeAxes = Axes.Both,
} }
} }
}, },
@ -90,6 +89,12 @@ namespace osu.Game.Rulesets.Mania.UI
Bottom = dir.NewValue == ScrollingDirection.Down ? ManiaStage.HIT_TARGET_POSITION : 0, Bottom = dir.NewValue == ScrollingDirection.Down ? ManiaStage.HIT_TARGET_POSITION : 0,
}; };
explosionContainer.Padding = new MarginPadding
{
Top = dir.NewValue == ScrollingDirection.Up ? NotePiece.NOTE_HEIGHT / 2 : 0,
Bottom = dir.NewValue == ScrollingDirection.Down ? NotePiece.NOTE_HEIGHT / 2 : 0
};
keyArea.Anchor = keyArea.Origin = dir.NewValue == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft; keyArea.Anchor = keyArea.Origin = dir.NewValue == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft;
}, true); }, true);
} }
@ -108,7 +113,7 @@ namespace osu.Game.Rulesets.Mania.UI
isSpecial = value; isSpecial = value;
Width = isSpecial ? special_column_width : column_width; Width = isSpecial ? special_column_width : COLUMN_WIDTH;
} }
} }
@ -163,9 +168,10 @@ namespace osu.Game.Rulesets.Mania.UI
if (!result.IsHit || !judgedObject.DisplayResult || !DisplayJudgements.Value) if (!result.IsHit || !judgedObject.DisplayResult || !DisplayJudgements.Value)
return; return;
explosionContainer.Add(new HitExplosion(judgedObject) explosionContainer.Add(new HitExplosion(judgedObject.AccentColour.Value, judgedObject is DrawableHoldNoteTick)
{ {
Anchor = Direction.Value == ScrollingDirection.Up ? Anchor.TopCentre : Anchor.BottomCentre Anchor = Direction.Value == ScrollingDirection.Up ? Anchor.TopCentre : Anchor.BottomCentre,
Origin = Anchor.Centre
}); });
} }

View File

@ -35,7 +35,6 @@ namespace osu.Game.Rulesets.Mania.UI.Components
{ {
Name = "Background", Name = "Background",
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Alpha = 0.3f
}, },
backgroundOverlay = new Box backgroundOverlay = new Box
{ {
@ -82,7 +81,7 @@ namespace osu.Game.Rulesets.Mania.UI.Components
if (!IsLoaded) if (!IsLoaded)
return; return;
background.Colour = AccentColour; background.Colour = AccentColour.Darken(5);
var brightPoint = AccentColour.Opacity(0.6f); var brightPoint = AccentColour.Opacity(0.6f);
var dimPoint = AccentColour.Opacity(0); var dimPoint = AccentColour.Opacity(0);

View File

@ -9,6 +9,7 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI;
using osu.Game.Rulesets.UI.Scrolling; using osu.Game.Rulesets.UI.Scrolling;
using osuTK.Graphics; using osuTK.Graphics;
@ -17,7 +18,6 @@ namespace osu.Game.Rulesets.Mania.UI.Components
{ {
public class ColumnHitObjectArea : CompositeDrawable, IHasAccentColour public class ColumnHitObjectArea : CompositeDrawable, IHasAccentColour
{ {
private const float hit_target_height = 10;
private const float hit_target_bar_height = 2; private const float hit_target_bar_height = 2;
private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>(); private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>();
@ -32,7 +32,8 @@ namespace osu.Game.Rulesets.Mania.UI.Components
hitTargetBar = new Box hitTargetBar = new Box
{ {
RelativeSizeAxes = Axes.X, RelativeSizeAxes = Axes.X,
Height = hit_target_height, Height = NotePiece.NOTE_HEIGHT,
Alpha = 0.6f,
Colour = Color4.Black Colour = Color4.Black
}, },
hitTargetLine = new Container hitTargetLine = new Container

View File

@ -1,16 +1,14 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using osuTK.Graphics; using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes;
using osu.Framework.MathUtils; using osu.Framework.MathUtils;
using osu.Game.Rulesets.Mania.Objects.Drawables;
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces; using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
using osu.Game.Rulesets.Objects.Drawables;
using osuTK; using osuTK;
using osuTK.Graphics;
namespace osu.Game.Rulesets.Mania.UI namespace osu.Game.Rulesets.Mania.UI
{ {
@ -18,51 +16,112 @@ namespace osu.Game.Rulesets.Mania.UI
{ {
public override bool RemoveWhenNotAlive => true; public override bool RemoveWhenNotAlive => true;
private readonly CircularContainer circle; private readonly CircularContainer largeFaint;
private readonly CircularContainer mainGlow1;
public HitExplosion(DrawableHitObject judgedObject) public HitExplosion(Color4 objectColour, bool isSmall = false)
{ {
bool isTick = judgedObject is DrawableHoldNoteTick;
Origin = Anchor.Centre;
RelativeSizeAxes = Axes.X; RelativeSizeAxes = Axes.X;
Y = NotePiece.NOTE_HEIGHT / 2;
Height = NotePiece.NOTE_HEIGHT; Height = NotePiece.NOTE_HEIGHT;
// scale roughly in-line with visual appearance of notes // scale roughly in-line with visual appearance of notes
Scale = new Vector2(isTick ? 0.4f : 0.8f); Scale = new Vector2(1f, 0.6f);
InternalChild = circle = new CircularContainer if (isSmall)
Scale *= 0.5f;
const float angle_variangle = 15; // should be less than 45
const float roundness = 80;
const float initial_height = 10;
var colour = Interpolation.ValueAt(0.4f, objectColour, Color4.White, 0, 1);
InternalChildren = new Drawable[]
{ {
Anchor = Anchor.Centre, largeFaint = new CircularContainer
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Masking = true,
// we want our size to be very small so the glow dominates it.
Size = new Vector2(0.1f),
EdgeEffect = new EdgeEffectParameters
{ {
Type = EdgeEffectType.Glow, Anchor = Anchor.Centre,
Colour = Interpolation.ValueAt(0.1f, judgedObject.AccentColour.Value, Color4.White, 0, 1), Origin = Anchor.Centre,
Radius = 100,
},
Child = new Box
{
Alpha = 0,
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
AlwaysPresent = true Masking = true,
// we want our size to be very small so the glow dominates it.
Size = new Vector2(0.8f),
Blending = BlendingParameters.Additive,
EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Glow,
Colour = Interpolation.ValueAt(0.1f, objectColour, Color4.White, 0, 1).Opacity(0.3f),
Roundness = 160,
Radius = 200,
},
},
mainGlow1 = new CircularContainer
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Masking = true,
Blending = BlendingParameters.Additive,
EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Glow,
Colour = Interpolation.ValueAt(0.6f, objectColour, Color4.White, 0, 1),
Roundness = 20,
Radius = 50,
},
},
new CircularContainer
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Masking = true,
Size = new Vector2(0.01f, initial_height),
Blending = BlendingParameters.Additive,
Rotation = RNG.NextSingle(-angle_variangle, angle_variangle),
EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Glow,
Colour = colour,
Roundness = roundness,
Radius = 40,
},
},
new CircularContainer
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Masking = true,
Size = new Vector2(0.01f, initial_height),
Blending = BlendingParameters.Additive,
Rotation = RNG.NextSingle(-angle_variangle, angle_variangle),
EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Glow,
Colour = colour,
Roundness = roundness,
Radius = 40,
},
} }
}; };
} }
protected override void LoadComplete() protected override void LoadComplete()
{ {
const double duration = 200;
base.LoadComplete(); base.LoadComplete();
circle.ResizeTo(circle.Size * new Vector2(4, 20), 1000, Easing.OutQuint); largeFaint
this.FadeIn(16).Then().FadeOut(500, Easing.OutQuint); .ResizeTo(largeFaint.Size * new Vector2(5, 1), duration, Easing.OutQuint)
.FadeOut(duration * 2);
mainGlow1.ScaleTo(1.4f, duration, Easing.OutQuint);
this.FadeOut(duration, Easing.Out);
Expire(true); Expire(true);
} }
} }

View File

@ -26,11 +26,11 @@ namespace osu.Game.Rulesets.Osu.Replays
Actions.AddRange(actions); Actions.AddRange(actions);
} }
public void ConvertFrom(LegacyReplayFrame legacyFrame, IBeatmap beatmap) public void ConvertFrom(LegacyReplayFrame currentFrame, IBeatmap beatmap, LegacyReplayFrame lastFrame = null)
{ {
Position = legacyFrame.Position; Position = currentFrame.Position;
if (legacyFrame.MouseLeft) Actions.Add(OsuAction.LeftButton); if (currentFrame.MouseLeft) Actions.Add(OsuAction.LeftButton);
if (legacyFrame.MouseRight) Actions.Add(OsuAction.RightButton); if (currentFrame.MouseRight) Actions.Add(OsuAction.RightButton);
} }
} }
} }

View File

@ -23,12 +23,12 @@ namespace osu.Game.Rulesets.Taiko.Replays
Actions.AddRange(actions); Actions.AddRange(actions);
} }
public void ConvertFrom(LegacyReplayFrame legacyFrame, IBeatmap beatmap) public void ConvertFrom(LegacyReplayFrame currentFrame, IBeatmap beatmap, LegacyReplayFrame lastFrame = null)
{ {
if (legacyFrame.MouseRight1) Actions.Add(TaikoAction.LeftRim); if (currentFrame.MouseRight1) Actions.Add(TaikoAction.LeftRim);
if (legacyFrame.MouseRight2) Actions.Add(TaikoAction.RightRim); if (currentFrame.MouseRight2) Actions.Add(TaikoAction.RightRim);
if (legacyFrame.MouseLeft1) Actions.Add(TaikoAction.LeftCentre); if (currentFrame.MouseLeft1) Actions.Add(TaikoAction.LeftCentre);
if (legacyFrame.MouseLeft2) Actions.Add(TaikoAction.RightCentre); if (currentFrame.MouseLeft2) Actions.Add(TaikoAction.RightCentre);
} }
} }
} }

View File

@ -14,8 +14,9 @@ namespace osu.Game.Rulesets.Replays.Types
/// <summary> /// <summary>
/// Populates this <see cref="ReplayFrame"/> using values from a <see cref="LegacyReplayFrame"/>. /// Populates this <see cref="ReplayFrame"/> using values from a <see cref="LegacyReplayFrame"/>.
/// </summary> /// </summary>
/// <param name="legacyFrame">The <see cref="LegacyReplayFrame"/> to extract values from.</param> /// <param name="currentFrame">The <see cref="LegacyReplayFrame"/> to extract values from.</param>
/// <param name="beatmap">The beatmap.</param> /// <param name="beatmap">The beatmap.</param>
void ConvertFrom(LegacyReplayFrame legacyFrame, IBeatmap beatmap); /// <param name="lastFrame">The last <see cref="LegacyReplayFrame"/>, used to fill in missing delta information. May be null.</param>
void ConvertFrom(LegacyReplayFrame currentFrame, IBeatmap beatmap, LegacyReplayFrame lastFrame = null);
} }
} }

View File

@ -218,6 +218,7 @@ namespace osu.Game.Scoring.Legacy
private void readLegacyReplay(Replay replay, StreamReader reader) private void readLegacyReplay(Replay replay, StreamReader reader)
{ {
float lastTime = 0; float lastTime = 0;
LegacyReplayFrame currentFrame = null;
foreach (var l in reader.ReadToEnd().Split(',')) foreach (var l in reader.ReadToEnd().Split(','))
{ {
@ -240,23 +241,27 @@ namespace osu.Game.Scoring.Legacy
if (diff < 0) if (diff < 0)
continue; continue;
replay.Frames.Add(convertFrame(new LegacyReplayFrame(lastTime, var lastFrame = currentFrame;
currentFrame = new LegacyReplayFrame(lastTime,
Parsing.ParseFloat(split[1], Parsing.MAX_COORDINATE_VALUE), Parsing.ParseFloat(split[1], Parsing.MAX_COORDINATE_VALUE),
Parsing.ParseFloat(split[2], Parsing.MAX_COORDINATE_VALUE), Parsing.ParseFloat(split[2], Parsing.MAX_COORDINATE_VALUE),
(ReplayButtonState)Parsing.ParseInt(split[3])))); (ReplayButtonState)Parsing.ParseInt(split[3]));
replay.Frames.Add(convertFrame(currentFrame, lastFrame));
} }
} }
private ReplayFrame convertFrame(LegacyReplayFrame legacyFrame) private ReplayFrame convertFrame(LegacyReplayFrame currentFrame, LegacyReplayFrame lastFrame)
{ {
var convertible = currentRuleset.CreateConvertibleReplayFrame(); var convertible = currentRuleset.CreateConvertibleReplayFrame();
if (convertible == null) if (convertible == null)
throw new InvalidOperationException($"Legacy replay cannot be converted for the ruleset: {currentRuleset.Description}"); throw new InvalidOperationException($"Legacy replay cannot be converted for the ruleset: {currentRuleset.Description}");
convertible.ConvertFrom(legacyFrame, currentBeatmap); convertible.ConvertFrom(currentFrame, currentBeatmap, lastFrame);
var frame = (ReplayFrame)convertible; var frame = (ReplayFrame)convertible;
frame.Time = legacyFrame.Time; frame.Time = currentFrame.Time;
return frame; return frame;
} }