diff --git a/osu.Desktop.VisualTests/Tests/TestCaseReplay.cs b/osu.Desktop.VisualTests/Tests/TestCaseReplay.cs index c5ca3b47c4..fe69469db7 100644 --- a/osu.Desktop.VisualTests/Tests/TestCaseReplay.cs +++ b/osu.Desktop.VisualTests/Tests/TestCaseReplay.cs @@ -4,12 +4,17 @@ using System; using System.Collections.Generic; using System.IO; +using System.Text; using osu.Framework.Allocation; using osu.Framework.Screens.Testing; using osu.Game.Beatmaps; using osu.Game.Beatmaps.Formats; using OpenTK; using osu.Framework.Graphics.Sprites; +using osu.Framework.Input; +using osu.Framework.Input.Handlers; +using osu.Framework.MathUtils; +using osu.Framework.Platform; using osu.Game.Beatmaps.IO; using osu.Game.Database; using osu.Game.Input.Handlers; @@ -19,62 +24,345 @@ using osu.Game.Modes.Objects; using osu.Game.Modes.Osu.Objects; using osu.Game.Screens.Play; using OpenTK.Graphics; +using OpenTK.Input; using SharpCompress.Archives.SevenZip; using SharpCompress.Readers; +using KeyboardState = osu.Framework.Input.KeyboardState; +using MouseState = osu.Framework.Input.MouseState; namespace osu.Desktop.VisualTests.Tests { + public class ScoreDatabase + { + private readonly Storage storage; + + private const string replay_folder = @"replays"; + + public ScoreDatabase(Storage storage) + { + this.storage = storage; + } + + public Score ReadReplayFile(string replayFilename) + { + Score score; + + using (Stream s = storage.GetStream(Path.Combine(replay_folder, replayFilename))) + using (SerializationReader sr = new SerializationReader(s)) + { + var ruleset = Ruleset.GetRuleset((PlayMode)sr.ReadByte()); + var processor = ruleset.CreateScoreProcessor(); + + score = processor.GetScore(); + + + + /* score.Pass = true;*/ + var version = sr.ReadInt32(); + /* score.FileChecksum = */ sr.ReadString(); + /* score.PlayerName = */ sr.ReadString(); + /* var localScoreChecksum = */ sr.ReadString(); + /* score.Count300 = */ sr.ReadUInt16(); + /* score.Count100 = */ sr.ReadUInt16(); + /* score.Count50 = */ sr.ReadUInt16(); + /* score.CountGeki = */ sr.ReadUInt16(); + /* score.CountKatu = */ sr.ReadUInt16(); + /* score.CountMiss = */ sr.ReadUInt16(); + score.TotalScore = sr.ReadInt32(); + score.MaxCombo = sr.ReadUInt16(); + /* score.Perfect = */ sr.ReadBoolean(); + /* score.EnabledMods = (Mods)*/ sr.ReadInt32(); + /* score.HpGraphString = */ sr.ReadString(); + /* score.Date = */ sr.ReadDateTime(); + + var compressedReplay = sr.ReadByteArray(); + + if (version >= 20140721) + /*OnlineId =*/ sr.ReadInt64(); + else if (version >= 20121008) + /*OnlineId =*/ sr.ReadInt32(); + + //new ASCIIEncoding().GetString(SevenZipHelper.Decompress(ReplayCompressed))); + + score.Replay = new LegacyReplay(); + + //float lastTime = 0; + //foreach (var l in File.ReadAllText(@"C:\Users\Dean\Desktop\2157025197").Split(',')) + //{ + // var split = l.Split('|'); + + // if (split.Length < 4 || float.Parse(split[0]) < 0) continue; + + // lastTime += float.Parse(split[0]); + + // list.Add(new LegacyReplay.LegacyReplayInputHandler.LegacyReplayFrame( + // lastTime, + // float.Parse(split[1]), + // 384 - float.Parse(split[2]), + // (LegacyReplay.LegacyReplayInputHandler.LegacyButtonState)int.Parse(split[3]) + // )); + //} + } + + return score; + } + } + class TestCaseReplay : TestCasePlayer { private WorkingBeatmap beatmap; - private LegacyReplayInputHandler replay; + private InputHandler replay; + + private Func getReplayStream; + private ScoreDatabase scoreDatabase; public override string Name => @"Replay"; public override string Description => @"Testing replay playback."; - public override void Reset() + [BackgroundDependencyLoader] + private void load(Storage storage) { - base.Reset(); - - var list = new List(); - - float lastTime = 0; - foreach (var l in File.ReadAllText(@"C:\Users\Dean\Desktop\2157025197").Split(',')) - { - var split = l.Split('|'); - - if (split.Length < 4 || float.Parse(split[0]) < 0) continue; - - lastTime += float.Parse(split[0]); - - list.Add(new LegacyReplayInputHandler.LegacyReplayFrame( - lastTime, - float.Parse(split[1]), - 384 - float.Parse(split[2]), - (LegacyReplayInputHandler.LegacyButtonState)int.Parse(split[3]) - )); - } - - - replay = new LegacyReplayInputHandler(list); - - //var data = File.ReadAllBytes(@"C:\Users\Dean\.osu\Replays\Tao - O2i3 - Ooi [Game Edit] [Advanced] (2016-08-08) Osu.osr"); - //using (MemoryStream dataStream = new MemoryStream(data)) - //{ - // var obj = SerializationReader.DynamicDeserializer.Deserialize(dataStream); - - - // Console.WriteLine(obj); - //} + scoreDatabase = new ScoreDatabase(storage); } protected override Player CreatePlayer(WorkingBeatmap beatmap) { var player = base.CreatePlayer(beatmap); - player.ReplayInputHandler = replay; + player.ReplayInputHandler = scoreDatabase.ReadReplayFile(@"Tao - O2i3 - Ooi [Game Edit] [Advanced] (2016-08-08) Osu.osr").Replay.GetInputHandler(); return player; } } + + public class LegacyReplay : Replay + { + private new List frames = new List(); + + public override ReplayInputHandler GetInputHandler() => new LegacyReplayInputHandler(frames); + + /// + /// The ReplayHandler will take a replay and handle the propagation of updates to the input stack. + /// It handles logic of any frames which *must* be executed. + /// + public class LegacyReplayInputHandler : ReplayInputHandler + { + private readonly List replayContent; + int currentFrameIndex; + + public LegacyReplayFrame CurrentFrame => !hasFrames ? null : replayContent[currentFrameIndex]; + public LegacyReplayFrame NextFrame => !hasFrames ? null : replayContent[MathHelper.Clamp(currentDirection > 0 ? currentFrameIndex + 1 : currentFrameIndex - 1, 0, replayContent.Count - 1)]; + + public LegacyReplayInputHandler(List replayContent) + { + this.replayContent = replayContent; + } + + private bool nextFrame() + { + int newFrame = MathHelper.Clamp(currentFrameIndex + (currentDirection > 0 ? 1 : -1), 0, replayContent.Count - 1); + + //ensure we aren't at an extent. + if (newFrame == currentFrameIndex) return false; + + currentFrameIndex = newFrame; + return true; + } + + public void SetPosition(Vector2 pos) + { + } + + private Vector2? position + { + get + { + if (!hasFrames) + return null; + + if (AtLastFrame) + return CurrentFrame.Position; + + return Interpolation.ValueAt(currentTime, CurrentFrame.Position, NextFrame.Position, CurrentFrame.Time, NextFrame.Time); + } + } + + public override List GetPendingStates() + { + return new List + { + new InputState + { + Mouse = new ReplayMouseState( + ToScreenSpace(position ?? Vector2.Zero), + new List + { + new MouseState.ButtonState(MouseButton.Left) + { + State = CurrentFrame?.MouseLeft ?? false + }, + new MouseState.ButtonState(MouseButton.Right) + { + State = CurrentFrame?.MouseRight ?? false + }, + } + ), + Keyboard = new ReplayKeyboardState(new List()) + } + }; + } + + public bool AtLastFrame => currentFrameIndex == replayContent.Count - 1; + public bool AtFirstFrame => currentFrameIndex == 0; + + public Vector2 Size => new Vector2(512, 384); + + private const double sixty_frame_time = 1000 / 60; + + double currentTime; + int currentDirection; + + /// + /// When set, we will ensure frames executed by nested drawables are frame-accurate to replay data. + /// Disabling this can make replay playback smoother (useful for autoplay, currently). + /// + public bool FrameAccuratePlayback = true; + + private bool hasFrames => replayContent.Count > 0; + + bool inImportantSection => + FrameAccuratePlayback && + //a button is in a pressed state + (currentDirection > 0 ? CurrentFrame : NextFrame)?.ButtonState > LegacyButtonState.None && + //the next frame is within an allowable time span + Math.Abs(currentTime - NextFrame?.Time ?? 0) <= sixty_frame_time * 1.2; + + /// + /// Update the current frame based on an incoming time value. + /// There are cases where we return a "must-use" time value that is different from the input. + /// This is to ensure accurate playback of replay data. + /// + /// The time which we should use for finding the current frame. + /// The usable time value. If null, we shouldn't be running components reliant on this data. + public override double? SetFrameFromTime(double time) + { + currentDirection = time.CompareTo(currentTime); + if (currentDirection == 0) currentDirection = 1; + + if (hasFrames) + { + //if we changed frames, we want to execute once *exactly* on the frame's time. + if (currentDirection == time.CompareTo(NextFrame.Time) && nextFrame()) + return currentTime = CurrentFrame.Time; + + //if we didn't change frames, we need to ensure we are allowed to run frames in between, else return null. + if (inImportantSection) + return null; + } + + return currentTime = time; + } + + private class ReplayMouseState : MouseState + { + public ReplayMouseState(Vector2 position, List list) + { + Position = position; + ButtonStates = list; + } + } + + private class ReplayKeyboardState : KeyboardState + { + public ReplayKeyboardState(List keys) + { + Keys = keys; + } + } + } + + [Flags] + public enum LegacyButtonState + { + None = 0, + Left1 = 1, + Right1 = 2, + Left2 = 4, + Right2 = 8, + Smoke = 16 + } + + public class LegacyReplayFrame + { + public Vector2 Position => new Vector2(MouseX, MouseY); + + public float MouseX; + public float MouseY; + public bool MouseLeft; + public bool MouseRight; + public bool MouseLeft1; + public bool MouseRight1; + public bool MouseLeft2; + public bool MouseRight2; + public LegacyButtonState ButtonState; + public double Time; + + public LegacyReplayFrame(double time, float posX, float posY, LegacyButtonState buttonState) + { + MouseX = posX; + MouseY = posY; + ButtonState = buttonState; + SetButtonStates(buttonState); + Time = time; + } + + public void SetButtonStates(LegacyButtonState buttonState) + { + ButtonState = buttonState; + MouseLeft = (buttonState & (LegacyButtonState.Left1 | LegacyButtonState.Left2)) > 0; + MouseLeft1 = (buttonState & LegacyButtonState.Left1) > 0; + MouseLeft2 = (buttonState & LegacyButtonState.Left2) > 0; + MouseRight = (buttonState & (LegacyButtonState.Right1 | LegacyButtonState.Right2)) > 0; + MouseRight1 = (buttonState & LegacyButtonState.Right1) > 0; + MouseRight2 = (buttonState & LegacyButtonState.Right2) > 0; + } + + public LegacyReplayFrame(Stream s) : this(new SerializationReader(s)) + { + } + + public LegacyReplayFrame(SerializationReader sr) + { + ButtonState = (LegacyButtonState)sr.ReadByte(); + SetButtonStates(ButtonState); + + byte bt = sr.ReadByte(); + if (bt > 0)//Handle Pre-Taiko compatible replays. + SetButtonStates(LegacyButtonState.Right1); + + MouseX = sr.ReadSingle(); + MouseY = sr.ReadSingle(); + Time = sr.ReadInt32(); + } + + public void ReadFromStream(SerializationReader sr) + { + throw new System.NotImplementedException(); + } + + public void WriteToStream(SerializationWriter sw) + { + sw.Write((byte)ButtonState); + sw.Write((byte)0); + sw.Write(MouseX); + sw.Write(MouseY); + sw.Write(Time); + } + + public override string ToString() + { + return $"{Time}\t({MouseX},{MouseY})\t{MouseLeft}\t{MouseRight}\t{MouseLeft1}\t{MouseRight1}\t{MouseLeft2}\t{MouseRight2}\t{ButtonState}"; + } + } + } } diff --git a/osu.Game.Modes.Osu/OsuScoreProcessor.cs b/osu.Game.Modes.Osu/OsuScoreProcessor.cs index 9493259558..269047dd19 100644 --- a/osu.Game.Modes.Osu/OsuScoreProcessor.cs +++ b/osu.Game.Modes.Osu/OsuScoreProcessor.cs @@ -8,7 +8,7 @@ namespace osu.Game.Modes.Osu { class OsuScoreProcessor : ScoreProcessor { - public OsuScoreProcessor(int hitObjectCount) + public OsuScoreProcessor(int hitObjectCount = 0) : base(hitObjectCount) { Health.Value = 1; diff --git a/osu.Game/Input/Handlers/LegacyReplayInputHandler.cs b/osu.Game/Input/Handlers/LegacyReplayInputHandler.cs deleted file mode 100644 index 03fa92515b..0000000000 --- a/osu.Game/Input/Handlers/LegacyReplayInputHandler.cs +++ /dev/null @@ -1,244 +0,0 @@ -// Copyright (c) 2007-2017 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using System; -using System.Collections.Generic; -using System.IO; -using osu.Framework.Input.Handlers; -using osu.Framework.MathUtils; -using osu.Framework.Platform; -using OpenTK; -using osu.Framework.Input; -using osu.Game.IO.Legacy; -using OpenTK.Input; -using KeyboardState = osu.Framework.Input.KeyboardState; -using MouseState = osu.Framework.Input.MouseState; - -namespace osu.Game.Input.Handlers -{ - /// - /// The ReplayHandler will take a replay and handle the propagation of updates to the input stack. - /// It handles logic of any frames which *must* be executed. - /// - public class LegacyReplayInputHandler : InputHandler - { - public Func ToScreenSpace { private get; set; } - - private readonly List replayContent; - int currentFrameIndex; - - public LegacyReplayFrame CurrentFrame => !hasFrames ? null : replayContent[currentFrameIndex]; - public LegacyReplayFrame NextFrame => !hasFrames ? null : replayContent[MathHelper.Clamp(currentDirection > 0 ? currentFrameIndex + 1 : currentFrameIndex - 1, 0, replayContent.Count - 1)]; - - public override bool Initialize(GameHost host) => true; - - public override bool IsActive => true; - - public override int Priority => 0; - - public LegacyReplayInputHandler(List replayContent) - { - this.replayContent = replayContent; - } - - private bool nextFrame() - { - int newFrame = MathHelper.Clamp(currentFrameIndex + (currentDirection > 0 ? 1 : -1), 0, replayContent.Count - 1); - - //ensure we aren't at an extent. - if (newFrame == currentFrameIndex) return false; - - currentFrameIndex = newFrame; - return true; - } - - public void SetPosition(Vector2 pos) - { - } - - private Vector2? position - { - get - { - if (!hasFrames) - return null; - - if (AtLastFrame) - return CurrentFrame.Position; - - return Interpolation.ValueAt(currentTime, CurrentFrame.Position, NextFrame.Position, CurrentFrame.Time, NextFrame.Time); - } - } - - public override List GetPendingStates() - { - return new List - { - new InputState - { - Mouse = new ReplayMouseState( - ToScreenSpace(position ?? Vector2.Zero), - new List - { - new MouseState.ButtonState(MouseButton.Left) { State = CurrentFrame?.MouseLeft ?? false }, - new MouseState.ButtonState(MouseButton.Right) { State = CurrentFrame?.MouseRight ?? false }, - } - ), - Keyboard = new ReplayKeyboardState(new List()) - } - }; - } - - public bool AtLastFrame => currentFrameIndex == replayContent.Count - 1; - public bool AtFirstFrame => currentFrameIndex == 0; - - public Vector2 Size => new Vector2(512, 384); - - private const double sixty_frame_time = 1000 / 60; - - double currentTime; - int currentDirection; - - /// - /// When set, we will ensure frames executed by nested drawables are frame-accurate to replay data. - /// Disabling this can make replay playback smoother (useful for autoplay, currently). - /// - public bool FrameAccuratePlayback = true; - - private bool hasFrames => replayContent.Count > 0; - - bool inImportantSection => - FrameAccuratePlayback && - //a button is in a pressed state - (currentDirection > 0 ? CurrentFrame : NextFrame)?.ButtonState > LegacyButtonState.None && - //the next frame is within an allowable time span - Math.Abs(currentTime - NextFrame?.Time ?? 0) <= sixty_frame_time * 1.2; - - /// - /// Update the current frame based on an incoming time value. - /// There are cases where we return a "must-use" time value that is different from the input. - /// This is to ensure accurate playback of replay data. - /// - /// The time which we should use for finding the current frame. - /// The usable time value. If null, we shouldn't be running components reliant on this data. - public double? SetFrameFromTime(double time) - { - currentDirection = time.CompareTo(currentTime); - if (currentDirection == 0) currentDirection = 1; - - if (hasFrames) - { - //if we changed frames, we want to execute once *exactly* on the frame's time. - if (currentDirection == time.CompareTo(NextFrame.Time) && nextFrame()) - return currentTime = CurrentFrame.Time; - - //if we didn't change frames, we need to ensure we are allowed to run frames in between, else return null. - if (inImportantSection) - return null; - } - - return currentTime = time; - } - - private class ReplayMouseState : MouseState - { - public ReplayMouseState(Vector2 position, List list) - { - Position = position; - ButtonStates = list; - } - } - - private class ReplayKeyboardState : KeyboardState - { - public ReplayKeyboardState(List keys) - { - Keys = keys; - } - } - - [Flags] - public enum LegacyButtonState - { - None = 0, - Left1 = 1, - Right1 = 2, - Left2 = 4, - Right2 = 8, - Smoke = 16 - } - - public class LegacyReplayFrame - { - public Vector2 Position => new Vector2(MouseX, MouseY); - - public float MouseX; - public float MouseY; - public bool MouseLeft; - public bool MouseRight; - public bool MouseLeft1; - public bool MouseRight1; - public bool MouseLeft2; - public bool MouseRight2; - public LegacyButtonState ButtonState; - public double Time; - - public LegacyReplayFrame(double time, float posX, float posY, LegacyButtonState buttonState) - { - MouseX = posX; - MouseY = posY; - ButtonState = buttonState; - SetButtonStates(buttonState); - Time = time; - } - - public void SetButtonStates(LegacyButtonState buttonState) - { - ButtonState = buttonState; - MouseLeft = (buttonState & (LegacyButtonState.Left1 | LegacyButtonState.Left2)) > 0; - MouseLeft1 = (buttonState & LegacyButtonState.Left1) > 0; - MouseLeft2 = (buttonState & LegacyButtonState.Left2) > 0; - MouseRight = (buttonState & (LegacyButtonState.Right1 | LegacyButtonState.Right2)) > 0; - MouseRight1 = (buttonState & LegacyButtonState.Right1) > 0; - MouseRight2 = (buttonState & LegacyButtonState.Right2) > 0; - } - - public LegacyReplayFrame(Stream s) : this(new SerializationReader(s)) - { - } - - public LegacyReplayFrame(SerializationReader sr) - { - ButtonState = (LegacyButtonState)sr.ReadByte(); - SetButtonStates(ButtonState); - - byte bt = sr.ReadByte(); - if (bt > 0)//Handle Pre-Taiko compatible replays. - SetButtonStates(LegacyButtonState.Right1); - - MouseX = sr.ReadSingle(); - MouseY = sr.ReadSingle(); - Time = sr.ReadInt32(); - } - - public void ReadFromStream(SerializationReader sr) - { - throw new System.NotImplementedException(); - } - - public void WriteToStream(SerializationWriter sw) - { - sw.Write((byte)ButtonState); - sw.Write((byte)0); - sw.Write(MouseX); - sw.Write(MouseY); - sw.Write(Time); - } - - public override string ToString() - { - return $"{Time}\t({MouseX},{MouseY})\t{MouseLeft}\t{MouseRight}\t{MouseLeft1}\t{MouseRight1}\t{MouseLeft2}\t{MouseRight2}\t{ButtonState}"; - } - } - } -} \ No newline at end of file diff --git a/osu.Game/Input/Handlers/ReplayInputHandler.cs b/osu.Game/Input/Handlers/ReplayInputHandler.cs new file mode 100644 index 0000000000..d933c68099 --- /dev/null +++ b/osu.Game/Input/Handlers/ReplayInputHandler.cs @@ -0,0 +1,41 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using System.Collections.Generic; +using System.IO; +using osu.Framework.Input.Handlers; +using osu.Framework.MathUtils; +using osu.Framework.Platform; +using OpenTK; +using osu.Framework.Input; +using osu.Game.IO.Legacy; +using OpenTK.Input; +using KeyboardState = osu.Framework.Input.KeyboardState; +using MouseState = osu.Framework.Input.MouseState; + +namespace osu.Game.Input.Handlers +{ + public abstract class ReplayInputHandler : InputHandler + { + /// + /// A function provided to convert replay coordinates from gamefield to screen space. + /// + public Func ToScreenSpace { protected get; set; } + + /// + /// Update the current frame based on an incoming time value. + /// There are cases where we return a "must-use" time value that is different from the input. + /// This is to ensure accurate playback of replay data. + /// + /// The time which we should use for finding the current frame. + /// The usable time value. If null, we shouldn't be running components reliant on this data. + public abstract double? SetFrameFromTime(double time); + + public override bool Initialize(GameHost host) => true; + + public override bool IsActive => true; + + public override int Priority => 0; + } +} \ No newline at end of file diff --git a/osu.Game/Modes/Ruleset.cs b/osu.Game/Modes/Ruleset.cs index 2b665dff17..30ac8e31ab 100644 --- a/osu.Game/Modes/Ruleset.cs +++ b/osu.Game/Modes/Ruleset.cs @@ -30,7 +30,7 @@ namespace osu.Game.Modes public abstract IEnumerable GetModsFor(ModType type); - public abstract ScoreProcessor CreateScoreProcessor(int hitObjectCount); + public abstract ScoreProcessor CreateScoreProcessor(int hitObjectCount = 0); public abstract HitRenderer CreateHitRendererWith(Beatmap beatmap, InputManager input = null); diff --git a/osu.Game/Modes/Score.cs b/osu.Game/Modes/Score.cs index 8da09cb974..a1324f614f 100644 --- a/osu.Game/Modes/Score.cs +++ b/osu.Game/Modes/Score.cs @@ -1,6 +1,9 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using osu.Framework.Input.Handlers; +using osu.Game.Input.Handlers; + namespace osu.Game.Modes { public class Score @@ -10,5 +13,12 @@ namespace osu.Game.Modes public double Combo { get; set; } public double MaxCombo { get; set; } public double Health { get; set; } + + public Replay Replay; + } + + public class Replay + { + public virtual ReplayInputHandler GetInputHandler() => null; } } diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 0aab0f9de7..e3651f0869 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -26,6 +26,7 @@ using osu.Framework.Graphics.Transforms; using osu.Framework.Input; using osu.Framework.Logging; using osu.Framework.Input; +using osu.Framework.Input.Handlers; using osu.Game.Graphics.Cursor; using osu.Game.Input.Handlers; @@ -339,7 +340,7 @@ namespace osu.Game.Screens.Play private Bindable mouseWheelDisabled; - public LegacyReplayInputHandler ReplayInputHandler; + public ReplayInputHandler ReplayInputHandler; protected override bool OnWheel(InputState state) => mouseWheelDisabled.Value && !isPaused; } diff --git a/osu.Game/Screens/Play/PlayerInputManager.cs b/osu.Game/Screens/Play/PlayerInputManager.cs index 084c96a82f..ac98b6533b 100644 --- a/osu.Game/Screens/Play/PlayerInputManager.cs +++ b/osu.Game/Screens/Play/PlayerInputManager.cs @@ -6,6 +6,7 @@ using osu.Framework.Configuration; using osu.Framework.Input; using osu.Game.Configuration; using System.Linq; +using osu.Framework.Input.Handlers; using osu.Framework.Timing; using osu.Game.Input.Handlers; using OpenTK.Input; @@ -23,8 +24,8 @@ namespace osu.Game.Screens.Play private ManualClock clock = new ManualClock(); private IFrameBasedClock parentClock; - private LegacyReplayInputHandler replayInputHandler; - public LegacyReplayInputHandler ReplayInputHandler + private ReplayInputHandler replayInputHandler; + public ReplayInputHandler ReplayInputHandler { get { return replayInputHandler; } set diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 23ca656199..9851edd8c1 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -79,7 +79,7 @@ - +