From dcb9d2903b6a6ad19ad772b0cc8992a16fac9b8d Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Fri, 24 Mar 2017 14:03:46 +0900 Subject: [PATCH 1/6] Add virtual method to instantiate legacy replays. --- osu.Game/Modes/Scoring/Score.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/osu.Game/Modes/Scoring/Score.cs b/osu.Game/Modes/Scoring/Score.cs index fa74fba279..75c243278d 100644 --- a/osu.Game/Modes/Scoring/Score.cs +++ b/osu.Game/Modes/Scoring/Score.cs @@ -6,6 +6,7 @@ using Newtonsoft.Json; using osu.Game.Database; using osu.Game.Modes.Mods; using osu.Game.Users; +using System.IO; namespace osu.Game.Modes.Scoring { @@ -43,6 +44,13 @@ namespace osu.Game.Modes.Scoring [JsonProperty(@"date")] public DateTime Date; + /// + /// Creates a legacy replay which is read from a stream. + /// + /// The stream reader. + /// The replay. + public virtual Replay CreateLegacyReplayFrom(StreamReader reader) => new LegacyReplay(reader); + // [JsonProperty(@"count50")] 0, //[JsonProperty(@"count100")] 0, //[JsonProperty(@"count300")] 100, From 99b96236719cbb348aa276021d847322481de16e Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Fri, 24 Mar 2017 14:09:58 +0900 Subject: [PATCH 2/6] Implement taiko replays + key conversion. --- osu.Game.Modes.Taiko/LegacyTaikoReplay.cs | 43 +++++++++++++++++++ .../Scoring/TaikoScoreProcessor.cs | 9 ++++ osu.Game.Modes.Taiko/TaikoScore.cs | 13 ++++++ .../osu.Game.Modes.Taiko.csproj | 2 + osu.Game/Database/ScoreDatabase.cs | 2 +- 5 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 osu.Game.Modes.Taiko/LegacyTaikoReplay.cs create mode 100644 osu.Game.Modes.Taiko/TaikoScore.cs diff --git a/osu.Game.Modes.Taiko/LegacyTaikoReplay.cs b/osu.Game.Modes.Taiko/LegacyTaikoReplay.cs new file mode 100644 index 0000000000..3e6ccd4ac7 --- /dev/null +++ b/osu.Game.Modes.Taiko/LegacyTaikoReplay.cs @@ -0,0 +1,43 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System.Collections.Generic; +using System.IO; +using osu.Framework.Input; +using osu.Game.Input.Handlers; +using OpenTK.Input; + +namespace osu.Game.Modes.Taiko +{ + public class LegacyTaikoReplay : LegacyReplay + { + public LegacyTaikoReplay(StreamReader reader) + : base(reader) + { + } + + public override ReplayInputHandler CreateInputHandler() => new LegacyTaikoReplayInputHandler(Frames); + + private class LegacyTaikoReplayInputHandler : LegacyReplayInputHandler + { + public LegacyTaikoReplayInputHandler(List replayContent) + : base(replayContent) + { + } + + public override List GetPendingStates() => new List + { + new InputState + { + Keyboard = new ReplayKeyboardState(new List(new[] + { + CurrentFrame?.MouseRight1 == true ? Key.F : Key.Unknown, + CurrentFrame?.MouseRight2 == true ? Key.J : Key.Unknown, + CurrentFrame?.MouseLeft1 == true ? Key.D : Key.Unknown, + CurrentFrame?.MouseLeft2 == true ? Key.K : Key.Unknown + })) + } + }; + } + } +} diff --git a/osu.Game.Modes.Taiko/Scoring/TaikoScoreProcessor.cs b/osu.Game.Modes.Taiko/Scoring/TaikoScoreProcessor.cs index 3007411230..25800f1e07 100644 --- a/osu.Game.Modes.Taiko/Scoring/TaikoScoreProcessor.cs +++ b/osu.Game.Modes.Taiko/Scoring/TaikoScoreProcessor.cs @@ -119,6 +119,15 @@ namespace osu.Game.Modes.Taiko.Scoring { } + public override Score CreateScore() => new TaikoScore + { + TotalScore = TotalScore, + Combo = Combo, + MaxCombo = HighestCombo, + Accuracy = Accuracy, + Health = Health, + }; + protected override void ComputeTargets(Beatmap beatmap) { double hpMultiplierNormal = 1 / (hp_hit_great * beatmap.HitObjects.FindAll(o => o is Hit).Count * BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.Difficulty.DrainRate, 0.5, 0.75, 0.98)); diff --git a/osu.Game.Modes.Taiko/TaikoScore.cs b/osu.Game.Modes.Taiko/TaikoScore.cs new file mode 100644 index 0000000000..2d5c3e750b --- /dev/null +++ b/osu.Game.Modes.Taiko/TaikoScore.cs @@ -0,0 +1,13 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Game.Modes.Scoring; +using System.IO; + +namespace osu.Game.Modes.Taiko +{ + public class TaikoScore : Score + { + public override Replay CreateLegacyReplayFrom(StreamReader reader) => new LegacyTaikoReplay(reader); + } +} diff --git a/osu.Game.Modes.Taiko/osu.Game.Modes.Taiko.csproj b/osu.Game.Modes.Taiko/osu.Game.Modes.Taiko.csproj index 937c5a5e51..54ebba138f 100644 --- a/osu.Game.Modes.Taiko/osu.Game.Modes.Taiko.csproj +++ b/osu.Game.Modes.Taiko/osu.Game.Modes.Taiko.csproj @@ -52,6 +52,7 @@ + @@ -61,6 +62,7 @@ + diff --git a/osu.Game/Database/ScoreDatabase.cs b/osu.Game/Database/ScoreDatabase.cs index 665ae8649e..096c0dcc29 100644 --- a/osu.Game/Database/ScoreDatabase.cs +++ b/osu.Game/Database/ScoreDatabase.cs @@ -101,7 +101,7 @@ namespace osu.Game.Database using (var lzma = new LzmaStream(properties, replayInStream, compressedSize, outSize)) using (var reader = new StreamReader(lzma)) - score.Replay = new LegacyReplay(reader); + score.Replay = score.CreateLegacyReplayFrom(reader); } } From 730051520e762f4fda7f9d945480ddb07db13906 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Fri, 24 Mar 2017 14:23:32 +0900 Subject: [PATCH 3/6] Add a way to determine the type of a Hit. --- .../Beatmaps/TaikoBeatmapConverter.cs | 10 ++++++++-- osu.Game.Modes.Taiko/Objects/Hit.cs | 5 +++++ osu.Game.Modes.Taiko/Objects/HitType.cs | 14 ++++++++++++++ osu.Game.Modes.Taiko/osu.Game.Modes.Taiko.csproj | 1 + 4 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 osu.Game.Modes.Taiko/Objects/HitType.cs diff --git a/osu.Game.Modes.Taiko/Beatmaps/TaikoBeatmapConverter.cs b/osu.Game.Modes.Taiko/Beatmaps/TaikoBeatmapConverter.cs index b2676bf28a..c09131dc61 100644 --- a/osu.Game.Modes.Taiko/Beatmaps/TaikoBeatmapConverter.cs +++ b/osu.Game.Modes.Taiko/Beatmaps/TaikoBeatmapConverter.cs @@ -44,7 +44,10 @@ namespace osu.Game.Modes.Taiko.Beatmaps IHasRepeats repeatsData = original as IHasRepeats; IHasEndTime endTimeData = original as IHasEndTime; - bool accented = ((original.Sample?.Type ?? SampleType.None) & SampleType.Finish) > 0; + // Old osu! used hit sounding to determine hits + SampleType sample = original.Sample?.Type ?? SampleType.None; + + bool accented = (sample & SampleType.Finish) > 0; if (distanceData != null) { @@ -71,11 +74,14 @@ namespace osu.Game.Modes.Taiko.Beatmaps }; } + HitType type = (sample & ~(SampleType.Finish | SampleType.Normal)) == 0 ? HitType.Centre : HitType.Rim; + return new Hit { StartTime = original.StartTime, Sample = original.Sample, - Accented = accented + Accented = accented, + Type = type }; } } diff --git a/osu.Game.Modes.Taiko/Objects/Hit.cs b/osu.Game.Modes.Taiko/Objects/Hit.cs index ad8d07d901..0ba07028fd 100644 --- a/osu.Game.Modes.Taiko/Objects/Hit.cs +++ b/osu.Game.Modes.Taiko/Objects/Hit.cs @@ -8,6 +8,11 @@ namespace osu.Game.Modes.Taiko.Objects { public class Hit : TaikoHitObject { + /// + /// Whether this hit is a centre-hit or a rim-hit. + /// + public HitType Type; + /// /// The hit window that results in a "GREAT" hit. /// diff --git a/osu.Game.Modes.Taiko/Objects/HitType.cs b/osu.Game.Modes.Taiko/Objects/HitType.cs new file mode 100644 index 0000000000..6e8e147d75 --- /dev/null +++ b/osu.Game.Modes.Taiko/Objects/HitType.cs @@ -0,0 +1,14 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +namespace osu.Game.Modes.Taiko.Objects +{ + /// + /// Describes whether a hit is a centre-hit or a rim-hit. + /// + public enum HitType + { + Centre, + Rim + } +} diff --git a/osu.Game.Modes.Taiko/osu.Game.Modes.Taiko.csproj b/osu.Game.Modes.Taiko/osu.Game.Modes.Taiko.csproj index 54ebba138f..f3d8c5b2d6 100644 --- a/osu.Game.Modes.Taiko/osu.Game.Modes.Taiko.csproj +++ b/osu.Game.Modes.Taiko/osu.Game.Modes.Taiko.csproj @@ -58,6 +58,7 @@ + From fcf9a599ddbcb6b83fffdd034bd2f32f46fb79e1 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Fri, 24 Mar 2017 14:24:10 +0900 Subject: [PATCH 4/6] Implement taiko auto replays. --- osu.Game.Modes.Taiko/LegacyTaikoReplay.cs | 4 + osu.Game.Modes.Taiko/TaikoAutoReplay.cs | 121 ++++++++++++++++++ .../osu.Game.Modes.Taiko.csproj | 1 + 3 files changed, 126 insertions(+) create mode 100644 osu.Game.Modes.Taiko/TaikoAutoReplay.cs diff --git a/osu.Game.Modes.Taiko/LegacyTaikoReplay.cs b/osu.Game.Modes.Taiko/LegacyTaikoReplay.cs index 3e6ccd4ac7..0b59c9ddd4 100644 --- a/osu.Game.Modes.Taiko/LegacyTaikoReplay.cs +++ b/osu.Game.Modes.Taiko/LegacyTaikoReplay.cs @@ -11,6 +11,10 @@ namespace osu.Game.Modes.Taiko { public class LegacyTaikoReplay : LegacyReplay { + protected LegacyTaikoReplay() + { + } + public LegacyTaikoReplay(StreamReader reader) : base(reader) { diff --git a/osu.Game.Modes.Taiko/TaikoAutoReplay.cs b/osu.Game.Modes.Taiko/TaikoAutoReplay.cs new file mode 100644 index 0000000000..2a5cac419a --- /dev/null +++ b/osu.Game.Modes.Taiko/TaikoAutoReplay.cs @@ -0,0 +1,121 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System.Collections.Generic; +using osu.Game.Modes.Taiko.Objects; +using osu.Game.Modes.Objects.Types; + +namespace osu.Game.Modes.Taiko +{ + public class TaikoAutoReplay : LegacyTaikoReplay + { + private readonly List hitObjects; + + public TaikoAutoReplay(List hitObjects) + { + this.hitObjects = hitObjects; + + createAutoReplay(); + } + + private void createAutoReplay() + { + bool hitButton = true; + + Frames.Add(new LegacyReplayFrame(-100000, 320, 240, LegacyButtonState.None)); + Frames.Add(new LegacyReplayFrame(hitObjects[0].StartTime - 1000, 320, 240, LegacyButtonState.None)); + + for (int i = 0; i < hitObjects.Count; i++) + { + TaikoHitObject h = hitObjects[i]; + + LegacyButtonState button; + + IHasEndTime endTimeData = h as IHasEndTime; + double endTime = endTimeData?.EndTime ?? h.StartTime; + + Bash sp = h as Bash; + if (sp != null) + { + int d = 0; + int count = 0; + int req = sp.RequiredHits; + double hitRate = sp.Duration / req; + for (double j = h.StartTime; j < endTime; j += hitRate) + { + switch (d) + { + default: + button = LegacyButtonState.Left1; + break; + case 1: + button = LegacyButtonState.Right1; + break; + case 2: + button = LegacyButtonState.Left2; + break; + case 3: + button = LegacyButtonState.Right2; + break; + } + + Frames.Add(new LegacyReplayFrame(j, 0, 0, button)); + d = (d + 1) % 4; + if (++count > req) + break; + } + } + else if (h is DrumRoll) + { + DrumRoll d = h as DrumRoll; + + double delay = d.TickTimeDistance; + + double time = d.StartTime; + + for (int j = 0; j < d.TotalTicks; j++) + { + Frames.Add(new LegacyReplayFrame((int)time, 0, 0, hitButton ? LegacyButtonState.Left1 : LegacyButtonState.Left2)); + time += delay; + hitButton = !hitButton; + } + } + else + { + Hit hit = h as Hit; + + if (hit.Type == HitType.Centre) + { + if (h.Accented) + button = LegacyButtonState.Right1 | LegacyButtonState.Right2; + else + button = hitButton ? LegacyButtonState.Right1 : LegacyButtonState.Right2; + } + else + { + if (h.Accented) + button = LegacyButtonState.Left1 | LegacyButtonState.Left2; + else + button = hitButton ? LegacyButtonState.Left1 : LegacyButtonState.Left2; + } + + Frames.Add(new LegacyReplayFrame(h.StartTime, 0, 0, button)); + } + + Frames.Add(new LegacyReplayFrame(endTime + 1, 0, 0, LegacyButtonState.None)); + + if (i < hitObjects.Count - 1) + { + double waitTime = hitObjects[i + 1].StartTime - 1000; + if (waitTime > endTime) + Frames.Add(new LegacyReplayFrame(waitTime, 0, 0, LegacyButtonState.None)); + } + + hitButton = !hitButton; + } + + //Player.currentScore.Replay = InputManager.ReplayScore.Replay; + //Player.currentScore.PlayerName = "mekkadosu!"; + } + } +} \ No newline at end of file diff --git a/osu.Game.Modes.Taiko/osu.Game.Modes.Taiko.csproj b/osu.Game.Modes.Taiko/osu.Game.Modes.Taiko.csproj index f3d8c5b2d6..dde92240d1 100644 --- a/osu.Game.Modes.Taiko/osu.Game.Modes.Taiko.csproj +++ b/osu.Game.Modes.Taiko/osu.Game.Modes.Taiko.csproj @@ -59,6 +59,7 @@ + From 589bdde03c29dcd99e14142747df8bbd0461e888 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Wed, 29 Mar 2017 10:59:35 +0900 Subject: [PATCH 5/6] Fix post-merge errors. --- osu.Game.Modes.Taiko/Beatmaps/TaikoBeatmapConverter.cs | 8 +++++--- osu.Game.Modes.Taiko/TaikoAutoReplay.cs | 6 +++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/osu.Game.Modes.Taiko/Beatmaps/TaikoBeatmapConverter.cs b/osu.Game.Modes.Taiko/Beatmaps/TaikoBeatmapConverter.cs index 65bbced0f8..aa095a1dda 100644 --- a/osu.Game.Modes.Taiko/Beatmaps/TaikoBeatmapConverter.cs +++ b/osu.Game.Modes.Taiko/Beatmaps/TaikoBeatmapConverter.cs @@ -44,8 +44,10 @@ namespace osu.Game.Modes.Taiko.Beatmaps IHasRepeats repeatsData = original as IHasRepeats; IHasEndTime endTimeData = original as IHasEndTime; - // Old osu! used hit sounding to determine hits - bool strong = ((original.Sample?.Type ?? SampleType.None) & SampleType.Finish) > 0; + // Old osu! used hit sounding to determine various hit type information + SampleType sample = original.Sample?.Type ?? SampleType.None; + + bool strong = (sample & SampleType.Finish) > 0; if (distanceData != null) { @@ -78,7 +80,7 @@ namespace osu.Game.Modes.Taiko.Beatmaps { StartTime = original.StartTime, Sample = original.Sample, - IsStrong = strong + IsStrong = strong, Type = type }; } diff --git a/osu.Game.Modes.Taiko/TaikoAutoReplay.cs b/osu.Game.Modes.Taiko/TaikoAutoReplay.cs index 2a5cac419a..1fc4ab8161 100644 --- a/osu.Game.Modes.Taiko/TaikoAutoReplay.cs +++ b/osu.Game.Modes.Taiko/TaikoAutoReplay.cs @@ -34,7 +34,7 @@ namespace osu.Game.Modes.Taiko IHasEndTime endTimeData = h as IHasEndTime; double endTime = endTimeData?.EndTime ?? h.StartTime; - Bash sp = h as Bash; + Swell sp = h as Swell; if (sp != null) { int d = 0; @@ -86,14 +86,14 @@ namespace osu.Game.Modes.Taiko if (hit.Type == HitType.Centre) { - if (h.Accented) + if (h.IsStrong) button = LegacyButtonState.Right1 | LegacyButtonState.Right2; else button = hitButton ? LegacyButtonState.Right1 : LegacyButtonState.Right2; } else { - if (h.Accented) + if (h.IsStrong) button = LegacyButtonState.Left1 | LegacyButtonState.Left2; else button = hitButton ? LegacyButtonState.Left1 : LegacyButtonState.Left2; From 475c86596825e93003873db16bcb5dd8305d5199 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Wed, 29 Mar 2017 11:04:16 +0900 Subject: [PATCH 6/6] Implement TaikoModAutoplay. --- osu.Game.Modes.Taiko/Mods/TaikoMod.cs | 11 +++++++++++ osu.Game.Modes.Taiko/TaikoAutoReplay.cs | 18 +++++++++--------- osu.Game.Modes.Taiko/TaikoRuleset.cs | 2 +- 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/osu.Game.Modes.Taiko/Mods/TaikoMod.cs b/osu.Game.Modes.Taiko/Mods/TaikoMod.cs index c929ebffdd..007187d81b 100644 --- a/osu.Game.Modes.Taiko/Mods/TaikoMod.cs +++ b/osu.Game.Modes.Taiko/Mods/TaikoMod.cs @@ -1,7 +1,10 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using osu.Game.Beatmaps; using osu.Game.Modes.Mods; +using osu.Game.Modes.Scoring; +using osu.Game.Modes.Taiko.Objects; namespace osu.Game.Modes.Taiko.Mods { @@ -61,4 +64,12 @@ namespace osu.Game.Modes.Taiko.Mods { } + + public class TaikoModAutoplay : ModAutoplay + { + protected override Score CreateReplayScore(Beatmap beatmap) => new Score + { + Replay = new TaikoAutoReplay(beatmap) + }; + } } diff --git a/osu.Game.Modes.Taiko/TaikoAutoReplay.cs b/osu.Game.Modes.Taiko/TaikoAutoReplay.cs index 1fc4ab8161..ba121e0968 100644 --- a/osu.Game.Modes.Taiko/TaikoAutoReplay.cs +++ b/osu.Game.Modes.Taiko/TaikoAutoReplay.cs @@ -1,19 +1,19 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using System.Collections.Generic; using osu.Game.Modes.Taiko.Objects; using osu.Game.Modes.Objects.Types; +using osu.Game.Beatmaps; namespace osu.Game.Modes.Taiko { public class TaikoAutoReplay : LegacyTaikoReplay { - private readonly List hitObjects; + private readonly Beatmap beatmap; - public TaikoAutoReplay(List hitObjects) + public TaikoAutoReplay(Beatmap beatmap) { - this.hitObjects = hitObjects; + this.beatmap = beatmap; createAutoReplay(); } @@ -23,11 +23,11 @@ namespace osu.Game.Modes.Taiko bool hitButton = true; Frames.Add(new LegacyReplayFrame(-100000, 320, 240, LegacyButtonState.None)); - Frames.Add(new LegacyReplayFrame(hitObjects[0].StartTime - 1000, 320, 240, LegacyButtonState.None)); + Frames.Add(new LegacyReplayFrame(beatmap.HitObjects[0].StartTime - 1000, 320, 240, LegacyButtonState.None)); - for (int i = 0; i < hitObjects.Count; i++) + for (int i = 0; i < beatmap.HitObjects.Count; i++) { - TaikoHitObject h = hitObjects[i]; + TaikoHitObject h = beatmap.HitObjects[i]; LegacyButtonState button; @@ -104,9 +104,9 @@ namespace osu.Game.Modes.Taiko Frames.Add(new LegacyReplayFrame(endTime + 1, 0, 0, LegacyButtonState.None)); - if (i < hitObjects.Count - 1) + if (i < beatmap.HitObjects.Count - 1) { - double waitTime = hitObjects[i + 1].StartTime - 1000; + double waitTime = beatmap.HitObjects[i + 1].StartTime - 1000; if (waitTime > endTime) Frames.Add(new LegacyReplayFrame(waitTime, 0, 0, LegacyButtonState.None)); } diff --git a/osu.Game.Modes.Taiko/TaikoRuleset.cs b/osu.Game.Modes.Taiko/TaikoRuleset.cs index ce7e756e30..1b3c3fc0eb 100644 --- a/osu.Game.Modes.Taiko/TaikoRuleset.cs +++ b/osu.Game.Modes.Taiko/TaikoRuleset.cs @@ -65,7 +65,7 @@ namespace osu.Game.Modes.Taiko { Mods = new Mod[] { - new ModAutoplay(), + new TaikoModAutoplay(), new ModCinema(), }, },