From bc3f11fdb87983e0faeab1acd96aa2e526f89f52 Mon Sep 17 00:00:00 2001 From: FreezyLemon Date: Wed, 29 Nov 2017 06:24:13 +0100 Subject: [PATCH 001/122] Added PlaysSamples property to prevent certain DrawableHitObjects from playing their samples on hit. Also added this to TaikoObjects so their hitsounds won't be played (will be done by the TaikoRulesetContainer) --- .../Objects/Drawables/DrawableTaikoHitObject.cs | 2 ++ osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs index 7976cbbbc1..8ebfaaea38 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs @@ -14,6 +14,8 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables { public override Vector2 OriginPosition => new Vector2(DrawHeight / 2); + protected override bool PlaysSamples => false; + protected readonly Vector2 BaseSize; protected readonly TaikoPiece MainPiece; diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index 941cedca3f..12f4fc4f31 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -59,6 +59,9 @@ namespace osu.Game.Rulesets.Objects.Drawables private readonly List judgements = new List(); public IReadOnlyList Judgements => judgements; + // Override in inheriting classes to prevent from playing samples on hit + protected virtual bool PlaysSamples => true; + protected List Samples = new List(); public readonly Bindable State = new Bindable(); @@ -92,7 +95,7 @@ namespace osu.Game.Rulesets.Objects.Drawables { UpdateState(state); - if (State == ArmedState.Hit) + if (State == ArmedState.Hit && PlaysSamples) PlaySamples(); }; From 3e8db8c5e1020031f51a874db7d0c7059a54e3b0 Mon Sep 17 00:00:00 2001 From: FreezyLemon Date: Wed, 29 Nov 2017 06:27:25 +0100 Subject: [PATCH 002/122] Enabled strong taiko hitobjects playing samples again. Also removes the first hitsound from the strong hitobject so only the "hitfinish" sound gets played. --- .../Objects/Drawables/DrawableHitStrong.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHitStrong.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHitStrong.cs index c07eaf4d8b..eced24a8da 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHitStrong.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHitStrong.cs @@ -16,6 +16,8 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables /// private const double second_hit_window = 30; + protected override bool PlaysSamples => true; + private double firstHitTime; private bool firstKeyHeld; private TaikoAction firstHitAction; @@ -53,6 +55,15 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables return base.OnReleased(action); } + protected override void LoadComplete() + { + base.LoadComplete(); + + if (Samples.Count > 1) + // Removes the "normal" hitsound, leaving only the hitfinish one + Samples.RemoveAt(0); + } + public override bool OnPressed(TaikoAction action) { if (AllJudged) From c00fb47236253aba363c6b2df67a1937a73ec932 Mon Sep 17 00:00:00 2001 From: FreezyLemon Date: Wed, 29 Nov 2017 06:28:08 +0100 Subject: [PATCH 003/122] Added hitsound handling to the TaikoRulesetContainer so every KeyDown can play a hitsound (instead of the DrawableHitObjects) --- .../UI/TaikoRulesetContainer.cs | 44 ++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs b/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs index 48ee0a5b42..e3765c4252 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs @@ -2,8 +2,11 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using osu.Framework.Allocation; +using osu.Framework.Audio; using osu.Framework.Graphics; +using osu.Framework.Input.Bindings; using osu.Game.Beatmaps; +using osu.Game.Input; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Replays; @@ -15,21 +18,45 @@ using osu.Game.Rulesets.Taiko.Scoring; using osu.Game.Rulesets.UI; using osu.Game.Rulesets.Taiko.Replays; using OpenTK; +using OpenTK.Input; using System.Linq; using osu.Framework.Input; +using System.Collections.Generic; namespace osu.Game.Rulesets.Taiko.UI { public class TaikoRulesetContainer : ScrollingRulesetContainer { + private readonly HashSet centreKeys = new HashSet(); + private readonly HashSet rimKeys = new HashSet(); + private AudioManager audio; + private IEnumerable keyBindings; + public TaikoRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap, bool isForCurrentRuleset) : base(ruleset, beatmap, isForCurrentRuleset) { } [BackgroundDependencyLoader] - private void load() + private void load(AudioManager audio, KeyBindingStore store) { + keyBindings = store.Query(Ruleset.RulesetInfo.ID, Ruleset.AvailableVariants?.First() ?? 0).Cast(); + if (keyBindings.Count() == 0) + keyBindings = Ruleset.GetDefaultKeyBindings(); + + foreach (var kb in keyBindings) + { + var key = (Key)(kb.KeyCombination.Keys as InputKey[]).First(); + var action = kb.GetAction(); + + if (action == TaikoAction.LeftCentre || action == TaikoAction.RightCentre) + centreKeys.Add(key); + + if (action == TaikoAction.LeftRim || action == TaikoAction.RightRim) + rimKeys.Add(key); + } + + this.audio = audio; loadBarLines(); } @@ -77,6 +104,21 @@ namespace osu.Game.Rulesets.Taiko.UI } } + protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) + { + var sampleBank = Beatmap.ControlPointInfo.SoundPointAt(WorkingBeatmap.Track.CurrentTime).SampleBank ?? "normal"; + string sampleName = ""; + + if (centreKeys.Contains(args.Key)) + sampleName = "hitnormal"; + + else if (rimKeys.Contains(args.Key)) + sampleName = "hitclap"; + + audio.Sample.Get($"Gameplay/{sampleBank}-{sampleName}")?.Play(); + return base.OnKeyDown(state, args); + } + protected override Vector2 GetPlayfieldAspectAdjust() { const float default_relative_height = TaikoPlayfield.DEFAULT_HEIGHT / 768; From e3232dd754528a8e2136f6326e20d2671fb60b7d Mon Sep 17 00:00:00 2001 From: FreezyLemon Date: Wed, 29 Nov 2017 06:51:00 +0100 Subject: [PATCH 004/122] Added if to ignore more (for our purposes) useless keydowns --- .../UI/TaikoRulesetContainer.cs | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs b/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs index e3765c4252..f72d253a73 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs @@ -106,16 +106,20 @@ namespace osu.Game.Rulesets.Taiko.UI protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) { - var sampleBank = Beatmap.ControlPointInfo.SoundPointAt(WorkingBeatmap.Track.CurrentTime).SampleBank ?? "normal"; - string sampleName = ""; + if (!args.Repeat) + { + var sampleBank = Beatmap.ControlPointInfo.SoundPointAt(WorkingBeatmap.Track.CurrentTime).SampleBank ?? "normal"; + string sampleName = ""; - if (centreKeys.Contains(args.Key)) - sampleName = "hitnormal"; + if (centreKeys.Contains(args.Key)) + sampleName = "hitnormal"; - else if (rimKeys.Contains(args.Key)) - sampleName = "hitclap"; + else if (rimKeys.Contains(args.Key)) + sampleName = "hitclap"; + + audio.Sample.Get($"Gameplay/{sampleBank}-{sampleName}")?.Play(); + } - audio.Sample.Get($"Gameplay/{sampleBank}-{sampleName}")?.Play(); return base.OnKeyDown(state, args); } From b584178e851fa26da60a3027ec3b52708b8bd39a Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 6 Dec 2017 00:37:37 +0900 Subject: [PATCH 005/122] Make Beatmap ISerializable and add more JsonIgnores --- osu.Game.Rulesets.Mania/Objects/Note.cs | 2 + .../osu.Game.Rulesets.Mania.csproj | 4 + .../Beatmaps/Formats/OsuJsonDecoderTest.cs | 153 ++++++++++++++++++ osu.Game.Tests/osu.Game.Tests.csproj | 1 + osu.Game/Beatmaps/Beatmap.cs | 8 +- osu.Game/Beatmaps/BeatmapDifficulty.cs | 2 + osu.Game/Beatmaps/BeatmapInfo.cs | 7 + osu.Game/Beatmaps/BeatmapMetadata.cs | 5 + .../ControlPoints/ControlPointInfo.cs | 6 +- .../Converters/TypedListConverter.cs | 83 ++++++++++ .../Converters/Vector2Converter.cs | 35 ++++ .../IO/Serialization/IJsonSerializable.cs | 26 +-- osu.Game/Rulesets/RulesetInfo.cs | 3 + osu.Game/osu.Game.csproj | 2 + 14 files changed, 322 insertions(+), 15 deletions(-) create mode 100644 osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs create mode 100644 osu.Game/IO/Serialization/Converters/TypedListConverter.cs create mode 100644 osu.Game/IO/Serialization/Converters/Vector2Converter.cs diff --git a/osu.Game.Rulesets.Mania/Objects/Note.cs b/osu.Game.Rulesets.Mania/Objects/Note.cs index 3c4ff4216f..c4d5a13352 100644 --- a/osu.Game.Rulesets.Mania/Objects/Note.cs +++ b/osu.Game.Rulesets.Mania/Objects/Note.cs @@ -1,6 +1,7 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using Newtonsoft.Json; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Rulesets.Mania.Judgements; @@ -15,6 +16,7 @@ namespace osu.Game.Rulesets.Mania.Objects /// /// The key-press hit window for this note. /// + [JsonIgnore] public HitWindows HitWindows { get; protected set; } = new HitWindows(); public override void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) diff --git a/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj b/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj index ec6f59b5be..1e11e2e694 100644 --- a/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj +++ b/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj @@ -40,6 +40,10 @@ $(SolutionDir)\packages\OpenTK.3.0.0-git00009\lib\net20\OpenTK.dll True + + $(SolutionDir)\packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll + True + diff --git a/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs new file mode 100644 index 0000000000..1531deb265 --- /dev/null +++ b/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs @@ -0,0 +1,153 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System.IO; +using System.Linq; +using NUnit.Framework; +using osu.Game.Audio; +using osu.Game.Beatmaps; +using osu.Game.Beatmaps.Formats; +using osu.Game.IO.Serialization; +using osu.Game.Rulesets.Objects.Types; +using osu.Game.Tests.Resources; +using OpenTK; +using OpenTK.Graphics; + +namespace osu.Game.Tests.Beatmaps.Formats +{ + [TestFixture] + public class OsuJsonDecoderTest + { + [Test] + public void TestDecodeMetadata() + { + var beatmap = decodeAsJson("Soleily - Renatus (Gamu) [Insane].osu"); + var meta = beatmap.BeatmapInfo.Metadata; + Assert.AreEqual(241526, meta.OnlineBeatmapSetID); + Assert.AreEqual("Soleily", meta.Artist); + Assert.AreEqual("Soleily", meta.ArtistUnicode); + Assert.AreEqual("03. Renatus - Soleily 192kbps.mp3", meta.AudioFile); + Assert.AreEqual("Gamu", meta.AuthorString); + Assert.AreEqual("machinetop_background.jpg", meta.BackgroundFile); + Assert.AreEqual(164471, meta.PreviewTime); + Assert.AreEqual(string.Empty, meta.Source); + Assert.AreEqual("MBC7 Unisphere 地球ヤバイEP Chikyu Yabai", meta.Tags); + Assert.AreEqual("Renatus", meta.Title); + Assert.AreEqual("Renatus", meta.TitleUnicode); + } + + [Test] + public void TestDecodeGeneral() + { + var beatmap = decodeAsJson("Soleily - Renatus (Gamu) [Insane].osu"); + var beatmapInfo = beatmap.BeatmapInfo; + Assert.AreEqual(0, beatmapInfo.AudioLeadIn); + Assert.AreEqual(false, beatmapInfo.Countdown); + Assert.AreEqual(0.7f, beatmapInfo.StackLeniency); + Assert.AreEqual(false, beatmapInfo.SpecialStyle); + Assert.IsTrue(beatmapInfo.RulesetID == 0); + Assert.AreEqual(false, beatmapInfo.LetterboxInBreaks); + Assert.AreEqual(false, beatmapInfo.WidescreenStoryboard); + } + + [Test] + public void TestDecodeEditor() + { + var beatmap = decodeAsJson("Soleily - Renatus (Gamu) [Insane].osu"); + var beatmapInfo = beatmap.BeatmapInfo; + + int[] expectedBookmarks = + { + 11505, 22054, 32604, 43153, 53703, 64252, 74802, 85351, + 95901, 106450, 116999, 119637, 130186, 140735, 151285, + 161834, 164471, 175020, 185570, 196119, 206669, 209306 + }; + Assert.AreEqual(expectedBookmarks.Length, beatmapInfo.Bookmarks.Length); + for (int i = 0; i < expectedBookmarks.Length; i++) + Assert.AreEqual(expectedBookmarks[i], beatmapInfo.Bookmarks[i]); + Assert.AreEqual(1.8, beatmapInfo.DistanceSpacing); + Assert.AreEqual(4, beatmapInfo.BeatDivisor); + Assert.AreEqual(4, beatmapInfo.GridSize); + Assert.AreEqual(2, beatmapInfo.TimelineZoom); + } + + [Test] + public void TestDecodeDifficulty() + { + var beatmap = decodeAsJson("Soleily - Renatus (Gamu) [Insane].osu"); + var difficulty = beatmap.BeatmapInfo.BaseDifficulty; + Assert.AreEqual(6.5f, difficulty.DrainRate); + Assert.AreEqual(4, difficulty.CircleSize); + Assert.AreEqual(8, difficulty.OverallDifficulty); + Assert.AreEqual(9, difficulty.ApproachRate); + Assert.AreEqual(1.8f, difficulty.SliderMultiplier); + Assert.AreEqual(2, difficulty.SliderTickRate); + } + + [Test] + public void TestDecodeColors() + { + var beatmap = decodeAsJson("Soleily - Renatus (Gamu) [Insane].osu"); + Color4[] expected = + { + new Color4(142, 199, 255, 255), + new Color4(255, 128, 128, 255), + new Color4(128, 255, 255, 255), + new Color4(128, 255, 128, 255), + new Color4(255, 187, 255, 255), + new Color4(255, 177, 140, 255), + }; + Assert.AreEqual(expected.Length, beatmap.ComboColors.Count); + for (int i = 0; i < expected.Length; i++) + Assert.AreEqual(expected[i], beatmap.ComboColors[i]); + } + + [Test] + public void TestDecodeHitObjects() + { + var beatmap = decodeAsJson("Soleily - Renatus (Gamu) [Insane].osu"); + + var curveData = beatmap.HitObjects[0] as IHasCurve; + var positionData = beatmap.HitObjects[0] as IHasPosition; + + Assert.IsNotNull(positionData); + Assert.IsNotNull(curveData); + Assert.AreEqual(new Vector2(192, 168), positionData.Position); + Assert.AreEqual(956, beatmap.HitObjects[0].StartTime); + Assert.IsTrue(beatmap.HitObjects[0].Samples.Any(s => s.Name == SampleInfo.HIT_NORMAL)); + + positionData = beatmap.HitObjects[1] as IHasPosition; + + Assert.IsNotNull(positionData); + Assert.AreEqual(new Vector2(304, 56), positionData.Position); + Assert.AreEqual(1285, beatmap.HitObjects[1].StartTime); + Assert.IsTrue(beatmap.HitObjects[1].Samples.Any(s => s.Name == SampleInfo.HIT_CLAP)); + } + + /// + /// Reads a .osu file first with a , serializes the resulting to JSON + /// and then deserializes the result back into a through an . + /// + /// The .osu file to decode. + /// The after being decoded by an . + private Beatmap decodeAsJson(string filename) + { + using (var stream = Resource.OpenResource(filename)) + using (var sr = new StreamReader(stream)) + { + var legacyDecoded = new OsuLegacyDecoder().Decode(sr); + + using (var ms = new MemoryStream()) + using (var sw = new StreamWriter(ms)) + using (var sr2 = new StreamReader(ms)) + { + sw.Write(legacyDecoded.Serialize()); + sw.Flush(); + + ms.Position = 0; + return new OsuJsonDecoder().Decode(sr2); + } + } + } + } +} diff --git a/osu.Game.Tests/osu.Game.Tests.csproj b/osu.Game.Tests/osu.Game.Tests.csproj index 092ccfb9b5..60ce67c7f6 100644 --- a/osu.Game.Tests/osu.Game.Tests.csproj +++ b/osu.Game.Tests/osu.Game.Tests.csproj @@ -83,6 +83,7 @@ + diff --git a/osu.Game/Beatmaps/Beatmap.cs b/osu.Game/Beatmaps/Beatmap.cs index 35b6cc2b02..c331872dda 100644 --- a/osu.Game/Beatmaps/Beatmap.cs +++ b/osu.Game/Beatmaps/Beatmap.cs @@ -9,19 +9,21 @@ using System.Linq; using osu.Game.Beatmaps.ControlPoints; using osu.Game.IO.Serialization; using osu.Game.Storyboards; +using Newtonsoft.Json; +using osu.Game.IO.Serialization.Converters; namespace osu.Game.Beatmaps { /// /// A Beatmap containing converted HitObjects. /// - public class Beatmap + public class Beatmap : IJsonSerializable where T : HitObject { public BeatmapInfo BeatmapInfo = new BeatmapInfo(); public ControlPointInfo ControlPointInfo = new ControlPointInfo(); public List Breaks = new List(); - public readonly List ComboColors = new List + public List ComboColors = new List { new Color4(17, 136, 170, 255), new Color4(102, 136, 0, 255), @@ -29,8 +31,10 @@ namespace osu.Game.Beatmaps new Color4(121, 9, 13, 255) }; + [JsonIgnore] public BeatmapMetadata Metadata => BeatmapInfo?.Metadata ?? BeatmapInfo?.BeatmapSet?.Metadata; + [JsonConverter(typeof(TypedListConverter))] /// /// The HitObjects this Beatmap contains. /// diff --git a/osu.Game/Beatmaps/BeatmapDifficulty.cs b/osu.Game/Beatmaps/BeatmapDifficulty.cs index 0b0fca8292..03fbf9a0a7 100644 --- a/osu.Game/Beatmaps/BeatmapDifficulty.cs +++ b/osu.Game/Beatmaps/BeatmapDifficulty.cs @@ -2,6 +2,7 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System.ComponentModel.DataAnnotations.Schema; +using Newtonsoft.Json; namespace osu.Game.Beatmaps { @@ -13,6 +14,7 @@ namespace osu.Game.Beatmaps public const float DEFAULT_DIFFICULTY = 5; [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + [JsonIgnore] public int ID { get; set; } public float DrainRate { get; set; } = DEFAULT_DIFFICULTY; diff --git a/osu.Game/Beatmaps/BeatmapInfo.cs b/osu.Game/Beatmaps/BeatmapInfo.cs index 022d64db03..6b5f7cb150 100644 --- a/osu.Game/Beatmaps/BeatmapInfo.cs +++ b/osu.Game/Beatmaps/BeatmapInfo.cs @@ -15,6 +15,7 @@ namespace osu.Game.Beatmaps public class BeatmapInfo : IEquatable, IJsonSerializable, IHasPrimaryKey { [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + [JsonIgnore] public int ID { get; set; } //TODO: should be in database @@ -38,13 +39,16 @@ namespace osu.Game.Beatmaps set { onlineBeatmapSetID = value > 0 ? value : null; } } + [JsonIgnore] public int BeatmapSetInfoID { get; set; } [Required] + [JsonIgnore] public BeatmapSetInfo BeatmapSet { get; set; } public BeatmapMetadata Metadata { get; set; } + [JsonIgnore] public int BaseDifficultyID { get; set; } public BeatmapDifficulty BaseDifficulty { get; set; } @@ -60,6 +64,7 @@ namespace osu.Game.Beatmaps [JsonProperty("file_sha2")] public string Hash { get; set; } + [JsonIgnore] public bool Hidden { get; set; } /// @@ -74,6 +79,7 @@ namespace osu.Game.Beatmaps public float StackLeniency { get; set; } public bool SpecialStyle { get; set; } + [JsonIgnore] public int RulesetID { get; set; } public RulesetInfo Ruleset { get; set; } @@ -116,6 +122,7 @@ namespace osu.Game.Beatmaps public string Version { get; set; } public double StarDifficulty { get; set; } + public bool ShouldSerializeStarDifficulty() => false; public bool Equals(BeatmapInfo other) { diff --git a/osu.Game/Beatmaps/BeatmapMetadata.cs b/osu.Game/Beatmaps/BeatmapMetadata.cs index 89f9ebf47a..2efbcd4f15 100644 --- a/osu.Game/Beatmaps/BeatmapMetadata.cs +++ b/osu.Game/Beatmaps/BeatmapMetadata.cs @@ -12,6 +12,7 @@ namespace osu.Game.Beatmaps public class BeatmapMetadata { [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + [JsonIgnore] public int ID { get; set; } private int? onlineBeatmapSetID; @@ -29,7 +30,10 @@ namespace osu.Game.Beatmaps public string Artist { get; set; } public string ArtistUnicode { get; set; } + [JsonIgnore] public List Beatmaps { get; set; } + + [JsonIgnore] public List BeatmapSets { get; set; } /// @@ -56,6 +60,7 @@ namespace osu.Game.Beatmaps public string AudioFile { get; set; } public string BackgroundFile { get; set; } + [JsonIgnore] public string[] SearchableTerms => new[] { Author?.Username, diff --git a/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs b/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs index e46eb8e20a..f24e25f112 100644 --- a/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs +++ b/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Linq; +using Newtonsoft.Json; using osu.Framework.Lists; namespace osu.Game.Beatmaps.ControlPoints @@ -58,18 +59,21 @@ namespace osu.Game.Beatmaps.ControlPoints /// The timing control point. public TimingControlPoint TimingPointAt(double time) => binarySearch(TimingPoints, time, TimingPoints.FirstOrDefault()); + [JsonIgnore] /// /// Finds the maximum BPM represented by any timing control point. /// public double BPMMaximum => 60000 / (TimingPoints.OrderBy(c => c.BeatLength).FirstOrDefault() ?? new TimingControlPoint()).BeatLength; + [JsonIgnore] /// /// Finds the minimum BPM represented by any timing control point. /// public double BPMMinimum => 60000 / (TimingPoints.OrderByDescending(c => c.BeatLength).FirstOrDefault() ?? new TimingControlPoint()).BeatLength; + [JsonIgnore] /// /// Finds the mode BPM (most common BPM) represented by the control points. /// @@ -108,4 +112,4 @@ namespace osu.Game.Beatmaps.ControlPoints return list[index - 1]; } } -} \ No newline at end of file +} diff --git a/osu.Game/IO/Serialization/Converters/TypedListConverter.cs b/osu.Game/IO/Serialization/Converters/TypedListConverter.cs new file mode 100644 index 0000000000..1d617422e7 --- /dev/null +++ b/osu.Game/IO/Serialization/Converters/TypedListConverter.cs @@ -0,0 +1,83 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace osu.Game.IO.Serialization.Converters +{ + public class TypedListConverter : JsonConverter + { + public override bool CanConvert(Type objectType) => objectType == typeof(List); + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + var list = new List(); + + var localSerializer = createLocalSerializer(); + + var obj = JObject.Load(reader); + + var lookupTable = new List(); + localSerializer.Populate(obj["LookupTable"].CreateReader(), lookupTable); + + foreach (var tok in obj["Items"]) + { + var itemReader = tok.CreateReader(); + + var typeName = lookupTable[(int)tok["Type"]]; + var instance = (T)Activator.CreateInstance(Type.GetType(typeName)); + localSerializer.Populate(itemReader, instance); + + list.Add(instance); + } + + return list; + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + var list = (List)value; + + var localSerializer = createLocalSerializer(); + + var lookupTable = new List(); + var objects = new List(); + foreach (var item in list) + { + var type = item.GetType().AssemblyQualifiedName; + + int typeId = lookupTable.IndexOf(type); + if (typeId == -1) + { + lookupTable.Add(type); + typeId = lookupTable.Count - 1; + } + + var itemObject = JObject.FromObject(item, localSerializer); + itemObject.AddFirst(new JProperty("Type", typeId)); + objects.Add(itemObject); + } + + writer.WriteStartObject(); + + writer.WritePropertyName("LookupTable"); + localSerializer.Serialize(writer, lookupTable); + + writer.WritePropertyName("Items"); + writer.WriteStartArray(); + foreach (var item in objects) + item.WriteTo(writer); + writer.WriteEndArray(); + + writer.WriteEndObject(); + } + + private JsonSerializer createLocalSerializer() + { + var localSettings = JsonSerializableExtensions.CreateGlobalSettings(); + localSettings.Converters = localSettings.Converters.Where(c => !(c is TypedListConverter)).ToArray(); + return JsonSerializer.Create(localSettings); + } + } +} diff --git a/osu.Game/IO/Serialization/Converters/Vector2Converter.cs b/osu.Game/IO/Serialization/Converters/Vector2Converter.cs new file mode 100644 index 0000000000..4ec27311bc --- /dev/null +++ b/osu.Game/IO/Serialization/Converters/Vector2Converter.cs @@ -0,0 +1,35 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using OpenTK; + +namespace osu.Game.IO.Serialization.Converters +{ + public class Vector2Converter : JsonConverter + { + public override bool CanConvert(Type objectType) => objectType == typeof(Vector2); + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + var obj = JObject.Load(reader); + return new Vector2((float)obj["X"], (float)obj["Y"]); + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + var vector = (Vector2)value; + + writer.WriteStartObject(); + + writer.WritePropertyName("X"); + writer.WriteValue(vector.X); + writer.WritePropertyName("Y"); + writer.WriteValue(vector.Y); + + writer.WriteEndObject(); + } + } +} diff --git a/osu.Game/IO/Serialization/IJsonSerializable.cs b/osu.Game/IO/Serialization/IJsonSerializable.cs index e725742726..8d10f0b291 100644 --- a/osu.Game/IO/Serialization/IJsonSerializable.cs +++ b/osu.Game/IO/Serialization/IJsonSerializable.cs @@ -2,6 +2,7 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using Newtonsoft.Json; +using osu.Game.IO.Serialization.Converters; namespace osu.Game.IO.Serialization { @@ -11,20 +12,21 @@ namespace osu.Game.IO.Serialization public static class JsonSerializableExtensions { - public static string Serialize(this IJsonSerializable obj) - { - return JsonConvert.SerializeObject(obj, new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore }); - } + public static string Serialize(this IJsonSerializable obj) => JsonConvert.SerializeObject(obj, CreateGlobalSettings()); - public static T Deserialize(this string objString) - { - return JsonConvert.DeserializeObject(objString); - } + public static T Deserialize(this string objString) => JsonConvert.DeserializeObject(objString, CreateGlobalSettings()); - public static T DeepClone(this T obj) - where T : IJsonSerializable + public static void DeserializeInto(this string objString, T target) => JsonConvert.PopulateObject(objString, target, CreateGlobalSettings()); + + public static T DeepClone(this T obj) where T : IJsonSerializable => Deserialize(Serialize(obj)); + + public static JsonSerializerSettings CreateGlobalSettings() => new JsonSerializerSettings { - return Deserialize(Serialize(obj)); - } + ReferenceLoopHandling = ReferenceLoopHandling.Ignore, + Formatting = Formatting.Indented, + ObjectCreationHandling = ObjectCreationHandling.Replace, + DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate, + Converters = new JsonConverter[] { new Vector2Converter() } + }; } } diff --git a/osu.Game/Rulesets/RulesetInfo.cs b/osu.Game/Rulesets/RulesetInfo.cs index 17f07158df..e6e0b98293 100644 --- a/osu.Game/Rulesets/RulesetInfo.cs +++ b/osu.Game/Rulesets/RulesetInfo.cs @@ -3,18 +3,21 @@ using System; using System.ComponentModel.DataAnnotations.Schema; +using Newtonsoft.Json; namespace osu.Game.Rulesets { public class RulesetInfo : IEquatable { [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + [JsonIgnore] public int? ID { get; set; } public string Name { get; set; } public string InstantiationInfo { get; set; } + [JsonIgnore] public bool Available { get; set; } public virtual Ruleset CreateInstance() => (Ruleset)Activator.CreateInstance(Type.GetType(InstantiationInfo), this); diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 4ca6123f04..f50e87b074 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -403,6 +403,8 @@ + + From d2dc7c8937dfe1901494c01c81c4459ef40e86ab Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 6 Dec 2017 00:38:12 +0900 Subject: [PATCH 006/122] Add OsuJsonDecoder --- osu.Game/Beatmaps/Formats/BeatmapDecoder.cs | 12 +++++++++- osu.Game/Beatmaps/Formats/OsuJsonDecoder.cs | 25 +++++++++++++++++++++ osu.Game/osu.Game.csproj | 1 + 3 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 osu.Game/Beatmaps/Formats/OsuJsonDecoder.cs diff --git a/osu.Game/Beatmaps/Formats/BeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/BeatmapDecoder.cs index 7e1a87085c..31869e207e 100644 --- a/osu.Game/Beatmaps/Formats/BeatmapDecoder.cs +++ b/osu.Game/Beatmaps/Formats/BeatmapDecoder.cs @@ -14,6 +14,7 @@ namespace osu.Game.Beatmaps.Formats static BeatmapDecoder() { OsuLegacyDecoder.Register(); + OsuJsonDecoder.Register(); } public static BeatmapDecoder GetDecoder(StreamReader stream) @@ -27,7 +28,16 @@ namespace osu.Game.Beatmaps.Formats if (line == null || !decoders.ContainsKey(line)) throw new IOException(@"Unknown file format"); - return (BeatmapDecoder)Activator.CreateInstance(decoders[line], line); + + try + { + return (BeatmapDecoder)Activator.CreateInstance(decoders[line], line); + } + catch + { + // As a default case, try a parameterless constructor + return (BeatmapDecoder)Activator.CreateInstance(decoders[line]); + } } protected static void AddDecoder(string magic) where T : BeatmapDecoder diff --git a/osu.Game/Beatmaps/Formats/OsuJsonDecoder.cs b/osu.Game/Beatmaps/Formats/OsuJsonDecoder.cs new file mode 100644 index 0000000000..392f1b4890 --- /dev/null +++ b/osu.Game/Beatmaps/Formats/OsuJsonDecoder.cs @@ -0,0 +1,25 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System.IO; +using osu.Game.IO.Serialization; + +namespace osu.Game.Beatmaps.Formats +{ + public class OsuJsonDecoder : BeatmapDecoder + { + public static void Register() + { + AddDecoder("{"); + } + + protected override void ParseFile(StreamReader stream, Beatmap beatmap) + { + stream.BaseStream.Position = 0; + stream.DiscardBufferedData(); + + string fullText = stream.ReadToEnd(); + fullText.DeserializeInto(beatmap); + } + } +} diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index f50e87b074..9e5d4291ce 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -266,6 +266,7 @@ + From e199ee52252b85ff0b091cc86c6c1c91f1ef2972 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 6 Dec 2017 00:42:17 +0900 Subject: [PATCH 007/122] Add a few xmldocs --- osu.Game/IO/Serialization/Converters/TypedListConverter.cs | 6 ++++++ osu.Game/IO/Serialization/Converters/Vector2Converter.cs | 3 +++ 2 files changed, 9 insertions(+) diff --git a/osu.Game/IO/Serialization/Converters/TypedListConverter.cs b/osu.Game/IO/Serialization/Converters/TypedListConverter.cs index 1d617422e7..9c35fae7d4 100644 --- a/osu.Game/IO/Serialization/Converters/TypedListConverter.cs +++ b/osu.Game/IO/Serialization/Converters/TypedListConverter.cs @@ -6,6 +6,12 @@ using Newtonsoft.Json.Linq; namespace osu.Game.IO.Serialization.Converters { + /// + /// A type of that serializes a alongside + /// a lookup table for the types contained. The lookup table is used in deserialization to + /// reconstruct the objects with their original types. + /// + /// The type of objects contained in the this attribute is attached to. public class TypedListConverter : JsonConverter { public override bool CanConvert(Type objectType) => objectType == typeof(List); diff --git a/osu.Game/IO/Serialization/Converters/Vector2Converter.cs b/osu.Game/IO/Serialization/Converters/Vector2Converter.cs index 4ec27311bc..5f21018fd5 100644 --- a/osu.Game/IO/Serialization/Converters/Vector2Converter.cs +++ b/osu.Game/IO/Serialization/Converters/Vector2Converter.cs @@ -8,6 +8,9 @@ using OpenTK; namespace osu.Game.IO.Serialization.Converters { + /// + /// A type of that serializes only the X and Y coordinates of a . + /// public class Vector2Converter : JsonConverter { public override bool CanConvert(Type objectType) => objectType == typeof(Vector2); From 44edb8724fcabc81456616346a9a25dc55dcb54a Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 6 Dec 2017 13:46:49 +0900 Subject: [PATCH 008/122] Add JsonIgnores to CommandTimelineGroup --- osu.Game/Storyboards/CommandTimelineGroup.cs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/osu.Game/Storyboards/CommandTimelineGroup.cs b/osu.Game/Storyboards/CommandTimelineGroup.cs index 332a6f79cb..c6d9202121 100644 --- a/osu.Game/Storyboards/CommandTimelineGroup.cs +++ b/osu.Game/Storyboards/CommandTimelineGroup.cs @@ -6,6 +6,7 @@ using OpenTK.Graphics; using osu.Framework.Graphics; using System.Collections.Generic; using System.Linq; +using Newtonsoft.Json; namespace osu.Game.Storyboards { @@ -23,6 +24,7 @@ namespace osu.Game.Storyboards public CommandTimeline FlipH = new CommandTimeline(); public CommandTimeline FlipV = new CommandTimeline(); + [JsonIgnore] public IEnumerable Timelines { get @@ -39,14 +41,25 @@ namespace osu.Game.Storyboards } } + [JsonIgnore] public double CommandsStartTime => Timelines.Where(t => t.HasCommands).Min(t => t.StartTime); + + [JsonIgnore] public double CommandsEndTime => Timelines.Where(t => t.HasCommands).Max(t => t.EndTime); + + [JsonIgnore] public double CommandsDuration => CommandsEndTime - CommandsStartTime; + [JsonIgnore] public virtual double StartTime => CommandsStartTime; + + [JsonIgnore] public virtual double EndTime => CommandsEndTime; + + [JsonIgnore] public double Duration => EndTime - StartTime; + [JsonIgnore] public bool HasCommands => Timelines.Any(t => t.HasCommands); public virtual IEnumerable.TypedCommand> GetCommands(CommandTimelineSelector timelineSelector, double offset = 0) From 887b81148db1741aaee3f85642beeb536ddc0528 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 6 Dec 2017 14:14:07 +0900 Subject: [PATCH 009/122] Don't ignore RulesetId for now --- osu.Game/Beatmaps/BeatmapInfo.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Beatmaps/BeatmapInfo.cs b/osu.Game/Beatmaps/BeatmapInfo.cs index 6b5f7cb150..9450022a01 100644 --- a/osu.Game/Beatmaps/BeatmapInfo.cs +++ b/osu.Game/Beatmaps/BeatmapInfo.cs @@ -79,7 +79,6 @@ namespace osu.Game.Beatmaps public float StackLeniency { get; set; } public bool SpecialStyle { get; set; } - [JsonIgnore] public int RulesetID { get; set; } public RulesetInfo Ruleset { get; set; } From f9e34dfa3d51415062e8bd7ce677274c7823d274 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 6 Dec 2017 16:23:51 +0900 Subject: [PATCH 010/122] Assume that control points are already sequentially-ordered Fixes up deserializing. --- .../UI/ManiaRulesetContainer.cs | 3 +-- .../Visual/TestCaseBeatSyncedContainer.cs | 4 ++-- .../Beatmaps/ControlPoints/ControlPointInfo.cs | 16 ++++++++++------ 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs b/osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs index cbbcb84b31..83306187bd 100644 --- a/osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs +++ b/osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs @@ -9,7 +9,6 @@ using osu.Framework.Allocation; using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; using osu.Framework.Input; -using osu.Framework.Lists; using osu.Framework.MathUtils; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; @@ -44,7 +43,7 @@ namespace osu.Game.Rulesets.Mania.UI // Generate the bar lines double lastObjectTime = (Objects.LastOrDefault() as IHasEndTime)?.EndTime ?? Objects.LastOrDefault()?.StartTime ?? double.MaxValue; - SortedList timingPoints = Beatmap.ControlPointInfo.TimingPoints; + List timingPoints = Beatmap.ControlPointInfo.TimingPoints; var barLines = new List(); for (int i = 0; i < timingPoints.Count; i++) diff --git a/osu.Game.Tests/Visual/TestCaseBeatSyncedContainer.cs b/osu.Game.Tests/Visual/TestCaseBeatSyncedContainer.cs index 18555574ba..d99485f3a2 100644 --- a/osu.Game.Tests/Visual/TestCaseBeatSyncedContainer.cs +++ b/osu.Game.Tests/Visual/TestCaseBeatSyncedContainer.cs @@ -2,12 +2,12 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; +using System.Collections.Generic; using osu.Framework.Audio.Track; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; -using osu.Framework.Lists; using osu.Framework.Timing; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Graphics.Containers; @@ -137,7 +137,7 @@ namespace osu.Game.Tests.Visual }; } - private SortedList timingPoints => Beatmap.Value.Beatmap.ControlPointInfo.TimingPoints; + private List timingPoints => Beatmap.Value.Beatmap.ControlPointInfo.TimingPoints; private TimingControlPoint getNextTimingPoint(TimingControlPoint current) { if (timingPoints[timingPoints.Count - 1] == current) diff --git a/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs b/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs index f24e25f112..652ae42979 100644 --- a/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs +++ b/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs @@ -5,31 +5,35 @@ using System; using System.Collections.Generic; using System.Linq; using Newtonsoft.Json; -using osu.Framework.Lists; namespace osu.Game.Beatmaps.ControlPoints { + [Serializable] public class ControlPointInfo { + [JsonProperty] /// /// All timing points. /// - public readonly SortedList TimingPoints = new SortedList(Comparer.Default); + public List TimingPoints { get; private set; } = new List(); + [JsonProperty] /// /// All difficulty points. /// - public readonly SortedList DifficultyPoints = new SortedList(Comparer.Default); + public List DifficultyPoints { get; private set; } = new List(); + [JsonProperty] /// /// All sound points. /// - public readonly SortedList SoundPoints = new SortedList(Comparer.Default); + public List SoundPoints { get; private set; } = new List(); + [JsonProperty] /// /// All effect points. /// - public readonly SortedList EffectPoints = new SortedList(Comparer.Default); + public List EffectPoints { get; private set; } = new List(); /// /// Finds the difficulty control point that is active at . @@ -87,7 +91,7 @@ namespace osu.Game.Beatmaps.ControlPoints /// The time to find the control point at. /// The control point to use when is before any control points. If null, a new control point will be constructed. /// The active control point at . - private T binarySearch(SortedList list, double time, T prePoint = null) + private T binarySearch(List list, double time, T prePoint = null) where T : ControlPoint, new() { if (list == null) From ed5f7e5353a77d05203a596cb0c3bee4380fd237 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 6 Dec 2017 16:28:34 +0900 Subject: [PATCH 011/122] Make OsuJsonDecoder apply defaults similar to OsuLegacyDecoder --- osu.Game/Beatmaps/Formats/OsuJsonDecoder.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Beatmaps/Formats/OsuJsonDecoder.cs b/osu.Game/Beatmaps/Formats/OsuJsonDecoder.cs index 392f1b4890..ed4b8f3857 100644 --- a/osu.Game/Beatmaps/Formats/OsuJsonDecoder.cs +++ b/osu.Game/Beatmaps/Formats/OsuJsonDecoder.cs @@ -20,6 +20,9 @@ namespace osu.Game.Beatmaps.Formats string fullText = stream.ReadToEnd(); fullText.DeserializeInto(beatmap); + + foreach (var hitObject in beatmap.HitObjects) + hitObject.ApplyDefaults(beatmap.ControlPointInfo, beatmap.BeatmapInfo.BaseDifficulty); } } } From b6b26cfe2565140b2b515ae1c076a0fe72083ab0 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 7 Dec 2017 03:04:36 +0900 Subject: [PATCH 012/122] Add basic method to migrate beatmaps to the new JSON format --- osu.Game/Beatmaps/BeatmapManager.cs | 25 ++++++++++++ .../IO/Serialization/IJsonSerializable.cs | 2 +- .../Sections/Maintenance/GeneralSettings.cs | 40 +++++++++++++++++++ 3 files changed, 66 insertions(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 0641cabcd8..c96b889213 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -545,6 +545,31 @@ namespace osu.Game.Beatmaps return beatmapSet; } + public void UpdateContent(BeatmapInfo beatmapInfo, Stream newData) + { + // let's only allow one concurrent update at a time for now. + var context = createContext(); + + using (var transaction = context.BeginTransaction()) + { + // create local stores so we can isolate and thread safely, and share a context/transaction. + var setInfo = beatmapInfo.BeatmapSet; + var existingSetFileInfo = setInfo.Files.First(f => f.FileInfo.Hash == beatmapInfo.Hash); + var existingFileInfo = existingSetFileInfo.FileInfo; + + existingSetFileInfo.FileInfo = files.Add(newData); + files.Dereference(existingFileInfo); + + beatmapInfo.Hash = newData.ComputeSHA2Hash(); + beatmapInfo.MD5Hash = newData.ComputeMD5Hash(); + + context.Update(existingSetFileInfo); + context.Update(beatmapInfo); + + context.SaveChanges(transaction); + } + } + /// /// Returns a list of all usable s. /// diff --git a/osu.Game/IO/Serialization/IJsonSerializable.cs b/osu.Game/IO/Serialization/IJsonSerializable.cs index 8d10f0b291..e192d702ce 100644 --- a/osu.Game/IO/Serialization/IJsonSerializable.cs +++ b/osu.Game/IO/Serialization/IJsonSerializable.cs @@ -16,7 +16,7 @@ namespace osu.Game.IO.Serialization public static T Deserialize(this string objString) => JsonConvert.DeserializeObject(objString, CreateGlobalSettings()); - public static void DeserializeInto(this string objString, T target) => JsonConvert.PopulateObject(objString, target, CreateGlobalSettings()); + public static void DeserializeInto(this string objString, T target) => JsonConvert.DeserializeAnonymousType(objString, target, CreateGlobalSettings()); public static T DeepClone(this T obj) where T : IJsonSerializable => Deserialize(Serialize(obj)); diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs index 4f4f381ae1..a41da6109c 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs @@ -1,12 +1,15 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System; +using System.IO; using System.Linq; using System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Game.Beatmaps; using osu.Game.Graphics.UserInterface; +using osu.Game.IO.Serialization; namespace osu.Game.Overlays.Settings.Sections.Maintenance { @@ -15,6 +18,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance private TriangleButton importButton; private TriangleButton deleteButton; private TriangleButton restoreButton; + private TriangleButton migrateButton; protected override string Header => "General"; @@ -55,6 +59,42 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance }).ContinueWith(t => Schedule(() => restoreButton.Enabled.Value = true)); } }, + migrateButton = new SettingsButton + { + Text = "Migrate all beatmaps to the new format", + Action = () => + { + migrateButton.Enabled.Value = false; + Task.Run(() => + { + var usableSets = beatmaps.GetAllUsableBeatmapSets(); + foreach (var set in usableSets) + { + foreach (var beatmap in set.Beatmaps) + { + var working = beatmaps.GetWorkingBeatmap(beatmap); + using (var ms = new MemoryStream()) + using (var sw = new StreamWriter(ms)) + { + try + { + sw.Write(working.Beatmap.Serialize()); + } + catch (Exception e) + { + Console.WriteLine(e); + throw; + } + sw.Flush(); + + ms.Position = 0; + beatmaps.UpdateContent(beatmap, ms); + } + } + } + }).ContinueWith(t => Schedule(() => migrateButton.Enabled.Value = true)); + } + } }; } } From 4232a54b32507afeaed5ad317b70ebf9f644160d Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 7 Dec 2017 03:04:56 +0900 Subject: [PATCH 013/122] Make TypedListConverter not reconstruct serializers --- .../Converters/TypedListConverter.cs | 20 ++++--------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/osu.Game/IO/Serialization/Converters/TypedListConverter.cs b/osu.Game/IO/Serialization/Converters/TypedListConverter.cs index 9c35fae7d4..f8897a4e9d 100644 --- a/osu.Game/IO/Serialization/Converters/TypedListConverter.cs +++ b/osu.Game/IO/Serialization/Converters/TypedListConverter.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using Newtonsoft.Json; using Newtonsoft.Json.Linq; @@ -20,12 +19,10 @@ namespace osu.Game.IO.Serialization.Converters { var list = new List(); - var localSerializer = createLocalSerializer(); - var obj = JObject.Load(reader); var lookupTable = new List(); - localSerializer.Populate(obj["LookupTable"].CreateReader(), lookupTable); + serializer.Populate(obj["LookupTable"].CreateReader(), lookupTable); foreach (var tok in obj["Items"]) { @@ -33,7 +30,7 @@ namespace osu.Game.IO.Serialization.Converters var typeName = lookupTable[(int)tok["Type"]]; var instance = (T)Activator.CreateInstance(Type.GetType(typeName)); - localSerializer.Populate(itemReader, instance); + serializer.Populate(itemReader, instance); list.Add(instance); } @@ -45,8 +42,6 @@ namespace osu.Game.IO.Serialization.Converters { var list = (List)value; - var localSerializer = createLocalSerializer(); - var lookupTable = new List(); var objects = new List(); foreach (var item in list) @@ -60,7 +55,7 @@ namespace osu.Game.IO.Serialization.Converters typeId = lookupTable.Count - 1; } - var itemObject = JObject.FromObject(item, localSerializer); + var itemObject = JObject.FromObject(item, serializer); itemObject.AddFirst(new JProperty("Type", typeId)); objects.Add(itemObject); } @@ -68,7 +63,7 @@ namespace osu.Game.IO.Serialization.Converters writer.WriteStartObject(); writer.WritePropertyName("LookupTable"); - localSerializer.Serialize(writer, lookupTable); + serializer.Serialize(writer, lookupTable); writer.WritePropertyName("Items"); writer.WriteStartArray(); @@ -78,12 +73,5 @@ namespace osu.Game.IO.Serialization.Converters writer.WriteEndObject(); } - - private JsonSerializer createLocalSerializer() - { - var localSettings = JsonSerializableExtensions.CreateGlobalSettings(); - localSettings.Converters = localSettings.Converters.Where(c => !(c is TypedListConverter)).ToArray(); - return JsonSerializer.Create(localSettings); - } } } From 9787788081d15fa49071f474db45fca99e01f045 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 7 Dec 2017 03:39:43 +0900 Subject: [PATCH 014/122] Revert unintended change --- osu.Game/IO/Serialization/IJsonSerializable.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/IO/Serialization/IJsonSerializable.cs b/osu.Game/IO/Serialization/IJsonSerializable.cs index e192d702ce..8d10f0b291 100644 --- a/osu.Game/IO/Serialization/IJsonSerializable.cs +++ b/osu.Game/IO/Serialization/IJsonSerializable.cs @@ -16,7 +16,7 @@ namespace osu.Game.IO.Serialization public static T Deserialize(this string objString) => JsonConvert.DeserializeObject(objString, CreateGlobalSettings()); - public static void DeserializeInto(this string objString, T target) => JsonConvert.DeserializeAnonymousType(objString, target, CreateGlobalSettings()); + public static void DeserializeInto(this string objString, T target) => JsonConvert.PopulateObject(objString, target, CreateGlobalSettings()); public static T DeepClone(this T obj) where T : IJsonSerializable => Deserialize(Serialize(obj)); From 41b607c1657cfaac915e66dbe0e0a10b7dbdafaa Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 7 Dec 2017 03:40:43 +0900 Subject: [PATCH 015/122] Dont serialize hitobject sample properties copied from the control point --- osu.Game/Audio/SampleInfo.cs | 28 +++++++++++++++++++++++--- osu.Game/Rulesets/Objects/HitObject.cs | 14 ++----------- 2 files changed, 27 insertions(+), 15 deletions(-) diff --git a/osu.Game/Audio/SampleInfo.cs b/osu.Game/Audio/SampleInfo.cs index 171a1bdf75..edfda3bdc9 100644 --- a/osu.Game/Audio/SampleInfo.cs +++ b/osu.Game/Audio/SampleInfo.cs @@ -1,8 +1,13 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System; +using Newtonsoft.Json; +using osu.Game.Beatmaps.ControlPoints; + namespace osu.Game.Audio { + [Serializable] public class SampleInfo { public const string HIT_WHISTLE = @"hitwhistle"; @@ -10,19 +15,36 @@ namespace osu.Game.Audio public const string HIT_NORMAL = @"hitnormal"; public const string HIT_CLAP = @"hitclap"; + [JsonIgnore] + public SoundControlPoint ControlPoint; + + private string bank; /// /// The bank to load the sample from. /// - public string Bank; + public string Bank + { + get { return string.IsNullOrEmpty(bank) ? (ControlPoint?.SampleBank ?? "normal") : bank; } + set { bank = value; } + } + + public bool ShouldSerializeBank() => Bank == ControlPoint.SampleBank; /// /// The name of the sample to load. /// - public string Name; + public string Name { get; set; } + private int volume; /// /// The sample volume. /// - public int Volume; + public int Volume + { + get { return volume == 0 ? (ControlPoint?.SampleVolume ?? 0) : volume; } + set { volume = value; } + } + + public bool ShouldSerializeVolume() => Volume == ControlPoint.SampleVolume; } } diff --git a/osu.Game/Rulesets/Objects/HitObject.cs b/osu.Game/Rulesets/Objects/HitObject.cs index c69979d4cf..92220ff8bd 100644 --- a/osu.Game/Rulesets/Objects/HitObject.cs +++ b/osu.Game/Rulesets/Objects/HitObject.cs @@ -48,21 +48,11 @@ namespace osu.Game.Rulesets.Objects Kiai |= effectPoint.KiaiMode; // Initialize first sample - Samples.ForEach(s => initializeSampleInfo(s, soundPoint)); + Samples.ForEach(s => s.ControlPoint = soundPoint); // Initialize any repeat samples var repeatData = this as IHasRepeats; - repeatData?.RepeatSamples?.ForEach(r => r.ForEach(s => initializeSampleInfo(s, soundPoint))); - } - - private void initializeSampleInfo(SampleInfo sample, SoundControlPoint soundPoint) - { - if (sample.Volume == 0) - sample.Volume = soundPoint?.SampleVolume ?? 0; - - // If the bank is not assigned a name, assign it from the control point - if (string.IsNullOrEmpty(sample.Bank)) - sample.Bank = soundPoint?.SampleBank ?? @"normal"; + repeatData?.RepeatSamples?.ForEach(r => r.ForEach(s => s.ControlPoint = soundPoint)); } } } From a8db3a9484cebcadde7ac61445a39c5ba1ef709f Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 7 Dec 2017 04:09:03 +0900 Subject: [PATCH 016/122] Add progress notification to migration --- osu.Game/Beatmaps/BeatmapManager.cs | 48 +++++++++++++++++++ .../Sections/Maintenance/GeneralSettings.cs | 29 +---------- 2 files changed, 49 insertions(+), 28 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index c96b889213..6b547afe5d 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -20,6 +20,7 @@ using osu.Game.Beatmaps.IO; using osu.Game.Database; using osu.Game.Graphics; using osu.Game.IO; +using osu.Game.IO.Serialization; using osu.Game.IPC; using osu.Game.Online.API; using osu.Game.Online.API.Requests; @@ -570,6 +571,53 @@ namespace osu.Game.Beatmaps } } + public void MigrateAllToNewFormat() + { + var usableSets = GetAllUsableBeatmapSets(); + + if (usableSets.Count == 0) + return; + + var notification = new ProgressNotification + { + Progress = 0, + State = ProgressNotificationState.Active, + }; + + PostNotification?.Invoke(notification); + + int i = 1; + foreach (var set in usableSets) + { + if (notification.State == ProgressNotificationState.Cancelled) + // user requested abort + return; + + notification.Text = $"Migrating ({i} of {usableSets.Count})"; + notification.Progress = (float)i++ / usableSets.Count; + + foreach (var beatmap in set.Beatmaps) + { + if (notification.State == ProgressNotificationState.Cancelled) + // user requested abort + return; + + var working = GetWorkingBeatmap(beatmap); + using (var ms = new MemoryStream()) + using (var sw = new StreamWriter(ms)) + { + sw.Write(working.Beatmap.Serialize()); + sw.Flush(); + + ms.Position = 0; + UpdateContent(beatmap, ms); + } + } + } + + notification.State = ProgressNotificationState.Completed; + } + /// /// Returns a list of all usable s. /// diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs index a41da6109c..9ae331daf0 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs @@ -65,34 +65,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance Action = () => { migrateButton.Enabled.Value = false; - Task.Run(() => - { - var usableSets = beatmaps.GetAllUsableBeatmapSets(); - foreach (var set in usableSets) - { - foreach (var beatmap in set.Beatmaps) - { - var working = beatmaps.GetWorkingBeatmap(beatmap); - using (var ms = new MemoryStream()) - using (var sw = new StreamWriter(ms)) - { - try - { - sw.Write(working.Beatmap.Serialize()); - } - catch (Exception e) - { - Console.WriteLine(e); - throw; - } - sw.Flush(); - - ms.Position = 0; - beatmaps.UpdateContent(beatmap, ms); - } - } - } - }).ContinueWith(t => Schedule(() => migrateButton.Enabled.Value = true)); + Task.Factory.StartNew(beatmaps.MigrateAllToNewFormat).ContinueWith(t => Schedule(() => migrateButton.Enabled.Value = true), TaskContinuationOptions.LongRunning); } } }; From 0e3b001b133e310064065be3c98f3f13f320321d Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 7 Dec 2017 10:37:51 +0900 Subject: [PATCH 017/122] Make maps with storyboards decode correctly with OsuJsonDecoder --- osu.Game/Beatmaps/Formats/OsuJsonDecoder.cs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/osu.Game/Beatmaps/Formats/OsuJsonDecoder.cs b/osu.Game/Beatmaps/Formats/OsuJsonDecoder.cs index ed4b8f3857..d00cbbb8fb 100644 --- a/osu.Game/Beatmaps/Formats/OsuJsonDecoder.cs +++ b/osu.Game/Beatmaps/Formats/OsuJsonDecoder.cs @@ -18,8 +18,16 @@ namespace osu.Game.Beatmaps.Formats stream.BaseStream.Position = 0; stream.DiscardBufferedData(); - string fullText = stream.ReadToEnd(); - fullText.DeserializeInto(beatmap); + try + { + string fullText = stream.ReadToEnd(); + fullText.DeserializeInto(beatmap); + } + catch + { + // Temporary because storyboards are deserialized into beatmaps at the moment + // This try-catch shouldn't exist in the future + } foreach (var hitObject in beatmap.HitObjects) hitObject.ApplyDefaults(beatmap.ControlPointInfo, beatmap.BeatmapInfo.BaseDifficulty); From 9597f9d46ba306fa2be72c46f7fccec7428797a2 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 7 Dec 2017 11:10:20 +0900 Subject: [PATCH 018/122] Resharper cleanup --- .../Overlays/Settings/Sections/Maintenance/GeneralSettings.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs index 9ae331daf0..f0f5b434cd 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs @@ -1,15 +1,12 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using System; -using System.IO; using System.Linq; using System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Game.Beatmaps; using osu.Game.Graphics.UserInterface; -using osu.Game.IO.Serialization; namespace osu.Game.Overlays.Settings.Sections.Maintenance { From ea2c67ca5fe03415fe7a79831738131f8ebb1585 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 7 Dec 2017 11:10:34 +0900 Subject: [PATCH 019/122] Fix incorrect serialization condition --- osu.Game/Audio/SampleInfo.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Audio/SampleInfo.cs b/osu.Game/Audio/SampleInfo.cs index edfda3bdc9..f8b5bf33d9 100644 --- a/osu.Game/Audio/SampleInfo.cs +++ b/osu.Game/Audio/SampleInfo.cs @@ -28,7 +28,7 @@ namespace osu.Game.Audio set { bank = value; } } - public bool ShouldSerializeBank() => Bank == ControlPoint.SampleBank; + public bool ShouldSerializeBank() => Bank != ControlPoint.SampleBank; /// /// The name of the sample to load. @@ -45,6 +45,6 @@ namespace osu.Game.Audio set { volume = value; } } - public bool ShouldSerializeVolume() => Volume == ControlPoint.SampleVolume; + public bool ShouldSerializeVolume() => Volume != ControlPoint.SampleVolume; } } From 499ecb4eddebc72913a4747715fb111bff7be6bb Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 7 Dec 2017 11:11:38 +0900 Subject: [PATCH 020/122] Add parity checking OsuJsonDecoder test cases --- .../Beatmaps/Formats/OsuJsonDecoderTest.cs | 36 +- ...n - The Unforgiving (Armin) [Marathon].osu | 7102 +++++++++++++++++ osu.Game.Tests/osu.Game.Tests.csproj | 4 + osu.Game.Tests/packages.config | 1 + 4 files changed, 7135 insertions(+), 8 deletions(-) create mode 100644 osu.Game.Tests/Resources/Within Temptation - The Unforgiving (Armin) [Marathon].osu diff --git a/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs index 1531deb265..c3ebcb9e7c 100644 --- a/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs @@ -3,6 +3,7 @@ using System.IO; using System.Linq; +using DeepEqual.Syntax; using NUnit.Framework; using osu.Game.Audio; using osu.Game.Beatmaps; @@ -18,10 +19,13 @@ namespace osu.Game.Tests.Beatmaps.Formats [TestFixture] public class OsuJsonDecoderTest { + private const string beatmap_1 = "Soleily - Renatus (Gamu) [Insane].osu"; + private const string beatmap_2 = "Within Temptation - The Unforgiving (Armin) [Marathon].osu"; + [Test] public void TestDecodeMetadata() { - var beatmap = decodeAsJson("Soleily - Renatus (Gamu) [Insane].osu"); + var beatmap = decodeAsJson(beatmap_1); var meta = beatmap.BeatmapInfo.Metadata; Assert.AreEqual(241526, meta.OnlineBeatmapSetID); Assert.AreEqual("Soleily", meta.Artist); @@ -39,7 +43,7 @@ namespace osu.Game.Tests.Beatmaps.Formats [Test] public void TestDecodeGeneral() { - var beatmap = decodeAsJson("Soleily - Renatus (Gamu) [Insane].osu"); + var beatmap = decodeAsJson(beatmap_1); var beatmapInfo = beatmap.BeatmapInfo; Assert.AreEqual(0, beatmapInfo.AudioLeadIn); Assert.AreEqual(false, beatmapInfo.Countdown); @@ -53,7 +57,7 @@ namespace osu.Game.Tests.Beatmaps.Formats [Test] public void TestDecodeEditor() { - var beatmap = decodeAsJson("Soleily - Renatus (Gamu) [Insane].osu"); + var beatmap = decodeAsJson(beatmap_1); var beatmapInfo = beatmap.BeatmapInfo; int[] expectedBookmarks = @@ -74,7 +78,7 @@ namespace osu.Game.Tests.Beatmaps.Formats [Test] public void TestDecodeDifficulty() { - var beatmap = decodeAsJson("Soleily - Renatus (Gamu) [Insane].osu"); + var beatmap = decodeAsJson(beatmap_1); var difficulty = beatmap.BeatmapInfo.BaseDifficulty; Assert.AreEqual(6.5f, difficulty.DrainRate); Assert.AreEqual(4, difficulty.CircleSize); @@ -87,7 +91,7 @@ namespace osu.Game.Tests.Beatmaps.Formats [Test] public void TestDecodeColors() { - var beatmap = decodeAsJson("Soleily - Renatus (Gamu) [Insane].osu"); + var beatmap = decodeAsJson(beatmap_1); Color4[] expected = { new Color4(142, 199, 255, 255), @@ -105,7 +109,7 @@ namespace osu.Game.Tests.Beatmaps.Formats [Test] public void TestDecodeHitObjects() { - var beatmap = decodeAsJson("Soleily - Renatus (Gamu) [Insane].osu"); + var beatmap = decodeAsJson(beatmap_1); var curveData = beatmap.HitObjects[0] as IHasCurve; var positionData = beatmap.HitObjects[0] as IHasPosition; @@ -124,13 +128,29 @@ namespace osu.Game.Tests.Beatmaps.Formats Assert.IsTrue(beatmap.HitObjects[1].Samples.Any(s => s.Name == SampleInfo.HIT_CLAP)); } + [TestCase(beatmap_1)] + [TestCase(beatmap_2)] + public void TestParity(string beatmap) + { + var beatmaps = decode(beatmap); + beatmaps.jsonDecoded.ShouldDeepEqual(beatmaps.legacyDecoded); + } + /// /// Reads a .osu file first with a , serializes the resulting to JSON /// and then deserializes the result back into a through an . /// /// The .osu file to decode. /// The after being decoded by an . - private Beatmap decodeAsJson(string filename) + private Beatmap decodeAsJson(string filename) => decode(filename).jsonDecoded; + + /// + /// Reads a .osu file first with a , serializes the resulting to JSON + /// and then deserializes the result back into a through an . + /// + /// The .osu file to decode. + /// The after being decoded by an . + private (Beatmap legacyDecoded, Beatmap jsonDecoded) decode(string filename) { using (var stream = Resource.OpenResource(filename)) using (var sr = new StreamReader(stream)) @@ -145,7 +165,7 @@ namespace osu.Game.Tests.Beatmaps.Formats sw.Flush(); ms.Position = 0; - return new OsuJsonDecoder().Decode(sr2); + return (legacyDecoded, new OsuJsonDecoder().Decode(sr2)); } } } diff --git a/osu.Game.Tests/Resources/Within Temptation - The Unforgiving (Armin) [Marathon].osu b/osu.Game.Tests/Resources/Within Temptation - The Unforgiving (Armin) [Marathon].osu new file mode 100644 index 0000000000..4f8e8f820f --- /dev/null +++ b/osu.Game.Tests/Resources/Within Temptation - The Unforgiving (Armin) [Marathon].osu @@ -0,0 +1,7102 @@ +osu file format v9 + +[General] +AudioFilename: Within Temptation - The Unforgiving.mp3 +AudioLeadIn: 2000 +PreviewTime: 2513029 +Countdown: 0 +SampleSet: Soft +StackLeniency: 0.7 +Mode: 0 +LetterboxInBreaks: 1 + +[Editor] +Bookmarks: 3177331 +DistanceSpacing: 0.9 +BeatDivisor: 4 +GridSize: 4 + +[Metadata] +Title:The Unforgiving +Artist:Within Temptation +Creator:Armin +Version:Marathon +Source: +Tags:Gonzvlo narakucrimson Roddie Vass_Bass ErufenRito Glass Card N'FoRcE force HakunoKaemi metal Why not me Shot in the Dark In the Middle of the Night Faster Fire and Ice Iron Where is the edge Sinead Lost Murder A Demon's Fate Stairway to the skies TU Marathon symphonic metal rock Sharon den Adel collab + +[Difficulty] +HPDrainRate:3 +CircleSize:4 +OverallDifficulty:7 +ApproachRate:8 +SliderMultiplier:2 +SliderTickRate:1 + +[Events] +//Background and Video events +0,0,"Within-Temptation.png" +Video,-300,"Mother Maiden_xvid_003.avi" +Video,910191,"Fire And Ice_x264.avi" +Video,648748,"17 Faster_x264_001.avi" +Video,1730578,"19 Sinead_xvid_001.avi" +Video,34667,"Within Temptation-Shot In The _x264_001.avi" +//Break Periods +2,31107,46554 +2,116273,123530 +2,193254,209002 +2,325697,336343 +2,442893,451543 +2,533893,549943 +2,644043,670986 +2,744936,750986 +2,886436,932774 +2,1017706,1021899 +2,1141547,1152290 +2,1285058,1290472 +2,1372331,1382290 +2,1476876,1505227 +2,1575917,1584318 +2,1666307,1676266 +2,1714619,1747493 +2,1825109,1829544 +2,1903058,1916980 +2,1935879,1949288 +2,1981007,1993647 +2,2205454,2225075 +2,2290311,2308242 +2,2394266,2400928 +2,2473072,2486674 +2,2513371,2525630 +2,2555908,2578758 +2,2686971,2696967 +2,2787469,2800847 +2,2889559,2901019 +2,2925673,2939538 +2,3002710,3007686 +2,3086784,3102501 +//Storyboard Layer 0 (Background) +//Storyboard Layer 1 (Fail) +//Storyboard Layer 2 (Pass) +//Storyboard Layer 3 (Foreground) +//Storyboard Sound Samples +//Background Colour Transformations +3,100,163,162,255 + +[TimingPoints] +2406,418.848167539267,4,2,0,100,1,0 +15829,418.848167539267,4,2,0,100,1,0 +34572,565.904267861353,4,1,0,100,1,0 +47011,-100,4,2,1,100,0,0 +95696,566.037735849057,4,2,1,100,1,0 +97111,-100,4,1,0,80,0,1 +97247,-100,4,1,0,82,0,1 +97388,-100,4,1,0,84,0,1 +97530,-100,4,1,0,86,0,1 +97671,-100,4,1,0,90,0,1 +97818,-100,4,1,0,93,0,0 +97960,-100,4,1,0,96,0,1 +98096,-100,4,2,1,100,0,1 +106020,-100,4,1,1,80,0,1 +106233,-100,4,1,1,83,0,1 +106374,-100,4,1,1,86,0,1 +106516,-100,4,1,1,89,0,1 +106657,-100,4,1,1,92,0,1 +106799,-100,4,1,1,95,0,1 +106940,-100,4,2,1,98,0,1 +116073,-100,4,2,1,98,0,0 +124134,-100,4,1,0,100,0,0 +124983,-100,4,2,1,100,0,0 +160926,-100,4,1,0,100,0,0 +161209,-100,4,2,1,100,0,0 +165454,-100,4,1,0,100,0,0 +165737,-100,4,2,1,100,0,0 +169983,-100,4,1,0,100,0,0 +170266,-100,4,2,0,87,0,0 +172671,-100,4,1,0,100,0,0 +173101,-100,4,1,0,81,0,1 +173237,-100,4,1,0,84,0,1 +173379,-100,4,1,0,87,0,1 +173520,-100,4,1,0,90,0,1 +174658,-100,4,2,0,100,0,0 +174941,-100,4,2,1,100,0,1 +182436,-100,4,2,0,100,0,1 +183002,-100,4,1,0,100,0,1 +183714,-100,4,2,0,100,0,0 +183997,-100,4,2,1,100,0,1 +191563,-100,4,1,0,80,0,1 +191775,-100,4,1,0,83,0,1 +191917,-100,4,1,0,86,0,1 +192058,-100,4,1,0,89,0,1 +192200,-100,4,1,0,91,0,1 +192341,-100,4,1,0,93,0,1 +192483,-100,4,1,0,95,0,1 +192624,-100,4,1,0,97,0,1 +192766,-100,4,1,0,98,0,1 +192907,-100,4,1,0,99,0,1 +193054,-100,4,2,0,100,0,0 +209888,-100,4,1,0,63,0,0 +211311,-100,4,2,0,5,0,0 +214708,-100,4,2,0,30,0,0 +215549,-100,4,1,0,15,0,0 +215686,566.037735849057,4,1,0,15,1,0 +215761,-100,4,2,0,5,0,0 +217105,-100,4,2,0,31,0,0 +217884,-100,4,1,0,15,0,0 +218450,-100,4,2,0,30,0,0 +218662,-100,4,1,0,15,0,0 +219299,-100,4,2,0,29,0,0 +219511,-100,4,2,0,36,0,0 +220148,-100,4,1,0,16,0,0 +220289,-100,4,2,0,16,0,0 +220997,-100,4,1,0,16,0,0 +221138,-100,4,2,0,16,0,0 +222341,-100,4,1,0,16,0,0 +222907,-100,4,2,0,16,0,0 +223190,-100,4,1,0,16,0,0 +223473,-100,4,2,0,16,0,0 +224605,-100,4,1,0,16,0,0 +225171,-100,4,2,0,16,0,0 +225454,-100,4,1,0,16,0,0 +226091,-100,4,2,0,16,0,0 +226870,-100,4,1,0,16,0,0 +227436,-100,4,2,0,16,0,0 +227719,-100,4,1,0,16,0,0 +228072,-100,4,2,0,16,0,0 +229134,-100,4,1,0,16,0,0 +229770,-100,4,2,0,16,0,0 +229983,-100,4,1,0,16,0,0 +230195,-100,4,2,0,16,0,0 +231469,-100,4,1,0,16,0,0 +231610,-100,4,2,0,16,0,0 +232318,-100,4,1,0,16,0,0 +232601,-100,4,2,0,33,0,0 +233167,-100,4,2,0,21,0,0 +233733,-100,4,1,0,21,0,0 +243355,-100,4,1,0,41,0,0 +246256,-100,4,1,0,26,0,0 +247954,-100,4,1,0,39,0,0 +250510,-100,4,2,0,40,0,0 +250651,-100,4,2,0,50,0,0 +250793,-100,4,2,0,60,0,0 +251912,-100,4,2,1,100,0,1 +267761,-100,4,2,1,100,0,0 +270025,-100,4,2,1,100,0,1 +270171,-76.9230769230769,4,2,1,83,0,1 +285737,-76.9230769230769,4,1,0,36,0,1 +286162,-76.9230769230769,4,1,0,45,0,1 +286445,-76.9230769230769,4,1,0,52,0,1 +286728,-76.9230769230769,4,1,0,60,0,1 +287011,-76.9230769230769,4,1,0,68,0,1 +287294,-76.9230769230769,4,1,0,76,0,1 +287577,-76.9230769230769,4,1,1,83,0,1 +287855,-76.9230769230769,4,2,1,100,0,0 +288138,-76.9230769230769,4,2,1,100,0,1 +296068,-76.9230769230769,4,1,1,54,0,1 +296351,-76.9230769230769,4,1,1,60,0,1 +296634,-76.9230769230769,4,1,1,71,0,1 +296923,-76.9230769230769,4,2,1,93,0,0 +297195,-76.9230769230769,4,2,1,100,0,1 +306252,-76.9230769230769,4,2,1,100,0,0 +324082,-76.9230769230769,4,2,1,100,0,0 +324152,-76.9230769230769,4,2,1,65,0,0 +337093,300,4,2,1,40,1,0 +346663,-100,4,1,0,70,0,0 +346851,-100,4,2,1,70,0,0 +366193,-100,4,2,1,70,0,0 +384870,-100,4,2,0,70,0,0 +384943,-100,4,1,0,70,0,0 +385138,-100,4,2,1,70,0,0 +388663,-100,4,1,0,70,0,0 +389001,-100,4,2,1,70,0,0 +399493,-100,4,1,0,70,0,0 +399651,-100,4,2,1,70,0,0 +408343,-100,4,1,0,70,0,0 +408943,-100,4,1,0,70,0,0 +409093,-100,4,1,0,70,0,0 +409168,-100,4,2,1,70,0,0 +416593,-100,4,1,0,70,0,0 +416670,-100,4,2,0,70,0,0 +416743,-100,4,1,0,50,0,0 +416893,-100,4,1,0,80,0,0 +416968,-100,4,2,0,70,0,0 +417043,-100,4,1,0,50,0,0 +417193,-100,4,1,0,90,0,0 +417270,-100,4,2,0,70,0,0 +417493,-100,4,1,0,100,0,0 +417568,-100,4,2,0,70,0,0 +418693,-100,4,2,1,70,0,1 +428226,-100,4,1,0,70,0,1 +428451,-100,4,2,1,70,0,1 +436634,-100,4,2,0,70,0,1 +436784,-100,4,1,0,70,0,1 +437830,-100,4,1,0,70,0,0 +437893,-100,4,1,0,70,0,1 +442693,-100,4,1,0,70,0,0 +452001,-100,4,2,1,70,0,0 +461293,-100,4,1,0,70,0,0 +461976,-100,4,2,1,70,0,0 +470293,-100,4,1,0,70,0,0 +471576,-100,4,2,0,70,0,0 +471726,-100,4,1,0,70,0,0 +471876,-100,4,2,1,70,0,0 +475693,-100,4,1,0,70,0,0 +475926,-100,4,1,0,70,0,0 +476526,-100,4,1,0,70,0,0 +476676,-100,4,2,1,70,0,0 +479893,-100,4,1,0,70,0,0 +481176,-100,4,2,0,70,0,0 +481326,-100,4,1,0,70,0,0 +481476,-100,4,2,1,70,0,0 +490693,-100,4,1,0,70,0,1 +490851,-100,4,2,1,70,0,1 +499693,-100,4,1,0,60,0,1 +499993,-100,4,1,0,65,0,1 +500143,-100,4,1,0,70,0,0 +500293,-100,4,1,0,70,0,1 +501276,-100,4,2,0,70,0,1 +501426,-100,4,1,0,70,0,1 +501876,-100,4,2,0,70,0,1 +502326,-100,4,1,0,70,0,1 +502776,-100,4,2,0,70,0,1 +502926,-100,4,1,0,70,0,1 +509293,-100,4,1,0,60,0,1 +509593,-100,4,1,0,65,0,1 +514693,-100,4,1,0,70,0,0 +514709,-100,4,1,0,70,0,0 +563151,-83.3333333333333,4,1,0,70,0,0 +574251,-76.9230769230769,4,1,0,70,0,0 +581893,-76.9230769230769,4,1,0,70,0,1 +591193,-76.9230769230769,4,1,0,70,0,0 +591493,-76.9230769230769,4,1,0,70,0,1 +601093,-76.9230769230769,4,1,0,70,0,1 +603726,-83.3333333333333,4,1,0,70,0,1 +605893,-83.3333333333333,4,1,0,70,0,0 +634993,-83.3333333333333,4,1,0,20,0,0 +648736,500,4,2,1,100,1,0 +710611,-100,4,1,0,63,0,0 +710781,-100,4,1,0,65,0,0 +710857,-100,4,1,0,70,0,0 +710982,-100,4,1,0,76,0,0 +711107,-100,4,1,0,79,0,0 +711232,-100,4,1,0,85,0,0 +711357,-100,4,1,0,91,0,0 +711482,-100,4,1,0,94,0,0 +711781,-100,4,1,0,100,0,0 +712736,-76.9230769230769,4,1,0,100,0,1 +712798,-76.9230769230769,4,2,1,100,0,1 +720498,-76.9230769230769,4,1,0,100,0,0 +720736,-76.9230769230769,4,1,0,100,0,1 +721986,-76.9230769230769,4,2,1,100,0,1 +727986,-76.9230769230769,4,1,0,80,0,1 +728111,-76.9230769230769,4,1,0,83,0,1 +728236,-76.9230769230769,4,1,0,86,0,1 +728361,-76.9230769230769,4,1,0,89,0,1 +728486,-76.9230769230769,4,1,0,92,0,1 +728623,-76.9230769230769,4,1,0,95,0,0 +728736,-76.9230769230769,4,1,0,98,0,1 +744736,-100,4,1,0,100,0,0 +751234,-100,4,2,1,100,0,0 +752611,-100,4,1,0,100,0,0 +752861,-100,4,2,1,100,0,0 +759611,-100,4,1,0,100,0,0 +759861,-100,4,2,0,100,0,0 +760173,-100,4,1,0,100,0,0 +760361,-100,4,2,0,100,0,0 +760673,-100,4,1,0,100,0,0 +760861,-100,4,2,1,100,0,0 +784548,-100,4,2,0,100,0,0 +785111,-100,4,1,0,100,0,0 +785361,-83.3333333333333,4,1,0,100,0,0 +785548,-83.3333333333333,4,2,0,100,0,0 +786111,-83.3333333333333,4,1,0,100,0,0 +786361,-71.4285714285714,4,1,0,100,0,0 +786548,-71.4285714285714,4,2,0,100,0,0 +787111,-62.5,4,1,0,100,0,0 +787548,-62.5,4,2,0,100,0,0 +788111,-55.5555555555556,4,1,0,100,0,0 +788548,-55.5555555555556,4,2,0,100,0,0 +789111,-55.5555555555556,4,1,0,100,0,0 +789361,-50,4,1,0,100,0,0 +789548,-50,4,2,0,100,0,0 +790111,-76.9230769230769,4,1,0,100,0,0 +790736,-76.9230769230769,4,1,0,80,0,0 +790986,-76.9230769230769,4,1,0,85,0,0 +791236,-76.9230769230769,4,1,0,90,0,0 +791486,-76.9230769230769,4,1,0,95,0,0 +791736,-76.9230769230769,4,1,0,100,0,0 +792736,-76.9230769230769,4,1,0,100,0,1 +800486,-76.9230769230769,4,1,0,100,0,0 +800736,-76.9230769230769,4,1,0,100,0,1 +808611,-76.9230769230769,4,1,0,100,0,0 +808736,-76.9230769230769,4,1,0,100,0,1 +824611,-76.9230769230769,4,1,0,100,0,0 +824736,-76.9230769230769,4,1,0,100,0,1 +824861,-76.9230769230769,4,1,0,100,0,0 +852361,-76.9230769230769,4,2,0,100,0,0 +858736,-76.9230769230769,4,1,0,100,0,0 +860736,-66.6666666666667,4,1,0,100,0,1 +868486,-66.6666666666667,4,1,0,100,0,0 +868736,-66.6666666666667,4,1,0,100,0,1 +872361,-66.6666666666667,4,1,0,100,0,1 +873861,-66.6666666666667,4,1,0,100,0,1 +884486,-66.6666666666667,4,1,0,100,0,0 +884736,-66.6666666666667,4,1,0,100,0,1 +886236,-66.6666666666667,4,1,0,100,0,0 +912957,856.959223023638,4,2,0,21,1,0 +941887,-117.647058823529,4,2,0,21,0,0 +972298,-100,4,2,0,21,0,0 +974654,-100,4,2,0,21,0,0 +991894,-117.647058823529,4,2,0,21,0,0 +992858,-100,4,2,0,21,0,0 +1015131,-90.9090909090909,4,2,0,21,0,0 +1015452,-90.9090909090909,4,2,0,5,0,0 +1017701,-100,4,2,0,15,0,0 +1022649,428.571428571429,4,2,1,78,1,0 +1030031,-90.9090909090909,4,2,0,79,0,0 +1031103,-100,4,2,1,79,0,0 +1049960,-100,4,1,0,60,0,0 +1050174,-100,4,2,0,100,0,0 +1051674,-100,4,1,0,60,0,0 +1051889,-100,4,2,0,100,0,0 +1052103,-100,4,1,0,60,0,0 +1052317,-100,4,2,0,100,0,0 +1052531,-100,4,1,0,60,0,0 +1052746,-100,4,2,0,100,0,0 +1052960,-100,4,1,0,60,0,0 +1053174,-100,4,2,0,100,0,0 +1053389,-100,4,1,0,80,0,0 +1053603,-100,4,2,0,100,0,0 +1054246,-100,4,1,0,80,0,0 +1054460,-100,4,2,1,81,0,0 +1067103,-100,4,1,0,80,0,0 +1067317,-100,4,2,1,100,0,0 +1069674,-100,4,1,0,85,0,0 +1069996,-100,4,2,1,85,0,0 +1070531,-100,4,1,0,68,0,0 +1070746,-100,4,2,0,100,0,0 +1071389,-100,4,1,0,80,0,0 +1071603,-100,4,2,0,100,0,0 +1072246,-100,4,1,0,60,0,0 +1072460,-100,4,2,0,100,0,0 +1073103,-100,4,1,0,80,0,0 +1073317,-100,4,2,0,100,0,0 +1073960,-100,4,1,0,60,0,0 +1074174,-100,4,2,0,100,0,0 +1074389,-100,4,1,0,60,0,0 +1074603,-100,4,2,0,100,0,0 +1074817,-100,4,1,0,80,0,0 +1075031,-100,4,2,0,100,0,0 +1075674,-100,4,1,0,60,0,0 +1076317,-100,4,2,0,100,0,0 +1076531,-100,4,1,0,80,0,0 +1076746,-100,4,2,0,100,0,0 +1077389,-100,4,2,1,81,0,0 +1081246,-90.9090909090909,4,2,1,82,0,0 +1082317,-100,4,2,1,80,0,0 +1083281,-100,4,2,1,80,0,0 +1093460,-90.9090909090909,4,2,1,80,0,0 +1094317,-100,4,2,1,80,0,0 +1105674,-100,4,2,1,80,0,0 +1118531,-100,4,1,0,80,0,0 +1118746,-100,4,2,1,80,0,0 +1122014,-100,4,1,0,80,0,0 +1122174,-100,4,2,1,80,0,0 +1128817,-133.333333333333,4,2,1,80,0,0 +1135674,-100,4,2,0,22,0,0 +1137505,444.444444444444,4,2,0,22,1,0 +1139282,461.538461538462,4,2,0,16,1,0 +1140205,571.428571428571,4,2,0,19,1,0 +1141347,571.428571428571,4,2,0,19,1,0 +1150313,454.545454545455,4,2,0,100,1,0 +1153040,-100,4,2,1,100,0,0 +1226981,-72.992700729927,4,2,1,100,0,0 +1241222,-68.0272108843537,4,2,1,100,0,1 +1284868,-105.042016806723,4,1,0,100,0,0 +1291224,-80.7754442649435,4,1,0,100,0,0 +1291299,-80.7754442649435,4,2,1,100,0,0 +1291375,-80.7754442649435,4,1,0,100,0,0 +1291451,-80.7754442649435,4,2,1,100,0,0 +1291527,-80.7754442649435,4,1,0,100,0,0 +1291602,-80.7754442649435,4,2,1,100,0,0 +1291678,-74.6268656716418,4,1,0,100,0,0 +1292133,-72.7272727272727,4,2,1,100,0,0 +1328494,-72.992700729927,4,2,1,100,0,1 +1342147,-72.992700729927,4,2,1,100,0,1 +1342737,-72.992700729927,4,2,1,100,0,0 +1343040,-72.992700729927,4,2,1,100,0,1 +1345025,-63.2911392405063,4,2,1,100,0,1 +1345935,-72.992700729927,4,2,1,100,0,1 +1357585,-72.992700729927,4,2,1,100,0,0 +1372139,-72.992700729927,4,2,1,100,0,0 +1408427,-86.2068965517241,4,2,1,100,0,0 +1409571,-87.5656742556918,4,2,1,100,0,0 +1412071,-87.5656742556918,4,1,0,100,0,0 +1412222,-87.5656742556918,4,2,1,100,0,0 +1415767,-72.992700729927,4,2,1,100,0,1 +1430009,-72.992700729927,4,2,1,100,0,0 +1430312,-72.992700729927,4,2,1,100,0,1 +1430632,-63.2911392405063,4,2,1,100,0,1 +1444706,-63.2911392405063,4,2,1,100,0,0 +1444858,-63.2911392405063,4,2,1,100,0,1 +1473949,-63.2911392405063,4,2,1,100,0,0 +1491562,389.61038961039,4,1,0,80,1,0 +1506367,-200,4,1,0,80,0,0 +1507146,-100,4,1,0,80,0,0 +1550782,-100,4,1,0,80,0,1 +1575717,-100,4,1,0,80,0,0 +1584873,-100,4,2,0,70,0,0 +1587511,-100,4,1,0,80,0,0 +1589938,-200,4,1,0,80,0,0 +1590523,-100,4,1,0,80,0,0 +1619354,-100,4,1,0,80,0,1 +1644289,-100,4,1,0,80,0,0 +1662990,-100,4,2,0,40,0,0 +1678575,-100,4,2,0,70,0,0 +1688315,-100,4,1,0,40,0,0 +1688510,-100,4,1,0,50,0,0 +1688704,-100,4,1,0,60,0,0 +1688899,-100,4,1,0,70,0,0 +1689094,-100,4,1,0,80,0,0 +1689289,-100,4,1,0,80,0,0 +1689484,-100,4,1,0,80,0,0 +1691042,-100,4,1,0,80,0,1 +1714419,-100,4,2,0,40,0,0 +1730551,512.820512820513,4,1,0,100,1,0 +1747667,-181.818181818182,4,2,0,35,0,0 +1763137,-120.481927710843,4,2,1,70,0,0 +1795191,-120.481927710843,4,2,1,90,0,0 +1796192,-90.9090909090909,4,2,1,100,0,1 +1824909,-100,4,2,1,100,0,0 +1830166,-119.760479041916,4,2,1,100,0,0 +1874140,-90.9090909090909,4,2,1,100,0,1 +1902858,-100,4,2,1,100,0,0 +1917477,-120.481927710843,4,2,1,100,0,0 +1950551,-120.481927710843,4,2,1,70,0,0 +1951063,-120.481927710843,4,2,1,60,0,0 +1952088,-90.9090909090909,4,2,1,100,0,1 +1967986,-90.9090909090909,4,2,1,100,0,0 +1968499,-90.9090909090909,4,2,1,100,0,1 +1980807,-90.9090909090909,4,2,1,100,0,0 +1994397,428.571428571429,3,2,0,30,1,0 +1995484,-100,3,2,0,48,0,0 +1995913,-100,3,2,0,30,0,0 +2000627,-100,3,2,0,51,0,0 +2001055,-100,3,2,0,30,0,0 +2045825,-100,3,2,0,40,0,0 +2070163,-100,3,1,0,60,0,0 +2070323,-100,3,2,0,60,0,0 +2071539,-100,3,1,0,50,0,0 +2072825,-100,3,1,0,60,0,0 +2073055,-100,3,2,0,60,0,0 +2073913,-100,3,2,1,60,0,0 +2130682,-100,3,2,1,60,0,1 +2141198,-87.719298245614,3,2,1,60,0,1 +2142484,-100,3,2,1,60,0,1 +2153825,-100,3,2,1,60,0,0 +2189734,-87.719298245614,3,2,1,60,0,0 +2197448,-100,3,2,1,60,0,0 +2245012,-100,3,1,0,60,0,0 +2246397,-100,3,1,0,60,0,1 +2246619,-100,3,2,1,60,0,1 +2269111,-100,3,2,1,60,0,0 +2269539,-100,3,2,1,60,0,1 +2290111,-100,3,2,1,60,0,0 +2308992,447.761194029851,4,2,0,29,1,0 +2316044,-100,4,2,1,51,0,0 +2336305,-100,4,1,0,41,0,0 +2337318,-100,4,2,1,51,0,0 +2350969,-100,4,1,0,41,0,0 +2351865,-133.333333333333,4,2,1,60,0,0 +2365521,-133.333333333333,4,1,0,20,0,0 +2365745,-133.333333333333,4,1,0,30,0,0 +2365969,-100,4,1,0,50,0,0 +2366305,-100,4,1,2,60,0,1 +2379408,-100,4,1,2,70,0,1 +2381087,-100,4,1,2,60,0,1 +2394962,-100,4,1,2,60,0,0 +2402350,-100,4,2,1,55,0,0 +2415223,-100,4,1,0,50,0,0 +2416566,-100,4,2,1,50,0,0 +2429775,-100,4,1,0,50,0,0 +2430671,-133.333333333333,4,2,1,50,0,0 +2444327,-133.333333333333,4,2,1,40,0,0 +2444551,-133.333333333333,4,2,1,50,0,0 +2445111,-100,4,1,2,60,0,1 +2470186,-100,4,1,0,65,0,0 +2488096,-100,4,1,0,65,0,1 +2488214,-100,4,1,0,65,0,0 +2502424,-100,4,1,0,65,0,1 +2502542,-100,4,1,0,65,0,0 +2526162,-100,4,1,0,40,0,0 +2526721,-100,4,1,0,50,0,0 +2527169,-100,4,1,0,60,0,0 +2527499,-100,4,1,2,65,0,1 +2541380,-100,4,1,2,65,0,0 +2541827,-100,4,1,2,65,0,1 +2553021,-100,4,1,2,65,0,1 +2555596,-100,4,1,2,5,0,1 +2556156,-100,4,1,2,56,0,0 +2565180,447.761194029851,4,1,0,100,1,0 +2579508,-100,4,2,0,80,0,0 +2586112,-100,4,1,0,69,0,0 +2643985,-100,4,1,0,69,0,1 +2658314,-100,4,1,0,69,0,1 +2671747,-100,4,1,0,69,0,1 +2672642,-100,4,1,0,69,0,0 +2701539,-90.9090909090909,4,1,0,69,0,0 +2715643,-100,4,1,0,69,0,0 +2729956,-100,4,1,0,69,0,1 +2758612,-76.9230769230769,4,1,0,69,0,0 +2761875,-66.6666666666667,4,1,0,69,0,0 +2801605,-133.333333333333,4,1,0,60,0,0 +2815926,-100,4,1,0,60,0,0 +2844582,-100,4,1,0,60,0,1 +2855329,-100,4,1,0,60,0,0 +2858911,-100,4,1,0,60,0,1 +2873239,-100,4,1,0,60,0,0 +2889304,-100,4,2,0,5,0,0 +2895844,370.37037037037,4,2,0,100,1,0 +2901399,-166.666666666667,4,2,0,50,0,0 +2924269,-200,4,2,0,50,0,0 +2940108,-200,4,2,1,50,0,0 +2952145,-100,4,2,1,75,0,0 +2960479,-133.333333333333,4,2,1,75,0,0 +2962331,-100,4,2,1,75,0,0 +2976220,-100,4,2,1,75,0,0 +3016775,-133.333333333333,4,2,1,75,0,0 +3018627,-100,4,2,1,75,0,0 +3057232,-151.515151515152,4,1,0,60,0,0 +3058719,-100,4,2,0,75,0,0 +3059182,-100,4,2,1,75,0,0 +3082562,-100,4,2,0,10,0,0 +3086775,-100,4,2,0,75,0,0 +3103066,-151.515151515152,4,1,0,60,0,0 +3105571,-151.515151515152,4,2,0,75,0,0 +3106126,-151.515151515152,4,1,0,60,0,0 +3108066,-151.515151515152,4,2,0,75,0,0 +3108437,-151.515151515152,4,1,0,60,0,0 +3108626,-151.515151515152,4,2,0,75,0,0 +3109177,-151.515151515152,4,1,0,60,0,0 +3111029,-151.515151515152,4,2,0,75,0,0 +3111400,-151.515151515152,4,1,0,60,0,0 +3111589,-151.515151515152,4,2,0,75,0,0 +3112140,-151.515151515152,4,1,0,60,0,0 +3117978,-100,4,2,1,75,0,0 +3126214,-100,4,2,1,75,0,0 +3165474,-100,4,2,1,75,0,1 +3176960,-100,4,2,1,75,0,0 +3177325,-100,4,2,1,75,0,1 +3177695,-100,4,2,1,75,0,0 + + +[Colours] +Combo1 : 12,50,233 +Combo2 : 253,225,28 +Combo3 : 185,17,17 +Combo4 : 30,136,35 +SliderBorder : 0,0,0 + +[HitObjects] +40,48,2405,1,4 +144,344,2824,1,0 +256,48,3243,1,2 +368,344,3662,1,0 +472,48,4081,1,2 +336,216,4500,2,0,B|308:146|192:136|171:225|171:225,1,200,0|2 +256,256,5128,1,0 +256,336,5337,1,0 +92,88,5756,5,2 +256,144,6175,1,0 +420,88,6594,1,2 +400,252,7013,1,0 +256,336,7432,1,2 +112,252,7851,1,0 +92,88,8269,1,2 +336,172,8688,6,0,B|308:102|192:92|171:181|171:181,1,200,0|2 +348,348,9526,1,0 +164,348,9945,1,2 +80,160,10364,1,0 +256,40,10782,1,2 +432,160,11201,1,0 +256,196,11620,1,2 +256,196,11830,1,0 +256,196,12039,1,0 +176,316,12458,6,0,B|204:386|320:396|341:307|341:307,1,200,2|0 +80,224,13296,1,2 +256,44,13714,1,0 +432,224,14133,1,2 +112,92,14552,1,0 +256,272,14971,1,2 +400,92,15390,1,0 +456,336,15829,5,4 +256,44,16247,1,0 +56,336,16666,1,2 +256,272,17085,1,0 +88,68,17504,1,2 +424,68,17923,1,0 +168,208,18342,1,2 +256,168,18551,1,0 +344,208,18760,1,0 +176,312,19179,6,0,B|204:382|320:392|341:303|341:303,1,200,2|0 +472,192,20017,1,2 +256,40,20436,1,0 +40,192,20855,1,2 +256,348,21274,1,0 +170,80,21692,2,0,B|179:110|211:135|252:141|252:141|280:151|302:184|280:217|256:223|227:217|199:184|225:151|252:141|252:141|296:135|323:114|337:72,1,400,2|2 +432,288,22949,5,0 +256,352,23368,1,2 +80,288,23787,1,0 +164,159,24205,2,0,B|208:128|256:168|256:168|304:128|348:158|348:158,1,200,2|0 +180,36,25043,1,2 +256,60,25253,1,0 +332,36,25462,1,0 +472,120,25881,6,0,B|402:148|392:264|481:285|481:285,1,200,2|0 +336,372,26719,2,0,B|308:302|192:292|171:381|171:381,1,200,2|0 +40,280,27556,2,0,B|110:252|120:136|31:115|31:115,1,200,2|0 +180,68,28394,5,2 +256,20,28603,1,0 +332,68,28813,1,0 +302,153,29022,1,0 +208,152,29232,1,0 +256,192,29336,12,0,30907 +40,116,47304,5,2 +100,44,47587,1,0 +172,104,47870,2,0,B|200:174|316:184|337:95|337:95,1,200,0|2 +412,44,48719,1,0 +472,116,49002,1,0 +428,304,49568,5,2 +354,355,49851,1,0 +342,265,50134,1,0 +168,265,50700,1,2 +156,355,50983,1,0 +82,304,51266,1,0 +212,171,51832,6,0,B|228:191|256:195|256:195|284:191|300:171,1,100,2|0 +333,86,52397,2,0,B|312:44|256:28|256:28|204:40|177:87,1,200,0|0 +256,112,53246,1,2 +255,112,53529,1,0 +340,252,54095,2,0,B|360:348|360:348,1,100,2|0 +340,252,54661,2,0,B|312:322|196:332|175:243|175:243,1,200,0|2 +151,349,55510,2,0,B|152:348|180:252,1,100,0|0 +256,112,56359,5,2 +300,40,56642,1,0 +212,40,56925,1,0 +184,129,57208,2,0,B|190:177|240:200|272:200|324:184|329:130|329:130,1,200,0|2 +348,227,58057,2,0,B|314:260|257:270|201:259|164:228,1,200,0|0 +104,288,58905,5,2 +256,368,59471,1,0 +408,288,60037,1,2 +408,288,60320,1,0 +256,200,60886,5,0 +336,160,61169,2,0,B|308:95|199:74|172:168|172:168,1,200,2|0 +300,28,62301,1,2 +212,32,62584,1,0 +212,32,63150,1,0 +300,32,63433,1,2 +342,197,63999,6,0,B|325:162|279:159|255:183|255:183|230:158|184:162|169:197|169:197,1,200,0|2 +168,280,64847,2,0,B|185:315|232:318|256:294|256:294|280:318|326:315|344:280|344:280,1,200,0|2 +432,272,65696,5,0 +400,356,65979,1,0 +336,188,66545,1,2 +256,144,66828,1,8 +176,188,67111,1,0 +112,28,67677,5,2 +84,112,67960,1,8 +20,44,68243,1,0 +216,88,68809,2,0,B|229:52|285:46|295:91|295:91,1,100,2|8 +256,164,69375,1,0 +432,112,69941,5,2 +492,48,70223,1,8 +400,28,70506,1,0 +332,196,71072,5,2 +256,244,71355,1,8 +180,196,71638,1,0 +336,284,72204,2,0,B|328:340|376:372|376:372,1,100,2|8 +336,284,72770,2,0,B|308:354|192:364|171:275|171:275,1,200,0|2 +137,371,73619,2,0,B|136:372|185:344|175:284,1,100,8|0 +156,108,74468,5,2 +212,36,74751,1,8 +300,36,75034,1,0 +356,108,75317,1,0 +256,124,75883,5,8 +256,124,76165,1,0 +384,332,76731,1,0 +384,332,77014,1,8 +256,220,77580,5,0 +128,332,78146,1,8 +128,332,78429,1,0 +256,308,78995,5,0 +256,308,79278,1,8 +300,232,79561,1,0 +256,220,79702,1,0 +212,232,79844,1,0 +112,92,80410,1,8 +176,32,80693,2,0,B|202:104|314:115|334:26|334:26,1,200,0|0 +400,92,81542,1,8 +332,248,82107,2,0,B|307:287|271:282|271:282|255:302|255:302|239:282|239:282|203:290|178:248,1,200,0|8 +104,300,82956,5,0 +168,364,83239,1,2 +256,380,83522,1,0 +344,364,83805,1,8 +408,300,84088,1,0 +336,240,84371,6,4,B|310:312|198:323|178:234|178:234,1,200,2|8 +156,152,85220,2,0,B|396:152|396:152,1,200,2|0 +336,64,86069,2,0,B|310:-8|198:-19|178:70|178:70,1,200,8|2 +48,184,87201,6,0,B|8:284|8:284,1,100,8|0 +100,264,87767,2,0,B|124:360|124:360,1,100,2|0 +188,300,88332,2,0,B|276:360|276:360,1,100,8|0 +316,280,88898,5,2 +376,344,89464,1,8 +376,344,89747,1,0 +408,260,90313,1,0 +408,260,90596,1,8 +480,316,91162,1,2 +464,200,91728,6,0,B|504:100|504:100,1,100,8|0 +412,120,92294,2,0,B|388:24|388:24,1,100,2|0 +324,84,92860,2,0,B|236:24|236:24,1,100,8|0 +196,104,93426,1,2 +256,192,93567,12,0,95696 +448,352,96262,5,2 +376,296,96545,1,0 +304,352,96828,1,2 +240,288,97111,1,0 +200,272,97252,1,0 +184,232,97394,1,0 +200,192,97535,1,0 +240,176,97677,1,0 +280,192,97818,1,0 +296,232,97960,5,4 +376,200,98243,2,0,B|488:200|488:200,1,100,2|8 +512,120,98809,2,0,B|512:16|512:16,1,100,0|8 +432,64,99375,5,2 +360,8,99658,1,8 +310,88,99941,2,0,B|340:125|338:201|254:252|176:198|152:135|204:82|204:82,1,300,2|8 +152,8,101073,1,2 +80,64,101356,1,8 +16,128,101639,6,0,B|16:240|16:240,1,100,2|8 +96,272,102205,2,0,B|160:220|260:296|192:368|192:368,1,200,2|0 +288,384,103054,2,0,B|320:352|320:352|400:352|400:352,1,100,8|0 +447,299,103620,1,10 +363,264,103903,1,0 +305,199,104186,2,0,B|287:169|287:138|318:107|318:107|349:76|349:30|287:15|271:45|256:61|256:61|241:45|225:15|163:30|163:76|194:107|194:107|225:138|225:169|208:199,1,500,8|2 +112,208,105884,5,0 +40,160,106167,1,0 +24,200,106309,1,0 +32,248,106450,1,0 +56,280,106592,1,0 +96,296,106733,1,0 +144,292,106875,1,0 +184,272,107016,6,0,B|296:272|296:272,1,100,4|0 +328,352,107582,2,0,B|216:352|216:352,1,100,8|0 +376,272,108148,2,0,B|456:352|456:352,1,100,2|0 +488,264,108714,2,0,B|408:184|408:184,1,100,8|0 +328,196,109280,1,2 +256,144,109563,1,0 +184,196,109846,1,8 +160,108,110129,6,0,B|216:12|216:12,1,100,0|2 +301,25,110695,2,0,B|296:16|352:112,1,100,0|8 +256,144,111262,2,0,B|256:352|256:352,1,200,2|0 +344,368,112111,2,0,B|440:296|440:296,1,100,8|0 +168,368,112677,2,0,B|72:296|72:296,1,100,2|0 +177,242,113243,6,0,B|202:312|316:323|340:236|340:236,1,200,8|2 +256,200,114092,1,0 +320,136,114375,6,0,B|336:96|376:72|424:96|424:96,2,100,8|0|2 +256,72,115224,1,0 +192,136,115507,2,0,B|176:96|136:70|88:96|88:96,2,100,8|8|4 +172,64,124280,5,0 +256,36,124563,1,0 +340,64,124846,1,0 +256,224,125412,1,2 +256,136,125695,1,8 +332,184,125979,6,0,B|404:210|415:322|326:342|326:342,1,200,0|2 +256,376,126828,1,8 +180,340,127111,2,0,B|108:314|97:202|186:182|186:182,1,200,0|2 +256,136,127960,1,8 +256,224,128243,1,0 +380,84,128809,6,0,B|472:28,1,100,2|8 +476,120,129375,2,0,B|368:184|368:184|368:260,1,200,0|0 +456,296,130224,1,8 +384,348,130507,1,0 +128,348,131073,5,2 +56,296,131356,1,8 +144,258,131639,2,0,B|144:184|144:184|36:120,1,200,0|0 +46,32,132488,2,0,B|132:84,1,100,8|0 +256,196,133337,5,2 +300,124,133620,1,8 +212,124,133903,1,0 +184,213,134186,2,0,B|190:261|240:284|272:284|324:268|329:214|329:214,1,200,0|8 +256,196,135035,1,0 +412,284,135601,5,0 +412,284,135884,1,8 +256,372,136450,1,0 +100,284,137016,1,8 +100,284,137299,1,0 +28,229,137582,2,0,B|108:40|108:40,1,200,0|8 +484,163,138714,2,0,B|404:352|404:352,1,200,0|8 +316,348,139563,5,0 +196,44,140412,1,8 +256,196,140979,1,0 +352,96,141545,6,0,B|365:60|421:54|431:99|431:99,1,100,8|0 +296,260,142111,2,0,B|283:296|227:302|217:257|217:257,1,100,0|0 +84,96,142677,2,0,B|97:60|153:54|163:99|163:99,1,100,8|0 +336,176,143526,5,0 +256,132,143809,1,8 +176,176,144092,1,0 +80,328,144658,5,0 +148,268,144941,2,0,B|216:360|216:360,1,100,8|0 +432,328,145790,1,0 +364,268,146073,2,0,B|296:360|296:360,1,100,8|0 +260,182,146922,1,0 +256,264,147205,1,8 +260,180,147488,1,0 +80,56,148054,5,0 +148,116,148337,2,0,B|216:24|216:24,1,100,8|0 +432,56,149186,1,0 +364,116,149469,2,0,B|296:24|296:24,1,100,8|0 +444,204,150318,5,0 +420,292,150601,1,8 +344,340,150884,1,0 +168,340,151450,1,0 +92,292,151733,1,8 +68,204,152016,1,0 +256,216,152865,5,8 +256,216,153148,1,0 +360,92,153714,5,0 +300,24,153997,1,8 +212,24,154280,1,0 +152,92,154563,1,0 +211,267,155129,2,0,B|227:291|305:301|313:244|313:244,1,100,8|0 +256,188,155695,1,0 +165,339,156262,2,0,B|213:380|313:386|352:337|352:337,1,200,8|0 +256,188,157394,1,8 +200,128,157677,2,0,B|170:91|172:15|256:-36|334:18|358:81|306:134|306:134,1,300,0|8 +439,58,159092,5,0 +439,58,159658,5,8 +420,149,159941,1,0 +348,198,160224,1,8 +256,192,160507,1,0 +163,185,160790,1,8 +91,234,161073,1,0 +72,325,161356,1,4 +256,348,162205,5,0 +256,192,162771,5,0 +192,132,163054,1,8 +212,92,163195,1,0 +256,76,163337,1,0 +300,92,163479,1,0 +320,132,163620,1,0 +72,58,164186,5,8 +91,149,164469,1,0 +163,198,164752,1,8 +256,192,165035,1,0 +348,185,165318,1,8 +420,234,165601,1,0 +439,325,165884,1,8 +184,304,166733,6,0,B|190:352|240:375|272:375|324:359|329:305|329:305,1,200 +256,256,167582,1,8 +256,168,167865,1,0 +72,120,168714,5,8 +128,48,168997,1,0 +212,16,169280,1,8 +300,16,169563,1,0 +384,48,169846,1,8 +440,120,170129,1,0 +256,192,170412,12,0,172677 +36,64,173101,5,0 +36,64,173243,1,0 +36,64,173384,1,0 +36,64,173526,1,0 +96,132,173809,1,0 +168,80,174092,1,0 +212,64,174233,1,0 +252,80,174375,1,0 +264,124,174516,1,0 +288,160,174658,1,0 +332,168,174799,1,0 +372,148,174941,5,4 +428,76,175224,2,0,B|496:164|496:164,1,100,0|8 +433,225,175790,2,0,B|404:326|404:326,1,100,0|2 +320,292,176356,1,0 +272,368,176639,1,8 +196,320,176922,2,0,B|160:364|88:360|40:304|80:244|80:244,1,200 +112,168,177771,2,0,B|108:104|44:88|44:88,1,100,8|0 +128,32,178337,6,0,B|236:32|236:32,1,100,2|0 +272,112,178903,1,8 +356,80,179186,2,0,B|396:40|472:52|508:132|436:180|436:180,1,200 +384,232,180035,2,0,B|340:276|372:332|372:332,1,100,8|0 +284,360,180601,2,0,B|164:360,1,100,2|0 +124,300,181167,2,0,B|66:343|-4:276|33:216|72:200|72:200|105:183|173:149|86:10|12:108|12:108,1,400,8|8 +4,16,182582,5,0 +92,8,182865,1,2 +168,56,183148,1,0 +208,76,183290,1,0 +232,112,183431,1,0 +256,152,183573,1,0 +280,112,183714,1,0 +304,76,183856,1,0 +344,56,183997,1,4 +420,8,184280,1,0 +508,16,184563,1,8 +484,102,184846,6,0,B|424:92|391:141|391:141,1,100,0|2 +369,222,185412,2,0,B|439:321|439:321,1,100,0|8 +342,362,185979,2,0,B|316:322|256:308|200:320|168:364,1,200,2|0 +85,303,186828,2,0,B|73:321|143:222,1,100,8|0 +117,136,187394,2,0,B|121:141|88:92|28:102,1,100,2|0 +124,32,187960,5,8 +220,104,188243,2,0,B|199:79|201:28|257:-5|309:30|325:72|290:108|290:108,1,200,2|0 +388,32,189092,1,8 +460,100,189375,5,0 +392,172,189658,1,2 +468,236,189941,1,0 +398,303,190224,2,0,B|383:345|327:359|298:317|327:288|312:232|270:246|256:352|256:352|241:246|199:232|185:288|213:317|185:359|114:345|114:303,1,500,8|0 +68,308,191780,5,0 +26,288,191922,1,0 +16,245,192063,1,0 +40,207,192205,1,0 +81,189,192346,1,0 +110,154,192488,1,0 +125,114,192629,1,0 +104,73,192771,1,0 +62,54,192912,1,0 +21,72,193054,1,4 +256,40,209752,5,2 +144,96,210035,1,0 +184,112,210177,1,0 +212,148,210318,1,0 +216,192,210460,1,0 +256,212,210601,1,0 +296,192,210743,1,0 +300,148,210884,1,0 +328,112,211026,1,0 +368,96,211167,1,4 +256,192,211309,12,0,214563 +256,32,215129,5,2 +236,183,215686,2,0,B|172:199|130:270|147:356|224:381|284:386|309:374|391:320|389:233|322:176|264:182|264:182,1,500,0|0 +256,268,217384,1,0 +448,64,217950,5,0 +256,124,218516,1,0 +256,124,218799,1,0 +64,64,219365,1,0 +64,64,219648,1,0 +176,260,220214,2,0,B|204:195|313:174|340:268|340:268,1,200,0|0 +336,337,221063,2,0,B|308:402|199:423|172:329|172:329,1,200,0|0 +256,299,221912,1,0 +256,40,222478,5,0 +172,164,223044,1,0 +256,204,223327,1,0 +340,164,223610,1,0 +460,300,224176,5,0 +256,360,224742,1,0 +52,300,225308,1,0 +52,300,225591,5,0 +256,360,226157,1,0 +256,360,226440,1,0 +460,300,227006,1,0 +340,164,227572,5,0 +256,204,227855,1,0 +172,164,228138,1,0 +172,76,228421,1,0 +256,32,228704,1,0 +340,76,228987,1,0 +256,120,229270,5,0 +376,252,229836,1,0 +293,287,230119,2,0,B|314:312|312:363|256:396|204:361|188:319|223:283|223:283,1,200 +136,252,230969,1,0 +176,72,231535,2,0,B|204:137|313:158|340:64|340:64,1,200,0|0 +256,32,232384,1,0 +256,32,232667,5,2 +480,192,233233,1,2 +256,356,233799,1,0 +32,192,234365,1,0 +336,320,234931,6,0,B|308:255|199:234|172:328|172:328,1,200,0|0 +436,112,236063,2,0,B|371:140|350:249|444:276|444:276,1,200,0|0 +176,72,237195,2,0,B|204:137|313:158|340:64|340:64,1,200,0|0 +76,272,238327,2,0,B|141:244|162:135|68:108|68:108,1,200,0|0 +256,208,239459,5,0 +472,288,240025,1,0 +424,92,240591,1,0 +256,340,241157,1,0 +88,92,241723,1,0 +40,288,242289,1,0 +256,208,242855,1,0 +256,44,243421,5,0 +460,340,244553,1,0 +52,340,245685,1,0 +81,156,246252,6,0,B|81:80|139:80|196:80|196:156|196:156|196:233|254:233|311:233|311:156|311:156|311:80|368:80|437:80|427:164,1,600 +348,328,248516,2,0,B|300:369|200:375|161:326|161:326,1,200 +168,152,249648,2,0,B|256:200|256:200|364:140,1,200 +257,103,250497,2,0,B|256:64,3,33.3333333333333 +257,103,251063,1,0 +452,228,251912,6,0,B|376:320,1,100,4|0 +256,356,252478,2,0,B|256:236,1,100,8|0 +123,305,253044,2,0,B|60:228,1,100,0|0 +120,156,253610,1,8 +184,61,253893,2,0,B|190:109|240:132|272:132|324:116|329:62|329:62,1,200,0|0 +392,156,254742,1,8 +300,232,255025,5,0 +256,244,255167,1,0 +212,232,255308,1,0 +152,324,255591,1,0 +256,368,255874,1,8 +360,324,256157,1,0 +256,136,256723,5,0 +180,56,257006,2,0,B|120:156,1,100,8|0 +332,56,257572,2,0,B|392:156,1,100,0|0 +256,136,258138,1,8 +184,208,258421,2,0,B|204:248|240:250|256:258|256:258|272:268|280:288|268:302|256:302|256:302|240:302|230:290|240:268|256:260|256:260|268:250|304:252|328:208|328:208,1,300,0|8 +384,272,259553,5,0 +352,296,259695,1,0 +336,332,259836,1,0 +312,364,259978,1,0 +276,380,260119,1,0 +236,380,260261,1,0 +200,364,260402,1,8 +176,332,260544,1,0 +160,296,260685,1,0 +128,272,260827,1,0 +116,236,260969,6,0,B|48:156|137:48|228:96|255:150|255:150|282:196|338:291|530:151|381:54|381:54,1,600,4|8 +304,32,262950,6,0,B|276:16|240:16|240:16,3,50 +216,16,263516,2,0,B|192:28|140:20|140:20,3,50,0|0|8|0 +128,24,264082,2,0,B|100:36|72:76|72:76,3,50 +68,88,264648,2,0,B|68:120|44:152|44:152|48:152,3,50,0|0|8|0 +44,172,265214,2,0,B|32:200|40:248|40:248,3,50 +52,260,265780,2,0,B|64:288|64:324|64:324,3,50,0|0|8|0 +92,336,266346,2,0,B|104:356|144:372|144:372,3,50 +172,364,266912,2,0,B|208:348|248:364|248:364,3,50,0|0|8|0 +260,368,267478,2,0,B|288:372|328:356|328:356,2,50 +256,192,267902,12,4,270025 +128,184,270308,5,0 +148,72,270591,1,8 +256,32,270874,1,0 +364,72,271157,1,8 +384,184,271440,1,0 +256,152,271723,1,8 +201,261,272006,2,0,B|177:291|185:358|259:403|325:356|346:301|306:252|306:252,1,259.999995350838 +396,352,272855,5,8 +256,291,273138,1,0 +116,352,273421,1,8 +200,196,273704,2,0,B|228:163|314:147|339:225|339:225,1,129.999997675419,0|8 +376,112,274270,2,0,B|320:40|192:36|144:112|144:112,1,259.999995350838 +100,252,275119,6,0,B|204:352,1,129.999997675419,8|0 +318,342,275686,2,0,B|412:252,1,129.999997675419,8|0 +275,87,276252,2,0,B|305:44|435:126|257:242|257:242|80:146|188:33|251:98,1,519.999990701676,8|8 +412,252,277667,6,0,B|308:352,1,129.999997675419,0|8 +194,342,278233,2,0,B|100:252,1,129.999997675419,0|8 +230,87,278799,2,0,B|164:90|145:147|174:218|231:190|231:190|260:255|260:255|288:190|288:190|340:215|372:147|366:77|281:88|281:88,1,519.999990701676 +416,240,280214,5,8 +256,348,280497,1,0 +96,240,280780,1,8 +204,64,281063,2,0,B|180:94|188:161|262:206|328:159|349:104|309:55|309:55,1,259.999995350838,0|0 +416,240,281912,6,0,B|480:120,1,129.999997675419,8|0 +304,336,282478,2,0,B|300:305|268:290|247:290|214:300|211:335|211:335,1,129.999997675419,8|0 +34,125,283044,2,0,B|96:240,1,129.999997675419,8|0 +256,40,283893,5,0 +432,156,284176,1,8 +360,348,284459,1,0 +152,348,284742,1,8 +80,156,285025,1,0 +256,188,285308,1,8 +314,247,285874,5,0 +314,247,286016,1,0 +314,247,286157,1,0 +314,247,286299,1,0 +314,247,286440,1,0 +314,247,286582,1,0 +314,247,286723,1,0 +314,247,286865,1,0 +314,247,287006,1,0 +314,247,287148,1,0 +314,247,287289,1,0 +314,247,287431,1,0 +314,247,287572,1,0 +314,247,287714,1,0 +314,247,287855,1,0 +314,247,287997,1,0 +314,247,288138,1,4 +320,40,288421,6,0,B|184:40|184:40,1,129.999997675419,0|8 +420,256,288987,2,0,B|420:120|420:120,1,129.999997675419,0|8 +192,344,289553,2,0,B|328:344|328:344,1,129.999997675419,0|8 +92,128,290119,2,0,B|92:264|92:264,1,129.999997675419,0|8 +256,192,290686,1,0 +256,192,290827,1,0 +256,192,290969,1,8 +408,254,291252,6,0,B|312:350,1,129.999997675419,0|8 +316,38,291818,2,0,B|408:130,1,129.999997675419,0|8 +104,130,292384,2,0,B|195:38,1,129.999997675419,0|8 +195,345,292950,2,0,B|104:254,1,129.999997675419,0|8 +256,192,293516,1,0 +408,130,293799,6,0,B|312:34,1,129.999997675419,8|0 +316,345,294365,2,0,B|408:254,1,129.999997675419,8|0 +104,254,294931,2,0,B|195:345,1,129.999997675419,8|0 +195,38,295497,2,0,B|104:130,1,129.999997675419,8|0 +256,192,296063,5,0 +256,192,296204,1,0 +256,192,296346,1,0 +256,192,296487,1,0 +256,192,296629,1,0 +256,192,296770,1,0 +256,192,296912,1,0 +256,192,297053,1,0 +256,192,297195,1,4 +212,324,297478,6,0,B|215:354|247:369|267:369|301:358|304:324|304:324,1,129.999997675419,0|8 +52,248,298044,2,0,B|84:192|84:192|44:120|44:120,1,129.999997675419,0|8 +312,40,298610,2,0,B|256:72|256:72|184:32|184:32,1,129.999997675419,0|8 +460,248,299176,2,0,B|428:192|428:192|468:120|468:120,1,129.999997675419,0|8 +312,348,299742,6,0,B|256:316|256:316|184:356|184:356,1,129.999997675419,0|8 +80,148,300308,2,0,B|50:151|35:183|35:203|46:237|80:240|80:240,1,129.999997675419,0|8 +300,36,300874,2,0,B|297:66|265:81|245:81|211:70|208:36|208:36,1,129.999997675419,0|8 +432,240,301440,2,0,B|462:237|477:205|477:185|466:151|432:148|432:148,1,129.999997675419,0|8 +256,192,302006,5,0 +136,272,302289,2,0,B|110:298|74:278|74:278|94:314|69:338|69:338,1,129.999997675419,8|0 +256,344,302855,1,8 +376,272,303138,2,0,B|401:298|437:278|437:278|417:314|442:338|442:338,1,129.999997675419,0|8 +256,192,303704,5,0 +136,112,303987,2,0,B|110:86|74:106|74:106|94:70|69:46|69:46,1,129.999997675419,8|0 +256,40,304553,1,8 +376,112,304836,2,0,B|401:86|437:106|437:106|417:70|442:46|442:46,1,129.999997675419,0|8 +256,192,305402,6,0,B|296:256|296:256|360:256,1,129.999997675419,0|8 +256,192,305969,2,0,B|216:256|216:256|152:256,1,129.999997675419,0|12 +196,352,306535,2,0,B|232:352|232:352|256:336|256:336|280:352|280:352|328:352,1,129.999997675419,0|8 +416,256,307101,5,0 +444,120,307384,1,8 +348,40,307667,2,0,B|340:101|275:131|234:131|167:110|161:41|161:41,1,259.999995350838,0|0 +68,120,308516,1,8 +96,256,308799,1,0 +212,348,309082,6,0,B|215:318|247:303|267:303|301:314|304:348|304:348,1,129.999997675419,8|0 +320,192,309648,2,0,B|184:192,1,129.999997675419,8|0 +192,48,310214,2,0,B|256:68|256:68|320:48,1,129.999997675419,8|0 +372,176,310780,2,0,B|256:228|256:228|132:172,1,259.999995350838,12|8 +68,292,311629,1,0 +256,368,311912,1,8 +444,292,312195,1,0 +348,45,312761,6,0,B|341:106|277:136|236:136|169:115|163:46|163:46,1,259.999995350838,0|0 +82,161,313610,2,0,B|124:224|188:240|188:240,1,129.999997675419,8|0 +328,238,314176,2,0,B|388:216|430:161,2,129.999997675419,8|0|8 +256,356,315025,1,0 +256,356,315308,5,12 +328,240,315591,2,0,B|452:304|452:304,1,129.999997675419,0|8 +184,240,316157,2,0,B|60:304|60:304,1,129.999997675419,0|8 +151,91,316723,2,0,B|220:112|256:40|256:40|292:112|364:92,1,259.999995350838,0|0 +256,356,317855,5,0 +380,284,318138,1,8 +380,140,318421,1,0 +256,68,318704,1,8 +132,140,318987,1,0 +132,284,319270,1,8 +256,208,319553,1,0 +256,192,319695,12,0,320686 +256,192,320827,12,0,322101 +255,57,322950,5,0 +115,303,323233,1,8 +256,192,323516,1,0 +396,304,323799,1,8 +256,192,324082,6,0,B|256:292|256:292|312:292|380:264|392:164|368:108|332:60|244:56|164:52|120:144|136:200|120:264|244:292|244:292,1,649.999988377094,4|0 +32,64,337093,5,8 +48,64,337243,1,0 +64,64,337393,1,8 +256,92,337693,2,0,B|256:316|256:316,1,200,8|8 +432,352,338293,2,0,B|368:304|368:224|432:176|432:176,1,200,8|8 +82,178,338893,2,0,B|134:224|144:304|80:352,1,200,8|8 +124,339,339343,5,0 +167,327,339493,1,8 +210,313,339643,1,0 +253,301,339793,1,8 +293,102,340093,2,0,B|313:77|311:26|255:-7|203:28|187:70|222:106|222:106,1,200,8|8 +432,192,340693,1,8 +256,296,340993,1,8 +80,192,341293,1,8 +208,360,341593,5,8 +180,272,341743,1,0 +256,216,341893,1,8 +332,272,342043,1,0 +304,360,342193,1,8 +356,44,342493,6,0,B|152:44,1,200,8|8 +356,124,343093,2,0,B|144:124,2,200,8|8|8 +408,272,343993,1,8 +348,344,344143,1,0 +256,372,344293,1,8 +164,344,344443,1,0 +104,272,344593,1,8 +256,192,344893,1,8 +256,192,345043,12,4,346693 +344,36,346993,5,8 +164,36,347293,1,8 +216,171,347593,2,0,B|230:139|284:129|297:175|297:175,1,100,8|8 +329,245,347893,2,0,B|319:311|199:343|183:245|183:245,2,200,8|8|8 +172,356,348793,1,8 +256,384,348943,1,8 +340,356,349093,1,8 +344,56,349393,6,0,B|432:112|432:112|456:232,1,200,8|8 +168,56,349993,1,8 +168,56,350143,1,0 +168,56,350293,2,0,B|80:112|80:112|56:232,1,200,8|8 +348,328,350893,2,0,B|256:368|256:368|148:320,2,200,8|8|4 +256,172,351793,5,8 +388,48,352093,1,8 +256,172,352393,1,8 +256,260,352543,1,8 +256,172,352693,1,8 +124,48,352993,1,8 +124,238,353293,2,0,B|192:272|192:336|192:336|240:336|256:368|256:368|272:336|320:336|320:336|320:272|393:240,1,400,8|4 +256,40,354193,5,8 +76,340,354493,1,8 +436,340,354793,1,8 +376,272,354943,6,0,B|410:236|410:236|476:237,1,100,0|8 +462,146,355243,2,0,B|412:144|412:144|368:94,1,100,0|8 +296,148,355543,2,0,B|282:116|228:106|215:152|215:152,1,100,0|8 +132,106,355843,2,0,B|99:144|99:144|50:146,1,100,0|8 +51,237,356143,2,0,B|101:236|101:236|136:272,1,100,0|4 +216,236,356443,6,0,B|230:268|284:278|297:232|297:232,1,100,0|8 +332,316,356743,2,0,B|352:288|352:288|384:288|384:288|404:260,2,100,0|8|0 +256,360,357193,1,8 +176,316,357343,2,0,B|156:288|156:288|124:288|124:288|104:260,2,100,0|8|0 +212,232,357793,1,8 +300,232,357943,1,0 +340,152,358093,2,0,B|339:105|339:105|380:70,1,100,8|0 +299,18,358393,2,0,B|256:40|256:40|206:15,1,100,8|0 +132,70,358693,2,0,B|173:105|173:105|172:152,1,100,4|0 +96,200,358993,5,8 +20,248,359143,1,0 +68,324,359293,1,8 +144,276,359443,1,0 +212,340,359593,2,0,B|228:340|228:340|248:332|248:332|256:344|256:344|264:332|264:332|280:340|280:340|296:340,1,100,8|0 +368,276,359893,1,8 +444,324,360043,1,0 +492,248,360193,1,8 +416,200,360343,1,0 +344,144,360493,6,0,B|376:130|386:76|340:63|340:63,1,100,8|0 +256,36,360793,1,8 +168,64,360943,2,0,B|136:78|126:132|172:145|172:145,1,100,0|4 +200,228,361243,1,0 +148,300,361393,2,0,B|100:280|100:280|88:232|88:232,2,100,8|0|8 +211,364,361843,2,0,B|256:341|256:341|306:366,1,100,0|8 +364,300,362143,2,0,B|412:280|412:280|424:232|424:232,2,100,0|8|0 +312,228,362593,1,8 +304,140,362743,5,0 +332,56,362893,1,8 +256,4,363043,1,0 +180,56,363193,1,8 +208,140,363343,1,0 +200,228,363493,5,4 +116,192,363643,1,0 +52,252,363793,1,8 +92,336,363943,1,0 +184,320,364093,1,8 +256,372,364243,1,0 +328,320,364393,1,8 +420,336,364543,1,8 +460,252,364693,1,8 +396,192,364843,1,8 +312,228,364993,1,8 +294,139,365143,6,0,B|280:171|226:181|213:135|213:135,2,100,8|8|8 +295,49,365593,2,0,B|281:17|227:7|214:53|214:53,2,100,8|8|4 +416,181,366193,6,0,B|359:309|142:350|89:164|89:164,1,400,0|8 +117,324,367093,2,0,B|176:384|364:408|416:309|426:294|426:294,2,300,0|0|8 +192,209,368293,2,0,B|160:113|256:41|352:113|320:209,2,300,0|0|8 +96,109,369493,6,0,B|148:5|256:-27|364:5|416:109,2,400,0|8|2 +168,224,370993,2,0,B|200:264|256:276|312:264|344:224,2,200,8|0|8 +32,184,371893,6,0,B|92:224|92:224|104:292|172:316,1,200,0|8 +256,204,372493,1,2 +340,315,372793,2,0,B|408:292|420:224|420:224|480:184,1,200,8|0 +360,120,373393,2,0,B|308:128|308:128|200:84|212:20|256:0|300:20|312:84|204:128|204:128|152:120,1,400,8|8 +40,204,374293,6,0,B|108:192|176:232|184:308,1,200,0|8 +184,308,374743,1,4 +328,308,375043,1,2 +328,308,375193,2,0,B|336:232|404:192|472:204,1,200,8|4 +340,156,375793,6,0,B|276:200|260:256|256:276|256:276|252:256|236:200|172:156,1,300,8|2 +172,84,376393,2,0,B|204:36|256:24|308:36|340:84,2,200,8|0|8 +296,152,377293,6,0,B|312:212|256:236|200:260|216:320,1,200,0|8 +216,150,377893,2,0,B|200:212|256:236|312:260|295:320,2,200,0|8|2 +256,16,378793,1,8 +140,96,379093,6,0,B|92:240|232:308|256:352|256:352|280:308|420:240|372:96,1,600,0|8 +304,120,380143,2,0,B|256:144|208:120,1,100,2|0 +68,100,380593,6,0,B|96:304|292:280|324:388,1,400,8|8 +188,385,381493,2,0,B|220:280|416:304|444:100,1,400,2|0 +304,72,382393,1,8 +184,148,382693,2,0,B|212:192|256:216|256:216|300:192|328:148,1,200,0|8 +208,72,383293,1,0 +256,204,383593,1,8 +374,272,383893,6,0,B|342:312|342:312|296:328,1,100,8|8 +216,328,384193,2,0,B|169:312|169:312|137:272,1,100,8|8 +137,195,384493,2,0,B|169:155|169:155|216:140,1,100,8|8 +296,140,384793,2,0,B|342:155|342:155|374:195,1,100,8|0 +436,232,385093,6,0,B|484:112|484:112|448:48,1,200,4|8 +380,8,385543,1,0 +348,80,385693,2,0,B|296:56|296:56|256:72|256:72|216:56|216:56|164:80,1,200,0|8 +132,8,386143,1,0 +62,50,386293,2,0,B|28:112|28:112|76:232,1,200,0|8 +120,300,386743,6,0,B|176:356|256:372|336:356|392:300,1,300,0|8 +424,228,387343,1,2 +344,240,387493,2,0,B|312:280|256:296|200:280|168:240,1,200,0|8 +88,228,387943,1,0 +140,168,388093,1,0 +256,140,388243,6,0,B|256:88,6,50,8|0|8|0|8|0|4 +256,140,389293,1,4 +296,212,389893,6,0,B|284:339|148:363|68:339,2,300,6|2|8 +256,140,390943,1,0 +216,212,391093,2,0,B|227:339|363:363|443:339,2,300,0|2|8 +368,268,392293,6,0,B|412:280|460:252|460:196|460:196|460:128,1,200,0|8 +472,56,392743,2,0,B|428:44|384:68|380:124|380:124|380:192,1,200 +300,192,393193,2,0,B|300:72|300:72|300:16|256:-4|212:16|212:72|212:72|212:192,1,400,8|8 +132,191,393943,2,0,B|132:124|132:124|128:68|84:44|40:56,1,200,2|0 +52,131,394393,2,0,B|52:196|52:196|52:252|100:280|144:268,1,200,8|0 +296,316,394993,6,0,B|440:264|424:68,1,300,8|2 +344,88,395593,2,0,B|364:244|256:288|148:244|168:88,1,400,8|8 +87,71,396343,2,0,B|72:264|216:316,1,300,2|8 +204,108,397093,6,0,B|336:108|336:108|400:140,1,200,0|8 +360,212,397543,1,2 +308,276,397693,2,0,B|176:276|176:276|112:244,1,200,0|8 +152,172,398143,1,0 +128,96,398293,6,0,B|48:32,2,100,8|0|8 +176,32,398743,2,0,B|256:92|256:92|336:32,1,200,0|8 +384,96,399193,2,0,B|464:32,2,100,8|0|4 +404,256,399793,6,0,B|320:280|320:280|348:340|304:388,1,200,8|0 +256,324,400243,1,0 +205,384,400393,2,0,B|164:340|192:280|192:280|108:256,1,200,8|0 +124,180,400843,2,0,B|204:204|204:204|240:216|260:236|264:244|256:256|248:244|252:236|272:216|308:204|308:204|388:180,1,300,2|2 +364,20,401593,6,0,B|292:24|228:68|216:132,1,200,8|0 +296,132,402043,2,0,B|284:68|220:24|148:20,1,200,2|0 +148,100,402493,1,0 +256,216,402793,1,8 +364,100,403093,6,0,B|384:116|400:144|400:204|400:204|400:292,1,200,0|8 +256,356,403693,1,0 +112,290,403993,2,0,B|112:204|112:204|112:144|128:116|148:100,1,200,8|4 +188,256,404593,6,0,B|200:200|256:164|312:200|324:256,2,200,8|0|8 +112,228,405343,1,0 +40,188,405493,2,0,B|60:160|94:147|128:148|156:160|156:160|176:136|216:120,1,200,2|8 +296,120,405943,2,0,B|336:136|356:160|356:160|384:148|417:147|452:160|472:188,1,200 +400,228,406393,1,8 +256,296,406693,6,0,B|336:344|336:344|448:328,2,200,0|8|2 +256,216,407443,1,0 +256,136,407593,2,0,B|176:88|176:88|64:104,2,200,8|0|8 +324,176,408343,5,0 +324,256,408493,1,0 +256,300,408643,1,0 +188,256,408793,1,0 +188,176,408943,1,0 +256,136,409093,1,4 +392,52,409393,6,0,B|396:144|432:192|496:204,1,200,0|8 +496,124,409843,2,0,B|433:135|397:183|393:275,1,200,2|0 +472,272,410293,2,0,B|468:328|432:360|372:360|372:360|316:360,1,200,0|8 +296,284,410743,1,0 +216,284,410893,1,0 +191,360,411043,6,0,B|140:360|140:360|80:360|44:328|40:272,1,200 +118,275,411493,2,0,B|114:183|78:135|16:124,1,200,2|8 +17,203,411943,2,0,B|80:192|116:144|120:52,1,200 +200,72,412393,6,0,B|196:140|256:164|316:140|312:72,1,200,8|0 +376,136,412843,2,0,B|348:208|256:244|164:208|136:136,1,300,2|0 +25,32,413593,5,8 +24,31,413893,2,0,B|61:43|61:43|53:76|53:76|86:88|86:88|73:121|73:121|94:141|94:141|90:178|-3:154|-27:269|49:343|155:302|155:192|155:192|217:192|217:192|217:228|217:228|225:273|267:302|267:302|295:314|308:351|287:384|253:392|221:384|200:351|213:314|241:302|241:302|283:273|291:228|291:228|291:192|291:192|353:192|353:192|353:302|459:343|537:269|513:154|418:178|414:141|414:141|435:121|435:121|422:88|422:88|455:76|455:76|447:43|447:43|484:31,1,1600,0|4 +340,104,416593,5,0 +256,104,416743,1,0 +300,32,416893,1,0 +212,32,417043,1,0 +172,104,417193,1,0 +212,172,417343,1,0 +300,172,417493,1,4 +460,216,417793,5,0 +392,328,418093,1,4 +252,380,418393,1,0 +252,380,418543,1,0 +252,380,418693,1,4 +120,328,418993,1,8 +52,216,419293,1,0 +208,144,419593,5,8 +296,144,419743,1,0 +328,59,419893,2,0,B|318:-7|198:-39|182:59|182:59,1,200,0|8 +128,132,420343,2,0,B|212:176|212:176|212:304,1,200 +300,281,420793,2,0,B|300:176|300:176|384:132,1,200,8|0 +472,156,421243,1,0 +408,220,421393,5,8 +352,384,421693,2,0,B|288:384|288:384|256:368|256:368|224:384|224:384|136:384|136:384,1,200,0|8 +104,220,422293,1,0 +156,48,422593,5,8 +180,140,422743,2,0,B|220:136|248:100|256:81|256:81|264:100|288:132|336:140,1,200 +356,48,423193,1,8 +256,204,423493,5,4 +324,368,423793,2,0,B|396:300,1,100,8|0 +188,368,424243,2,0,B|116:300,1,100,0|8 +216,153,424693,2,0,B|164:204|200:264|235:275|268:272|296:280|352:228|333:181|292:148|292:148,2,300,0|0|8 +348,44,425893,2,0,B|256:8|256:8|160:44,1,200,0|8 +53,188,426493,6,0,B|120:201|143:318|50:338|50:338,1,200,0|8 +216,360,427093,2,0,B|230:328|284:318|297:364|297:364,1,100,8|8 +344,288,427393,2,0,B|368:244|368:244|344:200,1,100,8|8 +296,132,427693,2,0,B|282:164|228:174|215:128|215:128,1,100,8|8 +168,204,427993,2,0,B|144:247|144:247|168:291,1,100,8|8 +256,248,428293,1,4 +456,340,428593,6,0,B|389:327|366:210|459:190|459:190,1,200,8|8 +336,56,429193,1,8 +256,92,429343,1,0 +176,56,429493,1,8 +256,228,429793,1,8 +334,269,429943,2,0,B|315:331|198:354|174:264|174:264,1,200 +120,332,430393,1,8 +105,147,430693,2,0,B|131:68|197:12|304:11|381:62|408:154,1,400,8|8 +392,332,431593,1,8 +184,248,431893,6,0,B|197:291|228:301|256:310|256:310|279:322|279:350|256:361|232:350|232:322|256:310|256:310|279:301|310:291|328:248,2,300,8|8|8 +328,136,433093,2,0,B|314:92|283:82|256:73|256:73|232:61|232:33|256:22|279:33|279:61|256:73|256:73|232:82|201:92|184:136,2,300,8|8|8 +64,60,434293,5,4 +256,248,434743,1,8 +448,60,435193,1,8 +309,184,435493,2,0,B|378:252|330:333|283:348|239:344|201:354|133:282|153:215|208:180|208:180,1,400,4|8 +86,328,436393,5,8 +256,248,436693,1,0 +426,328,436993,1,0 +304,160,437293,1,0 +328,72,437443,1,0 +256,24,437593,1,0 +184,72,437743,1,0 +208,160,437893,1,4 +336,304,438193,2,0,B|317:366|200:389|176:299|176:299,1,200 +49,138,438793,1,0 +149,31,439093,6,0,B|166:122|257:140|257:140|330:158|366:213|366:267|293:340|220:340|147:267|147:213|184:158|257:140|257:140|348:122|366:31,1,800 +453,145,440593,5,0 +370,358,440893,1,0 +142,357,441193,1,0 +59,145,441493,1,0 +256,20,441793,1,0 +179,207,442093,6,0,B|198:145|315:122|339:212|339:212,1,200 +256,256,442543,1,0 +256,352,442693,1,4 +64,332,452293,6,0,B|64:252|64:252|64:204|96:172|136:172,1,200,4|0 +212,84,452893,2,0,B|212:164|212:164|212:212|180:244|140:244,1,200,8|0 +300,300,453493,6,0,B|300:219|300:219|300:171|332:139|371:139,1,200 +448,50,454093,2,0,B|448:130|448:130|448:178|416:210|376:210,1,200,8|0 +200,232,454693,6,0,B|176:184|176:184|132:184|100:172|80:136|84:96,1,200 +136,36,455143,1,2 +160,108,455293,2,0,B|212:108|212:108|256:128|256:128|300:108|300:108|352:108,1,200,8|0 +376,36,455743,1,2 +428,96,455893,2,0,B|432:136|412:172|380:184|336:184|336:184|312:232,1,200 +128,272,456493,2,0,B|152:324|216:332|244:304|256:296|256:296|268:304|296:332|360:324|384:272,1,300,8|0 +428,208,457093,6,0,B|388:180|336:196|312:240|312:240|256:208|256:208|200:240|200:240|176:196|124:180|84:208,1,400,4|8 +28,152,457843,2,0,B|80:116|136:108|176:124|176:124|216:140,1,200 +295,140,458293,2,0,B|336:124|336:124|376:108|432:116|484:152,2,200,2|0|8 +156,232,459193,6,0,B|356:232,1,200 +424,188,459643,1,2 +476,252,459793,1,0 +432,320,459943,2,0,B|404:372|404:372|324:372|324:372|296:320,1,200,0|2 +216,318,460393,2,0,B|188:372|188:372|108:372|108:372|80:320,1,200,0|2 +36,252,460843,1,0 +88,188,460993,1,0 +216,92,461293,6,0,B|176:52,2,50 +296,92,461593,2,0,B|336:52,2,50 +296,172,461893,2,0,B|384:172|384:172|424:172|456:192|472:232,1,200,4|8 +464,312,462343,2,0,B|424:304|400:280|388:252|388:252|320:252|320:252|296:272,1,200,0|2 +216,272,462793,2,0,B|192:252|192:252|124:252|124:252|112:280|88:304|48:312,1,200,8|0 +40,230,463243,2,0,B|56:192|88:172|128:172|128:172|216:172,1,200,0|2 +216,92,463693,2,0,B|216:56|216:56|216:28|240:4|272:4|296:28|296:56|296:56|296:92,1,200,0|8 +424,192,464293,6,0,B|464:264|464:264|384:352,1,200,0|8 +127,351,464893,2,0,B|48:264|48:264|88:192,1,200,0|8 +140,252,465343,1,0 +164,176,465493,2,0,B|204:188|236:244|204:300|204:300|308:300|308:300|276:244|308:188|348:176,1,400,2|0 +324,100,466243,1,0 +256,144,466393,1,8 +188,104,466543,1,0 +256,56,466693,1,0 +408,108,466993,6,0,B|400:152|364:180|320:184|320:184|284:228|256:216|228:228|192:184|192:184|148:180|112:152|104:108,1,400,8|8 +24,244,467893,2,0,B|148:256|148:256|176:284|212:292,1,200,0|8 +299,292,468343,2,0,B|336:284|364:256|364:256|488:244,1,200,2|0 +448,324,468793,6,0,B|404:328|404:328|336:372|256:388|176:372|108:328|108:328|64:324,1,400,8|8 +96,252,469543,2,0,B|200:208|216:104,1,200,0|2 +295,103,469993,2,0,B|312:208|416:252,1,200,8|0 +360,312,470443,5,0 +296,268,470593,1,0 +256,204,470743,1,0 +216,268,470893,1,0 +152,312,471043,1,0 +216,360,471193,1,0 +296,360,471343,1,0 +380,384,471493,6,0,B|436:368|456:304|432:252|376:236,1,200,4|0 +396,160,471943,1,2 +320,184,472093,2,0,B|300:136|300:136|256:116|256:116|212:136|212:136|192:184,1,200,0|8 +116,160,472543,1,2 +134,236,472693,2,0,B|80:252|56:304|76:368|132:384,1,200,0|8 +156,312,473143,2,0,B|356:312,1,200 +336,236,473593,1,8 +256,236,473743,1,0 +176,236,473893,6,0,B|96:240|44:192|32:124,1,200,2|8 +72,56,474343,2,0,B|152:52|204:100|216:168,1,200 +296,166,474793,2,0,B|308:100|360:52|440:56,1,200,8|2 +479,125,475243,2,0,B|468:192|416:240|336:236,1,200 +256,236,475693,1,0 +212,304,475843,1,0 +256,372,475993,1,0 +300,304,476143,1,0 +256,236,476293,6,0,B|256:32,1,200,4|0 +336,36,476743,1,2 +416,36,476893,2,0,B|416:76|384:112|340:116|340:116|340:160|340:200,1,200,0|8 +172,195,477493,2,0,B|172:160|172:116|172:116|128:112|96:76|96:36,1,200,0|8 +176,36,477943,2,0,B|224:44|244:88|244:88|268:88|268:88|288:44|336:36,1,200 +352,116,478393,6,0,B|332:152|316:156|296:164|296:164|296:220|296:220|296:288,2,200,8|2|8 +160,116,479293,2,0,B|180:152|196:156|216:164|216:164|216:220|216:220|216:288,2,200,0|8|0 +120,184,480043,5,0 +140,260,480193,1,0 +216,288,480343,1,0 +256,356,480493,1,0 +296,288,480643,1,0 +372,260,480793,1,0 +392,184,480943,1,0 +377,106,481093,6,0,B|449:94|503:168|451:239,1,200,4|0 +392,184,481543,2,0,B|341:252|395:327|467:315,1,200,2|0 +412,388,481993,2,0,B|312:372|304:316|320:268|280:280|256:260|232:280|192:268|208:316|200:372|100:388,1,400,8|8 +43,315,482743,2,0,B|116:327|170:252|120:184,1,200,2|0 +59,238,483193,2,0,B|8:168|62:94|135:106,1,200,8|0 +296,264,483793,6,0,B|372:264|372:264|400:240|400:240|432:256|432:256|456:244|456:244|480:244,2,200,8|0|8 +256,196,484543,1,2 +216,120,484693,2,0,B|140:120|140:120|112:144|112:144|80:128|80:128|56:140|56:140|32:140,2,200,0|8|0 +351,32,485593,6,0,B|276:104|360:264|480:68|540:348|412:348|352:348|352:348|295:348,1,500,8|0 +216,348,486493,2,0,B|160:348|160:348|100:348|-28:348|32:68|152:264|236:104|160:32,1,500,2|0 +104,88,487393,5,8 +256,204,487693,1,2 +408,88,487993,1,8 +188,164,488293,5,8 +188,84,488443,1,8 +256,40,488593,1,8 +324,84,488743,1,8 +324,164,488893,1,8 +256,204,489043,1,8 +188,248,489193,1,8 +324,248,489343,1,8 +256,292,489493,6,0,B|256:340,8,50,8|0|8|0|8|0|8|0|8 +324,248,490243,1,0 +296,172,490393,1,8 +216,172,490543,1,0 +188,248,490693,1,4 +176,80,490993,6,0,B|195:18|312:-5|336:85|336:85,1,200,8|8 +396,252,491593,2,0,B|392:192|442:160|442:160,1,100,8|0 +488,240,491893,1,8 +340,340,492193,1,8 +295,265,492343,2,0,B|317:234|297:196|271:187|253:182|228:183|180:218|200:250|227:280|227:280,1,200 +172,340,492793,1,8 +24,240,493093,1,8 +73,165,493243,2,0,B|118:192|116:252,1,100,0|8 +169,78,493693,6,0,B|223:78|223:78|255:46|255:46|287:78|287:78|343:78,1,200,8|8 +375,277,494293,6,0,B|346:370|169:405|133:269|133:269,2,300,8|8|8 +315,126,495493,2,0,B|347:77|317:21|282:6|248:-1|209:2|143:56|170:103|211:148|211:148,2,300,8|8|8 +184,248,496693,2,0,B|197:291|228:301|256:310|256:310|279:322|279:350|256:361|232:350|232:322|256:310|256:310|279:301|310:291|328:248,2,300,8|8|8 +101,109,497893,6,0,B|104:69|146:40|188:52|188:52|217:4|256:6|297:6|321:51|321:51|363:38|412:70|414:121,1,400,8|8 +339,285,498793,2,0,B|332:301|311:315|290:309|290:309|275:333|255:336|232:331|221:310|221:310|202:316|175:303|169:277,2,200,8|8|8 +256,86,499693,5,0 +184,138,499843,1,0 +212,222,499993,1,0 +300,222,500143,1,0 +328,138,500293,1,4 +424,276,500593,5,0 +256,372,500893,1,0 +88,276,501193,1,0 +88,276,501343,1,0 +88,276,501493,1,0 +160,92,501793,1,0 +160,92,501943,1,0 +352,92,502243,1,0 +352,92,502393,1,0 +256,248,502693,5,0 +301,170,502843,2,0,B|283:152|255:151|229:152|210:170,1,100 +338,292,503293,2,0,B|316:352|200:377|175:288|175:288,1,200 +91,154,503893,6,0,B|44:150|21:102|10:42|65:7|131:-10|181:42|166:103|166:103,2,300 +421,154,505093,2,0,B|468:150|491:102|502:42|447:7|381:-10|331:42|346:103|346:103,2,300 +213,259,506293,2,0,B|161:310|197:370|232:381|265:378|293:386|349:334|330:287|289:254|289:254,2,300 +170,74,507493,6,0,B|224:74|224:74|256:42|256:42|288:74|288:74|344:74,1,200 +448,224,508093,1,0 +330,360,508393,2,0,B|315:315|255:300|255:300|195:315|182:360,1,200 +64,224,508993,1,0 +256,152,509293,5,0 +328,100,509443,1,0 +300,16,509593,1,0 +212,16,509743,1,0 +184,100,509893,1,4 +256,264,510193,1,0 +376,72,510493,1,0 +136,76,510793,1,0 +380,73,511093,6,0,B|445:147|468:248|406:346|328:392|268:399|149:402|86:328|25:223|84:96|152:64,1,800 +256,196,512593,1,0 +256,196,512893,5,0 +180,240,513043,1,0 +180,328,513193,1,0 +256,372,513343,1,0 +332,328,513493,1,0 +332,240,513643,1,0 +336,152,513793,6,0,B|368:138|378:84|332:71|332:71,1,100,0|0 +256,32,514093,1,0 +176,72,514243,2,0,B|144:86|134:140|180:153|180:153,1,100 +256,196,514543,1,0 +182,251,514693,2,0,B|256:319|256:319|326:249,1,200,4|0 +335,255,515068,1,0 +344,263,515143,1,0 +352,271,515218,1,0 +360,279,515293,2,0,B|415:295|465:274|495:228|488:171,1,200,8|0 +398,188,515743,1,0 +386,180,515818,1,0 +374,172,515893,2,0,B|318:155|268:176|238:222|245:279,2,200,8|0|8 +356,28,516793,1,8 +176,24,517093,5,0 +80,176,517393,1,8 +88,180,517468,1,0 +96,184,517543,1,0 +104,188,517618,1,0 +112,192,517693,2,0,B|168:175|218:196|248:242|241:299,1,200,8|0 +144,288,518143,1,0 +136,292,518218,1,0 +128,296,518293,2,0,B|73:312|23:291|-7:245|0:188,1,200,8|8 +48,100,518743,1,0 +48,100,518818,1,0 +48,100,518893,2,0,B|124:100|124:100|168:100|208:72|216:32,1,200,0|8 +464,284,519493,2,0,B|388:284|388:284|344:284|304:312|296:352,1,200,4|8 +216,352,519943,6,0,B|168:352,2,50,0|0|8 +296,32,520393,2,0,B|344:32,2,50,8|0|0 +204,68,520693,2,0,B|248:120|248:120|380:120,1,200,0|8 +308,316,521293,2,0,B|264:264|264:264|132:264,1,200,0|8 +24,96,521893,6,0,B|56:136|56:136|156:124|156:124|188:160,1,200,0|8 +256,232,522343,2,0,B|256:280,2,50,0|0|8 +324,159,522643,1,0 +324,159,522793,2,0,B|356:124|356:124|456:136|456:136|488:96,1,200,8|8 +428,16,523243,5,4 +24,288,523693,5,8 +84,368,523843,1,4 +256,120,524293,5,4 +452,156,524593,2,0,B|424:100,2,50,8|0|0 +504,240,524893,2,0,B|456:280|360:252|348:176,1,200,8|0 +163,176,525493,2,0,B|152:252|56:280|8:240,1,200,0|8 +60,156,525943,1,0 +60,156,526093,2,0,B|88:100,2,50,8|0|0 +60,156,526393,1,0 +300,336,526693,6,0,B|340:280|340:280|384:292|440:284|460:248,1,200,0|8 +388,180,527143,2,0,B|404:128,2,50,0|0|8 +124,180,527593,2,0,B|108:128,2,50,8|0|0 +52,249,527893,2,0,B|72:284|128:292|172:280|172:280|212:336,1,200,0|8 +256,140,528493,1,0 +256,140,528793,2,0,B|256:40,2,100,8|0|4 +460,192,529393,6,0,B|528:192,2,50,8|0|0 +360,192,529693,1,8 +52,188,529993,2,0,B|-16:188,2,50,8|0|0 +152,192,530293,1,8 +312,308,530593,1,8 +256,108,530893,1,0 +200,308,531193,1,8 +172,112,531493,6,0,B|172:60|212:16|276:12|316:52,1,200,0|8 +340,272,532093,2,0,B|340:324|300:368|236:372|196:332,1,200,0|8 +56,192,532543,5,0 +56,192,532618,1,0 +56,192,532693,1,0 +8,100,532843,1,4 +460,192,533293,5,8 +504,284,533443,1,4 +256,192,550693,12,4,553093 +48,116,553393,6,0,B|114:126|146:246|48:262|48:262,1,200,0|0 +183,36,553993,2,0,B|193:102|313:134|329:36|329:36,1,200,0|0 +464,262,554593,2,0,B|398:252|366:132|464:116|464:116,1,200,0|0 +300,352,555193,1,0 +328,268,555343,1,0 +256,212,555493,1,0 +184,268,555643,1,0 +212,352,555793,1,0 +108,200,556093,5,0 +168,40,556393,1,0 +344,40,556693,1,0 +404,200,556993,1,0 +256,288,557293,1,0 +256,108,557593,5,0 +212,186,557743,1,0 +301,185,557893,1,4 +174,312,558193,2,0,B|183:356|231:356|255:340|255:340|279:356|327:356|335:308,1,200 +470,164,558793,2,0,B|425:158|418:126|411:107|417:88|417:88|398:95|379:89|351:80|344:41,1,200 +166,43,559393,2,0,B|160:80|132:89|113:95|94:88|94:88|100:107|93:126|86:158|42:164,1,200 +152,288,559993,2,0,B|192:384,1,100 +256,320,560293,1,4 +321,380,560443,2,0,B|360:288,1,100 +295,119,560893,2,0,B|317:88|297:50|271:41|253:36|228:37|180:72|200:104|227:134|227:134,1,200 +56,200,561493,5,0 +128,272,561643,1,0 +164,298,561718,1,0 +181,339,561793,1,0 +256,264,561943,1,0 +331,339,562093,1,0 +348,298,562168,1,0 +384,272,562243,1,0 +432,176,562393,1,0 +360,88,562543,1,0 +256,56,562693,1,4 +152,88,562843,1,0 +80,176,562993,1,0 +213,343,563293,6,0,B|199:287|199:287|254:259|254:259|310:287|310:287|296:343,1,240.000005722046 +437,158,563893,2,0,B|471:123|471:123|465:38|381:32|381:32|341:72,1,240.000005722046 +166,67,564493,2,0,B|131:32|131:32|47:38|41:123|41:123|76:158,1,240.000005722046 +200,248,564943,2,0,B|176:304|176:304|200:360,1,120.000002861023,0|4 +312,358,565243,2,0,B|336:304|336:304|312:248,1,120.000002861023 +256,4,565693,5,0 +456,96,565993,1,0 +456,296,566293,1,0 +256,376,566593,1,0 +56,296,566893,1,0 +56,96,567193,1,0 +191,119,567343,2,0,B|231:167|191:231,1,120.000002861023 +320,229,567643,2,0,B|280:165|320:117,1,120.000002861023 +354,331,568093,6,0,B|303:321|271:347|254:380|254:380|238:347|205:321|155:331,1,240.000005722046 +157,90,568693,2,0,B|207:99|239:73|256:40|256:40|272:73|305:99|355:90,1,240.000005722046 +477,296,569293,1,0 +256,204,569593,1,0 +212,348,569743,1,0 +332,264,569893,1,0 +180,264,570043,1,0 +300,348,570193,1,0 +32,296,570493,1,0 +160,96,570793,6,0,B|182:21|324:-6|353:102|353:102,2,240.000005722046 +112,336,571693,2,0,B|161:288|160:224,1,120.000002861023 +256,280,571993,1,0 +352,229,572143,2,0,B|351:288|400:336,1,120.000002861023,0|4 +356,64,572593,6,0,B|306:48|289:14|289:14|256:31|222:14|222:14|205:48|155:64|155:64,1,240.000005722046,0|0 +376,192,573193,2,0,B|136:192,1,240.000005722046 +356,320,573793,2,0,B|306:336|289:370|289:370|256:353|222:370|222:370|205:336|155:320|155:320,1,240.000005722046 +153,67,574393,6,0,B|200:83|208:137|192:165|172:188|144:206|71:203|65:157|70:105|70:105,1,259.999995350838,0|4 +359,67,574993,2,0,B|311:83|303:137|319:165|339:188|367:206|440:203|446:157|441:105|441:105,1,259.999995350838 +367,348,575593,2,0,B|297:348|297:348|256:306|256:306|215:348|215:348|143:348,1,259.999995350838 +64,128,576193,1,0 +364,64,576493,2,0,B|328:10|256:-25|183:10|147:64,1,259.999995350838 +196,179,576943,2,0,B|224:208|286:211|320:176,1,129.999997675419,0|4 +138,298,577393,2,0,B|171:339|257:370|336:339|373:299,1,259.999995350838 +440,144,577993,5,0 +256,32,578293,1,0 +72,144,578593,1,0 +180,308,578893,1,0 +256,360,579043,1,0 +336,296,579193,1,0 +304,216,579343,1,0 +208,216,579493,1,4 +128,152,579643,5,0 +92,56,579793,2,0,B|172:44|212:104|212:104,1,129.999997675419 +303,99,580093,2,0,B|347:46|420:56,1,129.999997675419 +384,152,580393,1,0 +304,216,580543,1,0 +410,291,580693,5,4 +400,311,580768,1,0 +383,327,580843,1,0 +364,339,580918,1,0 +343,345,580993,1,0 +322,347,581068,1,0 +299,342,581143,1,0 +278,333,581218,1,0 +260,320,581293,1,4 +234,333,581368,1,0 +213,342,581443,1,0 +190,347,581518,1,0 +169,345,581593,1,0 +148,339,581668,1,0 +129,327,581743,1,0 +112,311,581818,1,0 +102,291,581893,1,4 +188,252,582043,5,0 +324,252,582193,1,0 +256,188,582343,1,0 +352,152,582493,1,0 +160,152,582643,1,0 +256,92,582793,1,0 +256,92,582943,1,0 +160,52,583093,6,0,B|96:52|32:108|44:192|104:240,1,259.999995350838,0|0 +256,312,583543,1,0 +408,240,583693,2,0,B|468:192|480:108|416:52|352:52,1,259.999995350838 +352,152,584143,1,0 +340,296,584293,2,0,B|316:228|256:200|256:200|196:228|172:296,1,259.999995350838 +256,312,584743,1,0 +172,294,584893,2,0,B|52:244,1,129.999997675419 +36,152,585193,2,0,B|156:204,1,129.999997675419 +236,232,585493,6,0,B|252:180|216:136|216:136|72:72,1,259.999995350838 +292,108,585943,2,0,B|408:44,1,129.999997675419 +320,184,586243,2,0,B|452:184,1,129.999997675419 +312,268,586543,1,0 +312,268,586693,6,0,B|432:316,1,129.999997675419,4|0 +332,376,586993,2,0,B|296:328|292:256|360:184|444:200,1,259.999995350838 +180,376,587593,2,0,B|216:328|220:256|152:184|68:200,1,259.999995350838 +96,124,588043,2,0,B|172:128|216:172,1,129.999997675419 +416,124,588343,2,0,B|340:128|296:172,1,129.999997675419 +140,52,588793,2,0,B|200:64|256:108|256:108|312:64|372:52,1,259.999995350838 +256,12,589243,1,0 +256,12,589393,1,0 +372,224,589693,5,0 +140,224,589993,1,0 +292,360,590293,2,0,B|337:315|305:263|275:254|246:256|222:249|174:294|190:335|226:364|226:364,2,259.999995350838 +364,141,591193,1,0 +256,101,591343,1,0 +148,141,591493,1,4 +363,54,591793,6,0,B|327:0|255:-35|182:0|146:54,2,259.999995350838 +256,103,592543,1,0 +362,150,592693,2,0,B|326:204|254:239|181:204|145:150,1,259.999995350838 +138,299,593143,1,0 +380,297,593443,1,0 +379,296,593593,1,0 +368,184,593893,6,0,B|308:180|244:244|252:324|304:376,1,259.999995350838 +380,288,594343,1,0 +272,320,594493,2,0,B|224:272|152:288,1,129.999997675419 +64,216,594793,2,0,B|20:272|52:340,1,129.999997675419 +144,200,595093,6,0,B|204:204|268:140|260:60|208:8,1,259.999995350838 +132,92,595543,1,0 +240,64,595693,2,0,B|288:112|360:96,1,129.999997675419 +448,168,595993,2,0,B|492:112|460:44,2,129.999997675419,0|0|4 +136,320,596593,1,0 +136,320,596743,1,0 +376,320,597043,1,0 +376,320,597193,1,0 +376,320,597493,6,0,B|424:268|422:191|375:126|311:112,1,259.999995350838 +136,320,597943,2,0,B|87:268|89:191|136:126|200:112,1,259.999995350838 +256,48,598393,1,0 +196,348,598693,2,0,B|256:392|316:348,1,129.999997675419 +256,272,598993,1,0 +256,272,599143,1,0 +308,144,599293,6,0,B|304:76|344:16|432:0|492:60,1,259.999995350838 +412,132,599743,1,0 +336,276,599893,2,0,B|340:204|256:148|172:204|176:276,1,259.999995350838 +100,132,600343,1,0 +25,55,600493,2,0,B|79:0|167:15|207:75|203:143,1,259.999995350838 +256,272,600943,1,0 +256,192,601018,12,0,602293 +256,192,602368,12,0,603493 +180,344,603793,6,0,B|205:286|205:286|257:262|257:262|310:286|310:286|334:344,1,240.000005722046 +488,176,604393,2,0,B|434:168|426:130|417:108|424:85|424:85|402:93|379:86|346:75|337:29,1,240.000005722046 +172,32,604993,2,0,B|164:76|131:86|108:93|86:85|86:85|93:108|85:130|76:168|24:176,1,240.000005722046 +168,320,605593,1,0 +256,360,605743,1,0 +344,320,605893,1,4 +453,145,606193,5,0 +256,20,606493,1,0 +59,145,606793,1,0 +142,357,607093,1,0 +370,358,607393,1,0 +256,188,607693,1,0 +315,98,607843,2,0,B|259:68|186:76|145:139|146:199,1,240.000005722046 +197,285,608293,2,0,B|250:314|325:307|366:246|366:183,1,240.000005722046 +464,288,608893,5,0 +256,156,609193,1,0 +48,288,609493,1,0 +166,112,609793,2,0,B|184:57|256:39|256:39|328:57|344:112,1,240.000005722046 +320,192,610243,2,0,B|320:256|255:272|255:272|182:292|198:370,1,240.000005722046 +314,370,610693,2,0,B|330:292|256:272|256:272|192:256|192:192,1,240.000005722046,4|0 +384,80,611293,5,0 +128,80,611593,1,0 +128,304,611893,1,0 +384,304,612193,1,0 +256,128,612493,1,0 +165,185,612643,2,0,B|217:196|249:228|257:252|257:252|265:228|289:196|352:183,1,240.000005722046 +346,280,613093,6,0,B|327:359|188:394|160:272|160:272,1,240.000005722046 +64,88,613693,1,0 +228,32,613993,2,0,B|256:24|256:24|284:32,4,60.0000014305115 +164,136,614443,2,0,B|200:136|200:136|224:112|224:112|256:152|256:152|288:112|288:112|312:136|312:136|352:136,1,240.000005722046 +420,208,614893,1,0 +368,300,615043,1,0 +256,344,615193,1,0 +144,300,615343,1,0 +92,208,615493,1,4 +420,48,615793,5,0 +92,48,616093,1,0 +92,336,616393,1,0 +420,336,616693,1,0 +256,40,616993,1,0 +88,200,617293,1,0 +160,272,617443,1,0 +256,304,617593,1,0 +352,272,617743,1,0 +424,200,617893,1,0 +164,76,618193,6,0,B|183:155|322:190|350:68|350:68,1,240.000005722046 +345,308,618793,2,0,B|323:230|188:196|161:312|161:312,1,240.000005722046 +388,192,619393,1,0 +124,192,619693,1,0 +200,108,619843,2,0,B|256:128|256:128|312:108,1,120.000002861023 +256,16,620143,1,0 +396,48,620293,6,0,B|451:66|469:138|469:138|451:210|396:226,1,240.000005722046 +116,336,620893,2,0,B|61:318|43:246|43:246|61:174|116:158,1,240.000005722046 +388,280,621493,5,0 +256,48,621793,1,0 +124,280,622093,1,0 +56,196,622243,2,0,B|116:172|116:172|136:116|136:116,1,120.000002861023 +202,192,622543,2,0,B|256:218|256:218|309:192,1,120.000002861023 +377,119,622843,2,0,B|376:116|396:172|396:172|456:196,1,120.000002861023 +400,288,623143,1,0 +304,344,623293,1,0 +256,360,623368,1,0 +208,344,623443,1,0 +128,272,623593,5,0 +160,168,623743,1,0 +256,128,623893,1,0 +352,168,624043,1,0 +384,272,624193,1,0 +256,248,624343,1,0 +352,168,624493,5,0 +368,112,624568,1,0 +352,64,624643,1,0 +312,24,624718,1,0 +256,8,624793,1,0 +200,24,624868,1,0 +160,64,624943,1,0 +144,112,625018,1,0 +160,168,625093,1,4 +84,244,625243,5,0 +152,336,625393,1,0 +256,364,625543,1,0 +360,336,625693,1,0 +428,244,625843,1,0 +428,140,625993,1,0 +360,48,626143,1,0 +256,20,626293,1,0 +152,48,626443,1,0 +84,140,626593,1,0 +206,158,626743,6,0,B|222:129|256:125|289:129|305:158,1,120.000002861023 +376,240,627043,1,0 +304,320,627193,2,0,B|287:349|254:353|220:349|204:320,1,120.000002861023 +136,240,627493,1,0 +256,248,627643,1,0 +312,144,627793,5,0 +312,144,627868,1,0 +312,144,627943,1,0 +344,48,628093,1,0 +256,0,628243,1,0 +168,48,628393,1,0 +200,144,628543,1,0 +96,168,628693,5,0 +88,272,628843,1,0 +192,320,628993,1,0 +256,232,629143,1,0 +312,144,629293,1,0 +416,168,629443,1,0 +424,272,629593,1,0 +320,320,629743,1,0 +256,232,629893,1,0 +200,144,630043,5,0 +208,40,630193,1,0 +256,16,630268,1,0 +304,40,630343,1,0 +312,144,630493,1,0 +416,200,630643,2,0,B|488:304,1,120.000002861023 +408,376,630943,2,0,B|339:277,1,120.000002861023 +256,344,631243,1,0 +172,277,631393,2,0,B|104:376,1,120.000002861023 +27,298,631693,2,0,B|96:200,1,120.000002861023 +93,91,631993,5,0 +206,63,632143,2,0,B|222:33|255:29|289:33|305:63,1,120.000002861023 +419,91,632443,1,0 +352,176,632593,1,0 +360,184,632668,1,0 +368,192,632743,1,0 +400,296,632893,2,0,B|456:278|456:278|476:222,1,120.000002861023 +308,356,633193,2,0,B|289:356|289:356|265:346|265:346|256:360|256:360|246:346|246:346|227:356|227:356|208:356,1,120.000002861023 +35,222,633493,2,0,B|55:278|55:278|112:296,1,120.000002861023 +184,96,633793,5,0 +256,272,633943,1,0 +328,96,634093,1,0 +160,200,634243,1,0 +352,200,634393,1,0 +256,32,634543,1,0 +256,168,634693,5,4 +352,328,634993,5,0 +400,88,635293,1,0 +160,40,635593,1,0 +112,248,635893,1,0 +276,357,636193,5,0 +431,167,636493,1,0 +242,12,636793,1,0 +102,173,637093,1,0 +205,350,637393,5,0 +425,244,637693,1,0 +319,23,637993,1,0 +124,110,638293,1,0 +138,310,638593,5,0 +383,315,638893,1,0 +389,71,639193,1,0 +175,59,639493,1,0 +99,249,639793,5,0 +319,358,640093,1,0 +427,138,640393,1,0 +239,38,640693,1,0 +89,186,640993,5,0 +252,369,641293,1,0 +435,206,641593,1,0 +297,43,641893,1,0 +107,116,642193,5,0 +177,351,642493,1,0 +412,281,642793,1,0 +304,240,642943,5,0 +256,224,643018,1,0 +208,240,643093,1,0 +136,155,643243,2,0,B|187:189|256:155|307:103|307:51|290:17|256:0|221:17|204:51|204:103|256:155|324:189|376:155,1,480.000011444092 +40,44,671736,6,0,B|40:164,1,100,8|8 +120,184,672236,2,0,B|120:76,1,100,8|0 +200,126,672736,2,0,B|217:74|276:53|341:72|356:135,1,200,4|8 +436,72,673486,1,0 +484,148,673736,1,8 +412,204,673986,2,0,B|408:244|424:280|464:296|464:296,1,100,0|8 +404,368,674486,5,0 +325,319,674736,2,0,B|299:294|264:292|232:320|232:320|204:348|157:346|140:313,1,200,8|8 +64,352,675486,2,0,B|16:316|12:208|68:160,1,200 +122,106,676236,2,0,B|174:90|190:38,1,100,8|0 +267,84,676736,2,0,B|243:131|281:187|370:171|373:107|349:70,1,200,8|8 +428,28,677486,5,0 +488,96,677736,1,8 +424,160,677986,1,0 +484,225,678236,2,0,B|470:274|470:274|486:322,1,100,8|0 +412,368,678736,2,0,B|308:368,1,100,8|0 +252,300,679236,1,8 +184,360,679486,5,0 +108,312,679736,2,0,B|48:328|4:284|4:204|68:188|68:188,1,200,8|8 +148,148,680486,2,0,B|194:117|188:60,1,100,0|8 +268,20,680986,1,0 +332,80,681236,2,0,B|448:48,1,100,8|0 +484,124,681736,2,0,B|388:152,1,100,8|0 +376,244,682236,6,0,B|492:212,1,100,8|0 +496,304,682736,1,8 +328,373,683236,2,0,B|313:319|252:296|191:320|176:383,1,200,8|8 +88,328,683986,2,0,B|16:248|48:136|48:136,1,200 +120,192,684736,2,0,B|124:75|216:16,1,200,8|8 +280,80,685486,5,0 +360,32,685736,2,0,B|480:32|480:32,1,100,8|0 +488,120,686236,2,0,B|440:128|440:168|488:176,1,100,8|0 +432,248,686736,2,0,B|480:256|480:296|432:304,1,100,8|0 +360,360,687236,1,8 +288,304,687486,5,0 +216,360,687736,2,0,B|104:360|104:360,1,100,8|0 +72,280,688236,2,0,B|184:280|184:280,1,100,8|0 +136,200,688736,2,0,B|85:203|44:162|36:100|88:60,1,200,12|8 +169,24,689486,1,0 +256,56,689736,2,0,B|360:36,1,100,8|0 +424,88,690236,6,0,B|444:188,1,100,8|0 +368,232,690736,1,8 +216,344,691236,2,0,B|223:318|255:306|287:319|295:351,1,100,8|0 +144,232,692236,1,8 +68,186,692486,2,0,B|88:88,1,100,0|8 +256,200,693236,5,8 +336,72,693736,1,8 +256,24,693986,1,0 +176,72,694236,1,8 +177,236,694736,2,0,B|198:284|254:310|321:285|336:232,1,200,8|8 +408,280,695486,1,0 +408,280,695736,5,8 +256,368,696236,1,8 +104,280,696736,1,4 +104,104,697236,1,8 +256,16,697736,1,8 +408,104,698236,5,8 +408,104,698486,1,0 +408,104,698736,1,8 +338,275,699236,2,0,B|315:320|259:346|192:321|176:269,1,200,8|8 +175,175,699986,2,0,B|198:130|254:104|321:129|337:181,1,200 +257,228,700736,5,8 +256,48,701236,1,8 +176,320,701736,1,8 +256,360,701986,1,0 +336,320,702236,1,8 +352,144,702736,2,0,B|287:143|287:143|255:127|255:127|223:143|223:143|151:143,1,200,8|8 +300,32,703736,5,8 +212,32,703986,1,0 +60,121,704486,6,0,B|94:207|94:207|50:304,1,200,8|0 +49,304,705236,1,8 +124,344,705486,2,0,B|169:247|169:247|257:217,1,200,8|0 +452,120,706236,1,8 +452,120,706486,2,0,B|417:207|417:207|462:304,1,200,8|0 +463,304,707236,1,8 +387,343,707486,2,0,B|342:247|342:247|254:217,1,200,8|0 +158,53,708236,1,8 +158,53,708486,2,0,B|223:52|223:52|255:36|255:36|287:52|287:52|359:52,1,200,8|0 +352,138,709236,1,8 +352,138,709486,2,0,B|287:139|287:139|255:155|255:155|223:139|223:139|151:139,1,200,8|0 +256,285,710236,5,8 +100,340,710486,1,8 +204,340,710736,5,0 +180,304,710861,1,0 +180,260,710986,1,0 +212,220,711111,1,0 +256,208,711236,1,0 +300,220,711361,1,0 +332,260,711486,1,0 +332,304,711611,1,0 +308,340,711736,1,0 +412,340,711986,37,0 +452,164,712486,21,0 +370,97,712736,2,0,B|340:54|262:14|173:45|137:104,1,259.999995350838,4|8 +370,287,713736,2,0,B|340:330|262:370|173:339|137:280,1,259.999995350838,0|8 +194,214,714486,2,0,B|258:263|325:207,1,129.999997675419,0|8 +256,144,714986,1,8 +96,288,715486,6,0,B|32:240|16:192|16:192|32:128|112:80,1,259.999995350838,8|8 +256,192,716236,1,8 +416,288,716486,2,0,B|480:240|496:192|496:192|480:128|400:80,1,259.999995350838,8|0 +200,76,717236,6,0,B|214:55|253:35|298:50|316:80,1,129.999997675419,8|0 +256,336,717736,1,8 +160,180,717986,2,0,B|174:243|252:283|341:252|352:168,2,259.999995350838,8|8|8 +320,344,719236,6,0,B|184:344,1,129.999997675419,8|0 +440,168,719736,2,0,B|360:36,1,129.999997675419,8|0 +72,168,720236,2,0,B|152:36,1,129.999997675419,8|0 +256,216,720736,2,0,B|256:296|256:296|360:292|368:200|340:136|304:100|196:92|156:152|149:244|204:280,1,519.999990701676,4|0 +348,360,722236,5,8 +256,384,722486,1,0 +172,360,722736,1,8 +256,208,723236,1,8 +299,22,723736,1,8 +214,25,723986,2,0,B|173:80|209:160|333:145|330:56|296:19,1,259.999995350838,8|8 +404,172,724986,5,8 +344,240,725236,1,8 +256,260,725486,1,0 +168,236,725736,1,8 +108,172,725986,1,0 +140,340,726486,2,0,B|170:383|248:423|337:392|373:333,1,259.999995350838,8|0 +316,268,727236,2,0,B|252:317|185:261,1,129.999997675419,8|0 +256,176,727736,5,8 +160,128,727986,1,0 +192,96,728111,1,0 +212,48,728236,1,0 +256,20,728361,1,0 +300,48,728486,1,0 +320,96,728611,1,0 +352,128,728736,1,4 +400,224,728986,6,0,B|400:288|400:288|464:352,1,129.999997675419 +352,368,729486,1,0 +279,292,729736,2,0,B|297:263|279:224|217:231|219:275|235:294,1,129.999997675419 +160,368,730236,1,0 +61,333,730486,2,0,B|107:286|107:286|107:222,1,129.999997675419 +195,167,730986,2,0,B|256:143|256:143|316:167,1,129.999997675419 +379,84,731486,2,0,B|256:35|256:35|135:84,1,259.999995350838 +207,173,732236,5,0 +305,174,732486,2,0,B|373:206|373:323|285:353|256:323|256:323|212:279|226:235|285:235|299:279|256:323|256:323|212:353|138:309|138:206|214:170,1,649.999988377094 +162,79,733986,1,0 +350,79,734486,1,0 +365,286,734986,2,0,B|335:243|257:203|168:234|132:293,1,259.999995350838 +195,370,735736,6,0,B|259:419|326:363,2,129.999997675419 +137,282,736486,1,0 +79,182,736736,2,0,B|202:174|221:20|153:-13|84:20|84:89|187:123|256:20|256:20|309:109|412:102|451:11|334:-40|296:20|329:166|352:180|459:186,1,779.999986052513,4|0 +344,248,738486,5,0 +256,192,738736,1,0 +168,248,738986,1,0 +355,355,739486,2,0,B|280:360|256:287|256:287|232:360|155:355,1,259.999995350838 +80,288,740236,1,0 +58,186,740486,6,0,B|28:128|76:66|76:66|158:49|196:100,1,259.999995350838 +256,184,741236,2,0,B|256:216|256:216|240:232|240:232|272:240|272:240|256:256|256:256|256:280,2,129.999997675419 +316,99,741986,2,0,B|354:49|436:66|436:66|484:128|454:186,1,259.999995350838 +315,349,742986,6,0,B|251:398|184:342,1,129.999997675419 +205,246,743486,1,0 +307,246,743736,1,0 +368,160,743986,5,0 +324,156,744111,1,0 +288,132,744236,1,0 +256,100,744361,1,0 +224,132,744486,1,0 +188,156,744611,1,0 +144,160,744736,1,4 +256,12,751736,5,8 +181,62,751986,1,0 +209,150,752236,1,8 +301,150,752486,1,0 +329,62,752736,1,4 +328,243,753236,2,0,B|313:297|252:320|191:296|176:233,1,200,8|8 +344,356,754236,5,8 +256,384,754486,1,0 +168,356,754736,1,8 +126,200,755236,1,8 +183,128,755486,2,0,B|233:132|253:72|253:72|273:132|336:128,1,200 +385,200,756236,1,8 +296,240,756486,2,0,B|288:216|259:203|225:213|217:244,1,100,0|8 +256,372,757236,5,8 +416,228,757736,1,8 +356,56,758236,1,8 +156,56,758736,1,8 +84,228,759236,1,8 +141,298,759486,5,0 +200,225,759736,1,4 +183,187,759861,1,0 +188,145,759986,1,0 +213,111,760111,1,0 +256,94,760236,1,0 +298,111,760361,1,0 +323,145,760486,1,0 +328,187,760611,1,0 +311,225,760736,1,0 +370,298,760986,5,0 +308,368,761236,2,0,B|196:368|196:368,1,100,8|0 +176,280,761736,2,0,B|200:272|213:243|203:209|172:201,1,100,8|0 +256,152,762236,1,8 +336,204,762486,2,0,B|310:211|300:245|313:274|337:282,1,100,0|8 +344,60,763236,2,0,B|256:12|256:12|168:60,1,200,8|8 +169,139,763986,2,0,B|256:186|256:186|344:138,1,200 +256,100,764736,5,8 +256,260,765236,1,8 +120,344,765736,1,8 +256,260,766236,1,8 +392,344,766736,1,8 +446,187,767236,5,8 +385,127,767486,1,0 +368,40,767736,1,8 +296,100,767986,2,0,B|289:126|255:136|226:123|218:99,1,100,0|8 +143,40,768486,1,0 +126,127,768736,1,12 +65,192,768986,1,0 +126,256,769236,5,8 +144,343,769486,1,0 +218,284,769736,2,0,B|226:261|255:248|289:258|296:284,1,100,8|0 +368,343,770236,1,8 +385,256,770486,1,0 +446,192,770736,1,8 +376,38,771236,5,8 +300,84,771486,2,0,B|324:131|286:187|197:171|194:107|218:70,1,200 +135,38,772236,1,8 +100,120,772486,5,0 +40,52,772736,1,8 +57,216,773236,1,8 +181,324,773736,2,0,B|196:375|260:399|323:374|338:309,1,200,8|8 +454,216,774736,1,8 +472,52,775236,5,8 +412,120,775486,1,0 +376,38,775736,1,8 +300,200,776236,2,0,B|324:153|286:97|197:113|194:177|218:214,1,200,8|8 +328,320,777236,2,0,B|278:316|258:376|258:376|238:316|175:320,1,200,8|8 +100,120,778236,5,8 +40,52,778486,1,0 +135,38,778736,1,8 +337,193,779236,2,0,B|314:148|258:122|191:147|175:199,1,200,8|8 +177,284,779986,2,0,B|193:332|254:358|327:334|336:280,1,200 +256,240,780736,5,8 +340,56,781236,1,8 +172,56,781736,1,8 +256,104,781986,1,0 +340,56,782236,1,8 +352,228,782736,2,0,B|287:229|287:229|255:245|255:245|223:229|223:229|151:229,1,200,8|8 +360,352,783736,5,8 +256,384,783986,1,8 +152,352,784236,1,8 +173,256,784486,2,0,B|185:285|256:336|325:292|350:244,1,200,8|0 +256,196,785236,1,0 +309,100,785486,2,0,B|336:52|291:-27|183:-4|172:77|210:125,1,240.000005722046 +112,168,786236,1,0 +128,272,786486,6,0,B|168:232|213:263|213:263|256:289|303:260|303:260|356:231|392:283|392:283,1,279.99999332428 +400,367,787236,1,0 +400,367,787486,2,0,B|354:412|303:377|303:377|254:347|200:380|200:380|140:413|99:354|99:354,1,320 +92,204,788236,5,0 +92,204,788486,2,0,B|135:142|257:127|384:123|441:224|441:224,1,359.999982833863 +442,299,789236,1,0 +442,299,789486,2,0,B|390:365|256:382|119:384|55:280|55:280,1,400 +106,180,790236,5,0 +32,87,790486,1,0 +160,64,790736,1,0 +200,100,790861,1,0 +216,156,790986,1,0 +208,212,791111,1,0 +256,244,791236,1,0 +304,212,791361,1,0 +296,156,791486,1,0 +312,100,791611,1,0 +356,64,791736,1,0 +484,96,791986,5,0 +412,196,792236,1,0 +412,196,792361,1,0 +412,196,792486,1,0 +370,318,792736,2,0,B|340:361|262:401|173:370|137:311,1,259.999995350838,4|0 +316,168,793736,6,0,B|345:220|295:307|176:281|164:192|206:139,1,259.999995350838 +160,68,794486,1,0 +256,8,794736,1,0 +352,68,794986,1,0 +360,240,795486,2,0,B|402:240|402:240|442:240|458:272|458:296|458:296|458:320|442:352|402:352|402:352|354:352|354:352,1,259.999995350838 +256,320,796236,1,0 +152,352,796486,2,0,B|158:352|110:352|110:352|70:352|54:320|54:296|54:296|54:272|70:240|110:240|110:240|152:240,1,259.999995350838 +200,144,797236,6,0,B|256:176|256:176|312:144,1,129.999997675419 +312,48,797736,2,0,B|255:15|255:15|199:47,1,129.999997675419 +368,232,798486,2,0,B|254:297|254:297|142:232,1,259.999995350838 +88,320,799236,6,0,B|200:384,1,129.999997675419 +311,384,799736,2,0,B|424:320,1,129.999997675419 +475,229,800236,1,0 +437,131,800486,1,0 +334,121,800736,2,0,B|354:55|308:3|254:-3|182:5|140:90|200:154|254:187|254:187|312:220|421:280|335:420|211:416|164:335|177:272,1,779.999986052513,4|0 +72,290,802486,5,0 +13,204,802736,1,0 +143,53,803236,2,0,B|173:10|251:-30|340:1|376:60,1,259.999995350838 +370,149,803986,2,0,B|340:192|262:232|173:201|137:142,1,259.999995350838 +192,360,804986,6,0,B|336:360,1,129.999997675419 +324,268,805486,2,0,B|180:268,1,129.999997675419 +128,177,805986,2,0,B|408:177,1,259.999995350838 +206,47,806986,6,0,B|216:16|254:0|298:13|307:47,1,129.999997675419 +304,152,807486,1,0 +256,168,807611,1,0 +208,152,807736,1,0 +128,216,807986,1,0 +160,256,808111,1,0 +208,280,808236,1,0 +256,288,808361,1,0 +304,280,808486,1,0 +352,256,808611,1,0 +384,216,808736,1,4 +464,128,808986,6,0,B|496:256,1,129.999997675419 +320,352,809486,2,0,B|192:384,1,129.999997675419 +16,254,809986,2,0,B|48:128,1,129.999997675419 +197,23,810486,6,0,B|168:76|217:160|334:136|346:48|305:-4,1,259.999995350838 +416,64,811236,1,0 +370,149,811486,2,0,B|340:192|262:232|173:201|137:142,1,259.999995350838 +96,64,812236,1,0 +48,160,812486,2,0,B|96:272|224:320|288:320|416:272|464:160,1,519.999990701676 +512,256,813736,1,0 +512,256,813986,5,0 +256,368,814486,1,0 +0,256,814986,1,0 +0,256,815236,1,0 +72,176,815486,5,0 +104,216,815611,1,0 +110,268,815736,1,0 +208,312,815986,1,0 +256,296,816111,1,0 +304,312,816236,1,0 +402,268,816486,1,0 +408,216,816611,1,0 +440,176,816736,1,4 +360,120,816986,6,0,B|391:110|407:72|394:28|360:19,1,129.999997675419 +256,0,817486,2,0,B|256:128,1,129.999997675419 +152,120,817986,2,0,B|121:110|105:72|118:28|152:19,2,129.999997675419 +215,203,818736,1,0 +300,206,818986,2,0,B|341:261|305:341|181:326|184:237|218:200,1,259.999995350838 +352,352,819986,1,0 +256,384,820236,1,0 +160,352,820486,1,0 +92,159,820986,5,0 +149,69,821236,1,0 +256,36,821486,1,0 +362,69,821736,1,0 +419,159,821986,1,0 +349,362,822486,5,0 +307,353,822611,1,0 +273,328,822736,1,0 +238,302,822861,1,0 +213,260,822986,1,0 +196,226,823111,1,0 +187,183,823236,1,0 +187,140,823361,1,0 +213,106,823486,1,0 +256,89,823611,1,0 +298,106,823736,1,0 +324,140,823861,1,0 +324,183,823986,1,0 +315,226,824111,1,0 +298,260,824236,1,0 +273,302,824361,1,0 +238,328,824486,1,0 +204,353,824611,1,0 +162,362,824736,1,4 +40,240,824986,6,0,B|71:230|87:192|74:148|40:139,1,129.999997675419 +205,34,825486,2,0,B|215:65|253:81|297:68|306:34,1,129.999997675419 +472,144,825986,2,0,B|441:154|425:192|438:236|472:245,1,129.999997675419 +307,350,826486,2,0,B|297:319|259:303|215:316|206:350,1,129.999997675419 +128,56,827236,5,0 +384,56,827736,1,0 +148,348,828236,1,0 +256,296,828486,1,0 +364,348,828736,1,0 +24,104,829236,2,0,B|93:112|135:188|104:277|12:281,1,259.999995350838 +148,36,830236,5,0 +256,88,830486,1,0 +364,36,830736,1,0 +488,280,831236,2,0,B|419:272|377:196|408:107|500:103,1,259.999995350838 +306,327,832236,2,0,B|296:358|258:374|214:361|205:327,1,129.999997675419 +256,192,832736,5,4 +64,48,833236,1,0 +184,280,833736,5,0 +152,152,833986,1,0 +256,80,834236,1,0 +360,152,834486,1,0 +328,280,834736,1,4 +448,48,835236,5,0 +256,192,835736,1,0 +64,336,836236,5,0 +152,240,836486,2,0,B|121:230|105:192|118:148|152:139,1,129.999997675419 +360,240,837236,2,0,B|391:230|407:192|394:148|360:139,1,129.999997675419 +440,336,838236,1,0 +358,236,838486,2,0,B|305:220|265:252|257:292|257:292|249:252|205:218|151:239,1,259.999995350838 +72,336,839236,1,0 +24,216,839486,5,0 +72,96,839736,1,0 +200,32,839986,1,0 +184,80,840111,1,0 +208,128,840236,1,0 +256,144,840361,1,0 +304,128,840486,1,0 +328,80,840611,1,0 +312,32,840736,1,4 +440,96,840986,1,0 +488,216,841236,1,0 +390,300,841486,5,0 +341,342,841611,1,0 +328,280,841736,1,0 +184,280,841986,1,0 +171,342,842111,1,0 +122,300,842236,1,0 +87,178,842486,5,0 +195,106,842736,2,0,B|207:67|256:59|256:59|288:43|272:11|240:11|224:43|256:59|256:59|302:67|321:111,1,259.999995350838 +424,176,843486,1,0 +424,176,843611,1,0 +424,176,843736,1,0 +376,296,843986,1,0 +256,352,844236,1,0 +136,296,844486,1,0 +136,296,844611,1,0 +136,296,844736,1,4 +88,176,844986,1,0 +204,101,845236,2,0,B|214:70|252:54|296:67|305:101,1,129.999997675419 +384,352,845986,5,0 +360,304,846111,1,0 +304,288,846236,1,0 +256,320,846361,1,0 +208,288,846486,1,0 +152,304,846611,1,0 +128,352,846736,1,4 +208,192,846986,5,0 +256,208,847111,1,0 +304,192,847236,1,0 +400,128,847486,1,0 +416,80,847611,1,0 +384,32,847736,1,0 +328,24,847861,1,0 +288,56,847986,1,0 +256,88,848111,1,0 +224,56,848236,1,0 +184,24,848361,1,0 +128,32,848486,1,0 +96,80,848611,1,0 +112,128,848736,1,0 +152,248,848986,5,0 +152,248,849111,1,0 +152,248,849236,1,0 +144,376,849486,1,0 +144,376,849611,1,0 +144,376,849736,1,0 +256,320,849986,1,0 +256,320,850111,1,0 +256,320,850236,1,0 +368,376,850486,1,0 +368,376,850611,1,0 +368,376,850736,1,0 +360,248,850986,1,0 +360,248,851111,1,0 +360,248,851236,1,0 +256,192,851486,5,0 +256,192,851611,1,0 +256,192,851736,1,4 +256,320,851986,1,4 +95,186,852486,6,0,B|159:153|207:57|191:25|127:-7|95:25|63:89|223:153|255:81|255:81|287:25|255:-7|223:25|255:81|255:81|285:136|415:121|383:89|479:-39|301:-25|223:89|431:196|431:196,1,909.999983727932,4|2 +312,280,854486,2,0,B|298:259|259:239|214:254|196:284,1,129.999997675419,0|2 +256,381,854986,1,0 +370,173,855486,2,0,B|340:130|262:90|173:121|137:180,1,259.999995350838,2|0 +208,28,856236,1,2 +304,28,856486,1,0 +256,192,856611,12,0,858236 +256,192,859486,12,4,860736 +191,69,860986,6,0,B|204:43|254:19|302:36|324:74,1,149.999995529652,0|0 +448,172,861486,2,0,B|384:212|384:212|368:304,1,149.999995529652 +256,376,861986,1,0 +140,285,862236,2,0,B|128:212|128:212|64:172,1,149.999995529652 +169,47,862736,2,0,B|216:69|216:133|216:133|256:153|256:153|296:133|296:133|292:69|347:45,1,299.999991059304 +301,358,863736,1,0 +211,358,863986,2,0,B|157:296|201:201|345:218|341:321|296:365,1,299.999991059304 +73,188,864986,5,0 +138,89,865236,1,0 +256,48,865486,1,0 +373,89,865736,1,0 +438,188,865986,1,0 +178,345,866486,2,0,B|212:367|256:331|256:331|284:311|284:279|256:259|228:279|228:311|256:331|256:331|296:367|336:343,1,299.999991059304 +321,225,867236,2,0,B|308:199|258:175|210:192|188:230,1,149.999995529652 +96,148,867736,5,0 +128,108,867861,1,0 +164,80,867986,1,0 +212,64,868111,1,0 +256,56,868236,1,0 +300,64,868361,1,0 +348,80,868486,1,0 +384,108,868611,1,0 +416,148,868736,1,4 +256,224,868986,5,0 +208,364,869236,1,0 +328,276,869486,1,0 +184,276,869736,1,0 +304,364,869986,1,0 +256,224,870236,5,0 +128,112,870486,2,0,B|160:61|249:17|350:49|391:118,1,299.999991059304 +256,200,871236,1,0 +126,291,871486,2,0,B|158:341|247:386|348:354|389:284,1,299.999991059304 +256,200,872236,1,0 +113,156,872486,6,0,B|35:111|52:28|108:-8|156:-7|216:29|209:95|209:95|224:62|256:174|288:62|304:94|304:94|292:32|356:-16|412:-6|465:38|473:120|387:160,1,749.999977648259,0|0 +372,298,873986,2,0,B|311:279|266:316|256:361|256:361|247:316|197:277|136:301,1,299.999991059304 +256,20,874986,5,0 +128,116,875236,1,0 +184,260,875486,1,0 +328,260,875736,1,0 +384,116,875986,1,0 +256,156,876236,5,0 +256,156,876361,1,0 +256,156,876486,1,0 +256,156,876611,1,0 +256,156,876736,1,4 +256,308,876986,5,0 +400,356,877236,1,0 +488,236,877486,1,0 +400,116,877736,1,0 +256,156,877986,1,0 +256,308,878236,1,0 +112,364,878486,1,0 +24,236,878736,1,0 +112,116,878986,1,0 +408,64,879486,6,0,B|459:96|503:185|471:286|402:327,1,299.999991059304 +256,192,880236,1,0 +104,64,880486,2,0,B|53:96|9:185|41:286|110:327,1,299.999991059304 +322,237,881236,2,0,B|309:263|259:287|211:270|189:232,1,149.999995529652 +320,147,881736,2,0,B|307:121|257:97|209:114|187:152,1,149.999995529652 +388,304,882486,6,0,B|356:355|267:399|166:367|125:298,1,299.999991059304 +256,192,883236,1,0 +184,60,883486,1,0 +256,32,883611,1,0 +328,60,883736,1,0 +396,196,883986,1,0 +341,251,884111,1,0 +326,324,884236,1,0 +256,360,884361,1,0 +185,324,884486,1,0 +170,251,884611,1,0 +115,196,884736,1,4 +256,192,884861,12,0,886236 +128,128,933524,5,2 +214,104,933953,1,0 +152,42,934381,1,2 +65,65,934810,1,0 +42,152,935238,1,2 +104,214,935667,1,0 +190,190,936095,1,2 +212,228,936310,1,0 +256,244,936524,1,0 +300,228,936738,1,0 +323,189,936952,5,2 +408,170,937381,1,0 +470,232,937809,1,2 +447,319,938238,1,0 +360,342,938666,1,2 +298,280,939095,1,0 +323,189,939523,1,2 +384,256,939952,1,0 +160,112,940380,5,2 +212,38,940809,1,0 +300,38,941237,1,2 +352,112,941666,1,0 +292,181,942094,2,0,B|272:153|230:153|219:184|219:184,1,84.9999964535238,2|0 +256,260,942951,1,2 +212,288,943165,1,0 +228,340,943380,1,0 +280,340,943594,1,0 +300,292,943808,1,2 +396,256,944236,6,0,B|468:192,1,84.9999964535238,0|2 +416,32,945093,2,0,B|376:108,1,84.9999964535238,0|2 +256,48,945950,1,0 +135,107,946379,2,0,B|96:32,1,84.9999964535238,2|0 +52,199,947236,2,0,B|116:256,1,84.9999964535238,2|0 +292,328,948093,6,0,B|272:356|230:356|219:325|219:325,1,84.9999964535238,2|0 +324,208,948950,2,0,B|352:124,1,84.9999964535238,2|0 +188,208,949807,2,0,B|160:124,1,84.9999964535238,2|0 +256,64,950449,1,0 +256,64,950664,5,2 +400,160,951092,1,0 +340,324,951521,1,2 +172,324,951949,1,0 +112,160,952378,1,2 +256,64,952806,1,0 +256,200,953235,5,2 +188,328,953663,1,0 +256,356,953877,1,0 +324,328,954092,1,2 +428,228,954520,1,0 +392,92,954948,1,2 +256,40,955377,1,0 +120,92,955805,1,2 +84,228,956234,1,0 +220,208,956662,6,0,B|240:236|282:236|293:205|293:205,1,84.9999964535238,2|0 +292,352,957519,2,0,B|272:324|230:324|219:355|219:355,1,84.9999964535238,2|0 +124,244,958376,1,2 +256,140,958805,1,0 +392,244,959233,1,2 +412,80,959662,1,0 +256,264,960090,1,2 +100,80,960519,1,0 +100,80,960733,1,0 +100,80,960947,5,2 +256,348,961376,1,0 +412,80,961804,1,2 +100,304,962233,5,0 +256,36,962661,1,2 +412,304,963090,1,0 +191,224,963518,1,2 +256,276,963732,1,0 +320,224,963947,1,0 +294,150,964161,1,0 +217,150,964375,1,2 +256,360,964804,5,0 +88,256,965232,1,2 +160,64,965660,1,0 +352,64,966089,1,2 +424,256,966517,1,0 +256,192,966946,1,2 +256,192,967160,1,0 +256,192,967374,1,0 +256,192,967589,1,0 +256,192,967803,5,2 +220,352,968231,2,0,B|240:380|282:380|293:349|293:349,1,84.9999964535238,0|2 +364,197,969088,1,0 +396,120,969303,1,0 +148,197,969731,1,0 +116,120,969945,1,0 +256,32,970374,5,2 +256,200,970802,1,0 +256,368,971231,1,2 +196,300,971445,2,0,B|224:300|224:300|256:284|256:284|288:300|288:300|320:300,1,127.499994680286,0|2 +439,128,972516,2,0,B|452:96|439:66|439:66,1,50 +352,57,972945,6,0,B|398:112|337:186|274:153|255:116|255:116|237:84|198:18|65:115|168:182|168:182,1,400,2|2 +120,348,975087,5,0 +178,278,975301,2,0,B|193:324|256:356|318:324|334:278,1,200 +392,348,976372,1,2 +355,173,976801,2,0,B|335:114|257:75|179:114|160:173,1,250 +95,106,978086,5,2 +256,24,978515,1,0 +256,24,978729,1,0 +256,328,979372,1,2 +336,168,979800,2,0,B|312:128|256:112|256:112|200:128|176:168,1,200,0|0 +417,106,981300,5,0 +417,106,981514,1,2 +256,24,981943,1,0 +295,191,982371,2,0,B|282:170|254:162|254:162|226:170|214:191,1,100,2|0 +216,280,983014,2,0,B|232:280|232:280|248:272|248:272|256:280|256:280|256:264|256:264|264:272|264:272|280:280|280:280|296:280,1,100 +344,351,983657,2,0,B|320:383|280:383|256:359|256:359|232:383|192:383|168:351,1,200,2|0 +80,328,984728,5,0 +144,264,984942,1,2 +56,240,985156,1,0 +256,56,985799,1,0 +368,264,986227,1,0 +456,240,986442,1,0 +432,328,986656,1,2 +56,264,987513,6,0,B|102:249|134:186|102:124|56:108,1,200,0|2 +256,92,988798,1,0 +256,92,989013,2,0,B|256:292,1,200 +256,292,990084,1,2 +456,264,990512,2,0,B|410:249|378:186|410:124|456:108,1,200 +256,36,991798,1,2 +196,108,992012,2,0,B|224:108|224:108|256:124|256:124|288:108|288:108|320:108,1,127.499994680286 +346,348,993083,5,2 +256,312,993297,1,0 +168,349,993512,2,0,B|111:265|160:184|191:152|261:139|319:160|356:186|407:266|341:356,1,500 +217,61,996939,6,0,B|224:83|256:100|287:83|295:61,1,100,2|0 +168,192,997796,1,2 +335,302,998225,2,0,B|320:348|257:380|195:348|179:302,1,200,0|2 +344,192,999510,1,0 +188,56,999939,5,2 +256,100,1000153,1,0 +324,56,1000367,1,0 +424,200,1000796,2,0,B|464:228|464:228|480:284,1,100,0|2 +348,360,1001653,1,0 +220,204,1002081,2,0,B|197:237|216:270|229:282|257:288|280:279|295:269|315:237|289:201,1,200,2|0 +164,360,1003367,5,2 +88,200,1003795,2,0,B|48:228|48:228|32:284,1,100 +144,60,1004652,1,2 +194,232,1005081,2,0,B|208:276|208:276|256:300|256:300|304:276|304:276|320:228,1,200 +369,59,1006366,1,2 +448,224,1006795,6,0,B|419:326,1,100,0|2 +256,240,1007651,2,0,B|256:136,1,100,0|2 +64,224,1008508,2,0,B|93:326,1,100,0|2 +256,48,1009794,5,2 +400,152,1010222,1,0 +348,328,1010651,1,2 +164,328,1011079,1,0 +112,152,1011508,1,2 +256,48,1011936,1,0 +256,196,1012793,5,2 +256,348,1013864,5,0 +256,348,1014079,1,2 +256,52,1014507,1,0 +45,192,1015364,2,0,B|61:143|110:127|175:143|142:192|158:256|239:240|256:192|256:192|272:240|353:256|369:192|336:143|401:127|450:143|466:192,1,549.999983608723,2|0 +179,48,1022649,6,0,B|194:94|257:126|319:94|335:48,1,200,8|0 +340,239,1023506,2,0,B|301:254|270:239|255:208|255:208|240:239|209:254|171:239,1,200,8|0 +172,349,1024148,2,0,B|210:333|241:349|256:379|256:379|271:349|302:333|340:349,1,200,0|0 +432,296,1024791,1,0 +456,64,1025220,1,8 +256,152,1025648,5,0 +64,64,1026077,1,8 +112,152,1026291,1,0 +174,64,1026506,2,0,B|201:28|256:10|256:10|310:28|337:64,1,200,0|8 +424,256,1027363,5,0 +360,336,1027577,1,0 +256,368,1027791,1,8 +152,336,1028006,1,0 +88,256,1028220,1,0 +256,40,1028648,1,8 +424,256,1029077,1,0 +408,56,1029506,5,8 +345,355,1029934,1,0 +282,199,1030148,2,0,B|309:172|361:186|361:251|309:263|309:263|270:277|256:315|256:315|243:277|204:263|204:263|152:251|152:186|204:172|230:199,1,439.999986886979 +167,355,1031220,1,8 +73,146,1031648,2,0,B|75:82|134:16|220:36|257:81|257:81|289:32|366:25|442:61|436:157,1,500 +400,256,1032934,1,8 +221,364,1033363,2,0,B|198:331|217:298|230:286|258:280|281:289|296:299|316:331|290:367,1,200,0|8 +112,256,1034220,5,0 +96,144,1034434,1,0 +200,184,1034648,1,8 +312,184,1034863,1,0 +416,144,1035077,1,0 +400,256,1035291,1,0 +333,336,1035506,6,0,B|318:290|255:258|193:290|177:336,1,200,8|0 +96,256,1036148,1,0 +64,152,1036363,2,8,B|160:120|160:120|192:24,1,200,8|0 +320,26,1037220,2,0,B|352:120|352:120|448:152,1,200,8|0 +336,240,1037863,2,0,B|288:240|288:240|256:200|256:200|224:240|224:240|176:240,1,200 +256,320,1038506,1,0 +64,192,1038934,5,8 +256,48,1039363,1,0 +304,184,1039577,1,0 +180,96,1039791,1,8 +332,96,1040006,1,0 +208,184,1040220,1,0 +448,192,1040648,1,8 +216,336,1041077,2,0,B|222:356|256:370|290:356|297:336,1,100 +333,189,1041506,2,0,B|370:117|336:59|311:34|253:28|214:34|176:54|137:117|184:193,2,400,8|8|8 +348,360,1043648,5,0 +256,320,1043863,1,0 +164,360,1044077,2,0,B|118:376|53:357|33:292|50:246,1,200,8|0 +21,137,1044720,1,0 +131,108,1044934,1,8 +160,217,1045148,1,0 +160,216,1045363,2,0,B|256:172|256:260|352:216,1,200,0|8 +460,28,1046220,1,0 +460,28,1046648,6,0,B|480:76|460:124,1,100,8|0 +348,84,1047077,2,0,B|280:176|348:268,1,200,0|8 +356,368,1047720,1,0 +256,336,1047934,1,0 +156,368,1048148,1,0 +163,268,1048363,2,0,B|231:175|163:83,1,200,8|0 +4,192,1049220,5,8 +256,352,1049648,1,0 +256,352,1049863,1,0 +256,352,1050077,6,0,B|352:328,1,100,4|0 +476,252,1050506,2,0,B|380:228,1,100,2|0 +256,148,1050934,2,0,B|352:124,1,100,2|0 +476,48,1051363,2,0,B|380:24,1,100,2|0 +256,48,1051791,6,0,B|160:92|160:4|64:48,1,200,0|0 +100,144,1052434,1,0 +100,144,1052648,2,0,B|120:192|100:240,1,100 +36,320,1053077,2,0,B|129:388|221:320,1,200,0|4 +256,224,1053720,1,0 +291,320,1053934,2,0,B|383:388|476:320,1,200 +512,116,1054791,6,0,B|416:144,1,100 +328,100,1055220,2,0,B|260:192|328:284,1,200,8|0 +312,384,1055863,1,0 +228,332,1056077,2,0,B|200:284|192:240,1,100,8|0 +191,144,1056506,2,0,B|200:100|228:52,1,100 +256,192,1056934,6,0,B|160:236|160:148|64:192,1,200,8|0 +256,192,1057791,2,0,B|352:148|352:236|448:192,1,200,8|0 +492,104,1058434,5,0 +396,112,1058649,2,0,B|354:80|348:28,1,100,8|0 +256,92,1059077,2,0,B|256:192,1,100,0|0 +115,112,1059506,2,0,B|157:80|164:27,1,100,8|0 +20,104,1059934,6,0,B|-48:196|20:288,1,200,0|8 +72,372,1060577,1,0 +160,324,1060791,2,0,B|256:276|352:324,1,200,0|8 +488,192,1061649,6,0,B|508:96,1,100 +372,152,1062077,2,0,B|352:56,1,100,8|0 +256,164,1062506,2,0,B|210:148|145:167|125:232|142:278,1,200,0|8 +370,277,1063363,2,0,B|387:232|367:167|302:148|256:164,1,200,0|8 +136,128,1064006,5,0 +208,76,1064220,2,0,B|256:96|304:76,1,100 +376,128,1064649,2,0,B|476:144,1,100,8|0 +512,272,1065077,6,0,B|413:256,1,100 +348,332,1065506,2,0,B|256:400|164:332,1,200,8|0 +164,52,1066363,2,0,B|256:-16|348:52,1,200,8|0 +356,152,1067006,1,0 +256,192,1067220,1,4 +156,152,1067434,1,0 +160,280,1067649,6,0,B|256:324|256:236|352:280,2,200,0|8|0 +68,320,1068720,1,0 +156,368,1068934,6,0,B|204:388|252:368,1,100,8|0 +356,192,1069363,2,0,B|308:172|260:192,1,100 +258,192,1069791,1,4 +100,276,1070220,1,0 +28,44,1070649,5,4 +120,88,1070863,1,0 +220,84,1071077,2,0,B|320:76,1,100 +412,32,1071506,2,0,B|442:133|378:220,1,200 +424,308,1072149,1,0 +328,340,1072363,1,0 +244,288,1072577,2,0,B|200:316|184:368,1,100 +88,340,1073006,1,0 +120,244,1073220,2,0,B|29:183|23:77,1,200 +112,28,1073863,1,0 +200,80,1074077,6,0,B|202:131|167:170,1,100 +116,260,1074506,2,0,B|216:280,1,100 +297,279,1074934,2,0,B|396:260,1,100 +345,171,1075363,2,0,B|309:131|312:80,1,100 +404,29,1075791,5,0 +481,103,1076006,1,0 +486,209,1076220,1,0 +445,308,1076434,1,0 +348,353,1076649,2,0,B|256:285|164:353,1,200,0|0 +70,309,1077291,1,0 +52,220,1077506,6,0,B|12:191|1:121|51:72|100:71,1,200,8|2 +186,99,1078149,2,0,B|225:127|236:197|186:246|137:247,1,200,0|0 +204,324,1078791,1,2 +304,324,1079006,1,0 +374,247,1079220,2,0,B|325:246|275:197|286:127|326:99,1,200,8|2 +411,71,1079863,2,0,B|460:72|510:121|499:191|460:220,1,200,0|0 +452,320,1080506,1,2 +360,356,1080720,1,0 +300,276,1080934,1,8 +368,204,1081149,1,0 +375,94,1081363,6,0,B|345:34|301:49|256:20|183:94|183:167|256:212|330:167|330:94|256:20|212:49|168:34|138:94,1,439.999986886979,0|2 +144,204,1082434,1,0 +212,276,1082649,1,8 +152,356,1082863,1,0 +60,320,1083077,1,2 +256,368,1083506,5,8 +344,184,1083934,1,0 +256,136,1084149,1,0 +168,184,1084363,1,8 +334,320,1084791,6,0,B|319:274|256:242|194:274|178:320,1,200,0|8 +88,192,1085434,1,0 +178,64,1085649,2,0,B|193:110|256:142|318:110|334:64,1,200,0|8 +424,192,1086291,1,0 +256,328,1086506,5,0 +96,80,1086934,1,8 +416,80,1087363,1,0 +256,194,1087577,1,0 +126,330,1087791,2,0,B|66:314|68:260|85:226|136:209|170:243|170:243|136:174|170:123|187:89|254:60|324:89|341:123|375:174|341:243|341:243|385:204|452:231|448:316|387:332,1,800,8|8 +432,144,1089720,1,8 +256,192,1089934,1,8 +80,144,1090149,1,0 +256,304,1090363,5,8 +200,120,1090577,1,8 +344,232,1090791,1,0 +168,232,1091006,1,8 +312,120,1091220,1,4 +114,294,1091649,6,0,B|68:279|36:216|68:154|114:138,1,200,2|8 +160,48,1092291,1,0 +256,80,1092506,1,2 +352,48,1092720,1,0 +398,138,1092934,2,0,B|444:154|476:216|444:279|398:294,1,200,8|0 +345,359,1093577,2,0,B|276:403|203:333|201:270|252:276|303:269|300:333|221:403|159:358,1,329.999990165234,2|8 +96,288,1094434,1,0 +176,224,1094649,2,0,B|194:180|256:154|319:178|340:230,1,200,2|0 +416,288,1095291,1,0 +337,343,1095506,6,0,B|319:387|257:413|194:389|173:337,1,200,8|2 +256,292,1096149,1,0 +205,208,1096363,1,8 +306,208,1096577,1,0 +376,130,1096791,2,0,B|380:64|353:-4|258:-45|163:0|124:60|137:130,1,400,2|2 +64,200,1097863,5,0 +64,200,1098077,1,8 +216,360,1098506,2,0,B|200:332|211:298|231:286|256:274|280:285|300:295|321:325|297:370,1,200,0|8 +448,200,1099363,1,0 +297,32,1099791,2,0,B|313:60|302:94|282:106|257:118|233:107|213:97|192:67|216:22,2,200,2|0|8 +156,200,1101077,5,2 +179,297,1101291,1,0 +272,322,1101506,1,10 +341,249,1101720,1,0 +317,152,1101934,1,0 +220,128,1102149,1,0 +146,223,1102363,1,8 +193,321,1102577,1,0 +298,327,1102791,1,0 +355,233,1103006,1,0 +308,134,1103220,5,8 +203,128,1103434,1,8 +149,253,1103649,1,8 +227,345,1103863,1,0 +342,321,1104077,1,8 +376,205,1104291,1,0 +297,113,1104506,1,8 +183,137,1104720,1,0 +147,263,1104934,5,12 +327,301,1105363,1,0 +365,121,1105791,1,8 +185,83,1106220,6,0,B|144:55|77:57|40:114|45:163,1,200,0|8 +76,260,1106863,1,0 +160,192,1107077,2,0,B|256:236|256:148|352:192,1,200,0|8 +436,124,1107720,5,0 +466,221,1107934,2,0,B|471:269|434:326|367:328|327:301,1,200,0|8 +256,232,1108577,1,0 +172,176,1108791,6,0,B|152:128|172:80,1,100 +340,208,1109220,2,0,B|360:256|340:304,1,100,8|0 +163,360,1109649,6,0,B|118:376|53:357|33:292|49:246,1,200,0|8 +16,152,1110291,1,0 +108,116,1110506,2,0,B|84:20,1,100 +224,76,1110934,2,0,B|248:173,1,100,8|0 +336,128,1111363,6,0,B|440:173|428:287,1,200,0|8 +84,287,1112220,2,0,B|71:173|176:128,1,200,0|8 +352,348,1113077,6,0,B|256:304|256:392|160:348,1,200,0|8 +112,276,1113720,1,0 +208,260,1113934,2,0,B|188:212|208:164,1,100 +304,164,1114363,2,0,B|324:212|304:260,1,100,8|0 +128,192,1114791,2,0,B|132:124|160:60|256:28|352:60|380:124|384:192,1,400,0|0 +332,328,1116077,1,8 +180,56,1116506,1,0 +372,12,1116934,6,0,B|440:104|372:196,1,200,8|0 +140,372,1117791,2,0,B|72:280|140:188,1,200,8|0 +184,96,1118434,1,0 +300,108,1118649,6,0,B|300:192|212:192|212:280,2,200,4|0|8 +256,20,1119720,1,0 +212,108,1119934,2,0,B|212:192|300:192|300:280,1,200,0|8 +256,364,1120577,1,0 +163,360,1120791,6,0,B|118:376|53:357|33:292|49:246,1,200,0|8 +348,360,1121649,2,0,B|394:376|459:357|479:292|462:246,1,200,0|4 +452,148,1122291,5,0 +356,124,1122506,2,0,B|311:153|308:207,1,100 +352,280,1122934,2,0,B|304:304|256:280|256:280|208:304|160:280,1,200,8|0 +204,207,1123577,2,0,B|200:153|156:124,1,100,0|8 +60,148,1124006,1,8 +60,148,1124220,6,0,B|72:48,1,100 +160,100,1124649,2,0,B|208:124|256:100|256:100|304:76|352:100,1,200,8|0 +440,48,1125291,1,0 +440,48,1125506,6,0,B|452:148,1,100,8|0 +376,268,1125934,2,0,B|364:168,1,100,8|0 +456,304,1126363,6,0,B|436:348|376:380|316:348|296:304,1,200,8|0 +256,192,1127006,1,0 +147,168,1127220,2,0,B|136:268,1,100,8|8 +55,303,1127649,2,0,B|76:348|136:380|196:348|216:303,2,200,8|4|0 +64,220,1128720,1,0 +111,151,1128934,6,0,B|88:80,1,74.9999977648259 +208,32,1129363,2,0,B|224:68|208:104,1,74.9999977648259 +304,156,1129791,2,0,B|288:120|304:84,1,74.9999977648259 +424,80,1130220,2,0,B|400:151,1,74.9999977648259 +482,201,1130649,5,0 +458,275,1130863,1,0 +397,322,1131077,1,0 +320,325,1131291,1,0 +256,284,1131506,1,0 +192,325,1131720,1,0 +115,322,1131934,1,0 +54,275,1132149,1,0 +30,201,1132363,1,0 +256,192,1132470,12,2,1135791 +80,56,1136220,5,0 +212,252,1136649,2,0,B|196:224|207:190|227:178|252:166|276:177|296:187|317:217|293:262,1,200,2|0 +432,56,1137505,1,2 +369,247,1137949,2,0,B|379:196|354:120|287:88|223:88|161:122|127:184|140:247,1,400,0|2 +68,288,1139060,1,0 +48,200,1139282,5,2 +256,224,1139743,1,0 +464,200,1140205,1,2 +346,34,1140776,2,0,B|307:69|273:52|256:35|256:35|238:52|204:69|164:31,1,200,0|2 +256,320,1153040,5,8 +256,252,1153343,1,8 +256,240,1153494,1,8 +256,228,1153646,1,8 +256,216,1153797,1,0 +256,204,1153949,1,4 +380,136,1154252,6,0,B|412:196,1,66.6666666666667,0|8 +456,124,1154555,2,0,B|423:62,1,66.6666666666667,0|0 +324,64,1154858,2,2,B|256:92|188:64,1,133.333333333333,2|0 +88,62,1155312,2,0,B|56:124,1,66.6666666666667,8|0 +99,197,1155616,2,0,B|132:136,1,66.6666666666667,0|0 +256,228,1156070,6,0,B|256:296,2,66.6666666666667,0|8|0 +256,140,1156525,1,0 +196,80,1156676,2,2,B|256:53|256:53|316:80,1,133.333333333333,2|0 +388,140,1157131,2,0,B|456:156,2,66.6666666666667,8|0|0 +316,201,1157585,6,0,B|255:227|255:227|195:201,1,133.333333333333,4|0 +124,140,1158040,2,0,B|56:156,1,66.6666666666667,8|0 +44,336,1158494,2,2,B|184:304,1,133.333333333333,2|0 +256,256,1158949,2,0,B|256:324,1,66.6666666666667,8|0 +468,336,1159403,6,0,B|328:304,1,133.333333333333,4|0 +324,212,1159858,2,0,B|360:152,1,66.6666666666667,8|0 +256,140,1160161,1,0 +188,212,1160312,2,0,B|152:152,1,66.6666666666667,2|0 +204,52,1160616,5,8 +228,40,1160767,1,8 +256,36,1160919,1,8 +288,40,1161070,1,0 +316,52,1161222,1,4 +468,156,1161525,6,0,B|468:224,1,66.6666666666667,0|8 +468,316,1161828,1,0 +380,344,1161979,1,0 +288,352,1162131,2,0,B|288:284|288:284|336:228,1,133.333333333333,2|0 +248,192,1162585,6,0,B|200:248,1,66.6666666666667,8|0 +140,312,1162888,1,0 +80,244,1163040,2,0,B|176:140,1,133.333333333333,0|0 +256,100,1163494,2,0,B|256:30,2,66.6666666666667,8|0|0 +337,141,1163949,2,0,B|432:244,1,133.333333333333,2|0 +339,268,1164403,2,0,B|305:222|256:203|206:222|172:268,1,200,8|4 +172,93,1165161,5,0 +171,92,1165312,2,0,B|205:137|256:156|305:137|339:92,1,200,8|2 +358,254,1166070,2,0,B|332:320,1,66.6666666666667,0|8 +256,360,1166373,1,0 +179,319,1166525,2,0,B|154:254,1,66.6666666666667,0|4 +316,112,1166979,6,0,B|304:44,2,66.6666666666667,8|8|8 +256,180,1167434,1,0 +196,112,1167585,2,8,B|208:44,2,66.6666666666667,8|8|0 +152,224,1168040,6,0,B|216:252,1,66.6666666666667,8|8 +360,224,1168343,2,0,B|296:252,1,66.6666666666667,0|4 +256,32,1168949,5,8 +420,112,1169252,1,0 +494,80,1169403,2,2,B|462:12|375:0|319:68|343:144|343:144|356:188|356:188|379:259|323:287,1,400,2|0 +144,268,1170616,2,0,B|136:232|144:200,1,66.6666666666667,0|8 +172,120,1170919,1,0 +224,56,1171070,2,0,B|256:32|288:56,1,66.6666666666667,0|2 +340,120,1171373,1,0 +367,199,1171525,2,0,B|376:232|368:268,1,66.6666666666667,0|8 +187,287,1172131,6,0,B|132:260|154:188|154:188|168:144|168:144|192:68|136:0|48:12|16:80,1,400,4|2 +24,164,1173191,1,0 +92,112,1173343,1,0 +164,68,1173494,2,0,B|196:48|232:60|259:88|259:88|283:112,1,133.333333333333,8|0 +328,184,1173949,1,2 +256,224,1174100,1,0 +184,184,1174252,1,0 +227,112,1174403,2,0,B|252:88|252:88|280:60|316:48|348:68,1,133.333333333333,8|0 +452,192,1174858,5,4 +256,356,1175161,1,2 +60,192,1175464,1,2 +256,28,1175767,1,4 +256,196,1176070,6,0,B|292:136,1,66.6666666666667,0|8 +256,196,1176373,2,0,B|220:136,1,66.6666666666667 +174,68,1176676,2,0,B|99:68|51:153|99:239|174:239,1,266.666666666667,4|2 +338,67,1177585,2,0,B|412:67|461:152|412:239|338:239,1,266.666666666667,4|2 +192,152,1178494,2,0,B|228:184|256:152|284:120|320:152,2,133.333333333333,4|2|2 +80,281,1179403,6,0,B|136:352|256:396|376:352|441:272,1,400,4|2 +448,188,1180464,1,0 +368,164,1180616,1,0 +356,248,1180767,2,0,B|332:272|292:276,1,66.6666666666667,8|0 +156,248,1181070,6,0,B|180:272|218:275,1,66.6666666666667,8|4 +212,192,1181373,2,0,B|188:168|150:165,1,66.6666666666667,0|0 +68,148,1181676,1,8 +84,64,1181828,1,8 +168,80,1181979,1,8 +256,106,1182131,6,0,B|256:36,1,66.6666666666667 +344,80,1182434,1,0 +428,64,1182585,1,8 +444,148,1182737,1,8 +362,164,1182888,2,0,B|324:168|300:192,1,66.6666666666667,0|4 +68,292,1183494,5,8 +40,212,1183646,2,0,B|84:192|140:220|148:268,2,133.333333333333,0|2|0 +32,128,1184403,1,8 +116,136,1184555,2,0,B|188:152|216:228,1,133.333333333333,0|4 +395,136,1185161,6,0,B|324:152|296:225,1,133.333333333333,0|0 +408,352,1185767,2,0,B|479:336|507:262,1,133.333333333333,2|0 +396,136,1186373,1,0 +104,352,1186676,6,0,B|32:336|4:262,1,133.333333333333,4|0 +80,220,1187131,1,8 +164,204,1187282,2,0,B|148:136,1,66.6666666666667 +192,69,1187585,2,0,B|256:87|256:87|319:69,1,133.333333333333,2|0 +364,135,1188040,2,0,B|348:204,1,66.6666666666667,8|0 +256,344,1188494,5,4 +140,120,1188797,1,2 +332,284,1189100,1,2 +256,44,1189403,1,4 +180,284,1189706,1,2 +372,120,1190009,1,2 +256,344,1190312,1,4 +488,244,1190767,6,0,B|436:40,1,200,8|2 +300,140,1191525,2,0,B|364:164,1,66.6666666666667,0|8 +212,140,1191979,2,0,B|148:164,1,66.6666666666667,8|2 +75,40,1192585,2,0,B|24:244,1,200,8|2 +204,268,1193343,5,0 +228,280,1193494,1,8 +256,284,1193646,1,8 +288,280,1193797,1,0 +316,268,1193949,1,4 +80,203,1194403,6,0,B|141:127|256:85|370:127|431:203,1,400,8|10 +212,312,1195767,2,0,B|180:252,1,66.6666666666667 +300,312,1196222,2,0,B|332:248,1,66.6666666666667,8|0 +212,144,1196676,5,8 +208,108,1196828,1,0 +224,76,1196979,1,0 +256,64,1197131,1,8 +288,76,1197282,1,0 +304,108,1197434,1,0 +300,144,1197585,1,12 +392,264,1197888,5,2 +392,264,1198040,1,2 +256,344,1198343,1,2 +256,344,1198494,1,0 +120,264,1198797,1,2 +176,104,1199100,1,2 +332,104,1199403,1,0 +256,216,1199706,5,0 +256,200,1199858,1,8 +256,184,1200009,1,0 +256,168,1200161,1,0 +256,152,1200312,1,2 +304,284,1200616,1,0 +284,304,1200767,1,8 +256,312,1200919,1,0 +228,304,1201070,1,0 +208,284,1201222,1,2 +84,192,1201525,6,0,B|52:280|52:280,1,66.6666666666667,0|8 +32,108,1201979,2,0,B|64:32|64:32,1,66.6666666666667,0|2 +201,101,1202434,2,0,B|219:71|252:59|293:64|315:108,1,133.333333333333 +313,250,1203040,2,0,B|296:278|260:291|216:285|192:238,1,133.333333333333,2|0 +155,317,1203494,6,0,B|182:349|233:356,1,66.6666666666667,8|0 +298,353,1203797,2,0,B|332:345|357:317,1,66.6666666666667,0|2 +256,188,1204252,1,0 +256,168,1204403,1,8 +256,148,1204555,1,0 +256,128,1204706,1,0 +256,104,1204858,1,4 +428,192,1205161,6,0,B|460:280|460:280,1,66.6666666666667,0|8 +480,108,1205616,2,0,B|448:32|448:32,1,66.6666666666667,0|2 +311,57,1206070,2,0,B|292:30|265:30|254:19|254:19|246:30|220:30|203:55,1,133.333333333333 +121,176,1206676,2,0,B|130:226|215:249|256:199|256:199|288:247|388:235|392:162,1,333.333333333333,2|0 +464,232,1207585,1,2 +337,345,1207888,5,0 +294,354,1208040,1,8 +256,336,1208191,1,0 +217,354,1208343,1,0 +178,345,1208494,1,2 +48,232,1208797,1,0 +48,232,1208949,1,8 +224,165,1209252,6,0,B|256:176|256:176|290:164,1,66.6666666666667,0|2 +197,56,1209706,2,0,B|255:28|255:28|317:55,2,133.333333333333,0|0|2 +116,184,1210616,1,0 +147,197,1210767,1,8 +169,224,1210919,1,0 +181,256,1211070,1,0 +180,292,1211222,1,2 +332,292,1211525,1,8 +331,256,1211676,1,8 +343,224,1211828,1,8 +365,197,1211979,1,0 +396,184,1212131,1,4 +336,44,1212434,6,0,B|336:77|336:77|314:106,1,66.6666666666667,0|8 +176,44,1212888,2,0,B|175:77|175:77|197:106,1,66.6666666666667,0|2 +200,244,1213343,2,0,B|217:272|253:285|297:279|321:232,1,133.333333333333 +99,267,1213949,2,0,B|131:363|263:412|385:368|423:243,1,400,2|2 +180,145,1215312,6,0,B|195:97|255:86|255:86|311:94|333:148,1,200,8|4 +124,44,1216222,5,8 +256,168,1216525,1,0 +256,168,1216676,1,2 +388,44,1216979,1,0 +435,226,1217282,1,2 +353,350,1217585,2,0,B|284:340|117:251|74:123|147:-32|400:-9|466:163|336:289|227:339|160:351,1,800,2|4 +77,224,1219706,1,0 +77,224,1219858,5,8 +120,48,1220161,1,2 +120,48,1220312,1,2 +256,120,1220616,1,0 +392,48,1220919,1,0 +400,200,1221222,2,0,B|382:282|318:334|255:334|166:330|116:273|107:181|107:181,2,400,2|2|4 +256,40,1223494,5,8 +256,184,1223797,1,2 +256,184,1223949,1,2 +319,332,1224252,2,0,B|300:360|264:373|220:367|196:320,1,133.333333333333,0|0 +96,200,1224858,1,2 +184,72,1225161,5,0 +256,40,1225312,1,8 +328,72,1225464,1,0 +416,200,1225767,1,0 +296,356,1226070,1,8 +320,280,1226222,1,8 +256,232,1226373,1,0 +192,280,1226525,1,0 +216,356,1226676,1,4 +336,111,1227131,6,0,B|352:47|288:15|256:15|223:15|159:47|175:111,2,274.000001469851,2|2|8 +256,304,1228343,1,0 +193,277,1228494,2,0,B|181:298|174:343|209:397|268:399|316:376|345:340|324:276|318:268,1,274.000001469851,2|8 +496,128,1229403,1,0 +256,32,1229706,5,0 +216,156,1229858,1,8 +320,80,1230009,1,8 +192,80,1230161,1,8 +296,156,1230312,1,4 +16,128,1230767,5,2 +175,288,1231222,2,0,B|159:352|223:384|256:384|288:384|352:352|336:288,1,274.000001469851,2|8 +438,116,1231979,1,0 +361,51,1232131,2,0,B|334:77|294:90|255:51|255:24|255:24|255:51|215:90|175:77|149:51,1,274.000001469851,2|8 +64,336,1233040,1,2 +256,224,1233343,5,0 +296,356,1233494,1,8 +192,276,1233646,1,8 +320,276,1233797,1,0 +216,356,1233949,1,4 +362,100,1234403,6,0,B|338:31|253:0|175:28|151:108,1,274.000001469851,2|2 +448,336,1235312,1,8 +256,212,1235616,1,0 +203,281,1235767,2,0,B|184:332|184:332|220:332|256:368|256:368|292:332|328:332|328:332|308:279,1,274.000001469851,2|8 +64,337,1236676,1,2 +180,88,1237131,6,0,B|203:42|256:31|310:43|333:90,1,182.666667646567,8|0 +362,187,1237585,2,0,B|324:295|164:293|148:177|148:177,3,274.000001469851,4|8|2|8 +40,360,1239252,1,8 +127,312,1239403,2,0,B|166:350|217:355,1,91.3333338232835,2|0 +305,353,1239706,2,0,B|346:350|385:312,1,91.3333338232835,0|8 +472,360,1240009,1,2 +474,357,1240085,1,0 +476,354,1240161,5,8 +488,248,1240312,1,0 +408,208,1240464,1,0 +320,144,1240616,1,0 +256,64,1240767,1,8 +192,144,1240919,1,0 +112,208,1241070,1,0 +24,248,1241222,1,4 +328,340,1241676,6,0,B|320:312|296:280|256:268|216:280|192:312|184:340,1,196.000001869202,8|0 +120,252,1242131,2,0,B|180:208|256:180|332:208|392:252,1,294.000002803803,2|8 +472,96,1242888,1,0 +392,36,1243040,6,0,B|332:80|256:108|180:80|120:36,1,294.000002803803,4|8 +16,68,1243646,2,0,B|8:168,1,98.0000009346008 +112,140,1243949,2,0,B|196:196|204:308,1,196.000001869202,2|0 +308,305,1244403,2,0,B|316:196|400:140,1,196.000001869202,8|2 +368,36,1244858,6,0,B|304:60|256:128|256:128|208:60|144:36,2,294.000002803803,4|8|2 +503,165,1246070,2,0,B|496:68,1,98.0000009346008,0|8 +424,148,1246373,2,0,B|431:245,1,98.0000009346008,0|0 +340,300,1246676,6,0,B|340:224|292:192|256:192|220:192|172:160|172:84,1,294.000002803803,4|8 +339,85,1247585,2,0,B|340:160|292:192|256:192|220:192|172:224|171:299,1,294.000002803803,2|8 +80,356,1248191,2,0,B|68:304|76:260,1,98.0000009346008,8|0 +136,168,1248494,6,0,B|212:168|228:256|304:256,1,196.000001869202,4|0 +412,248,1248949,2,0,B|480:252|496:180|496:180|512:104,1,196.000001869202,8|0 +424,40,1249403,2,0,B|356:36|340:108|340:108|324:184,1,196.000001869202,2|0 +324,184,1249858,1,8 +100,248,1250161,5,0 +100,248,1250312,2,0,B|32:252|16:180|16:180|0:104,1,196.000001869202,4|0 +88,40,1250767,2,0,B|156:36|172:108|172:108|188:184,1,196.000001869202,8|0 +292,212,1251222,2,0,B|384:220|384:220|396:164|372:120,1,196.000001869202,2|0 +324,60,1251676,1,8 +256,28,1251828,1,0 +188,60,1251979,1,0 +140,120,1252131,6,0,B|116:164|128:220|128:220|220:212,1,196.000001869202,4|0 +328,204,1252585,2,0,B|384:200|384:200|440:196|472:248|452:308|392:312|392:312|340:316,2,294.000002803803,8|2|8 +328,204,1253646,1,0 +174,316,1253949,2,0,B|120:312|120:312|60:308|40:248|72:196|128:200|128:200|184:204,1,294.000002803803,4|8 +192,96,1254555,2,0,B|96:88,2,98.0000009346008,0|8|4 +418,87,1255161,6,0,B|320:96,1,98.0000009346008,0|8 +280,184,1255464,2,0,B|378:175,1,98.0000009346008,8|0 +376,272,1255767,6,0,B|280:280|280:280|224:284|204:336,1,196.000001869202,4|0 +308,336,1256222,2,0,B|288:284|232:280|232:280|136:272,1,196.000001869202,8|0 +40,264,1256676,2,0,B|52:180|140:176|140:176|228:172|240:88,1,294.000002803803,2|8 +144,80,1257282,1,0 +136,272,1257585,5,4 +256,116,1257888,1,0 +256,116,1258040,1,8 +376,272,1258343,1,0 +376,272,1258494,2,0,B|424:252|460:200|440:136|416:108,1,196.000001869202,2|0 +332,60,1258949,2,0,B|280:60|256:8|256:8|232:60|180:60,1,196.000001869202,8|0 +96,108,1259403,2,0,B|71:136|51:200|87:252|135:272,1,196.000001869202,4|0 +180,360,1259858,2,0,B|232:360|256:308|256:308|280:360|332:360,1,196.000001869202,8|0 +424,320,1260312,2,0,B|368:276|336:192|368:108|424:64,2,294.000002803803,2|8|4 +256,176,1261676,5,8 +87,320,1262131,2,0,B|144:276|176:192|144:108|88:64,1,294.000002803803,2|8 +32,144,1262737,1,2 +32,240,1262888,1,0 +132,236,1263040,6,0,B|328:228,1,196.000001869202,4|0 +380,148,1263494,2,0,B|184:156,1,196.000001869202,8|0 +184,156,1263949,1,2 +332,60,1264252,2,0,B|429:55,1,98.0000009346008,0|8 +436,232,1264706,2,0,B|338:236,1,98.0000009346008,0|4 +82,329,1265161,6,0,B|180:324,1,98.0000009346008,0|8 +173,148,1265616,2,0,B|76:152,1,98.0000009346008,0|2 +132,236,1266070,1,0 +132,236,1266222,2,0,B|328:228,1,196.000001869202,8|0 +432,192,1266676,5,4 +256,128,1266979,1,0 +256,128,1267131,1,8 +80,192,1267434,1,0 +80,192,1267585,1,2 +352,240,1267888,1,0 +352,240,1268040,1,8 +160,240,1268343,1,0 +160,240,1268494,1,2 +316,372,1268949,5,8 +256,380,1269100,1,8 +196,372,1269252,1,2 +168,288,1269403,5,8 +256,276,1269555,1,0 +344,284,1269706,1,2 +372,200,1269858,5,8 +256,176,1270009,1,0 +140,200,1270161,1,2 +256,100,1270312,5,4 +384,280,1270767,6,0,B|436:280|488:252|512:192|488:132|436:104|384:104,1,294.000002803803,8|2 +300,126,1271373,2,0,B|300:224,1,98.0000009346008,0|2 +256,296,1271676,1,8 +212,224,1271828,2,0,B|212:126,1,98.0000009346008,0|2 +128,103,1272131,2,0,B|76:104|24:132|0:192|24:252|76:280|128:280,3,294.000002803803,4|2|0|2 +340,76,1273949,6,0,B|384:108|412:184|384:260|332:308|256:328|180:308|128:260|100:184|128:108|172:76,2,588.000005607605,4|2|4 +48,40,1276222,1,8 +36,136,1276373,1,0 +72,228,1276525,1,0 +140,296,1276676,2,0,B|220:304|256:224|256:224|292:304|372:296,1,294.000002803803,2|8 +440,228,1277282,1,0 +476,136,1277434,1,0 +464,40,1277585,1,4 +256,248,1278040,5,8 +256,64,1278494,1,2 +160,164,1278646,5,0 +160,260,1278797,1,0 +256,288,1278949,1,8 +352,260,1279100,1,0 +352,164,1279252,1,2 +256,136,1279403,1,4 +456,56,1279858,6,0,B|456:350,1,294.000002803803,8|2 +56,350,1280767,2,0,B|56:56,1,294.000002803803,8|4 +360,88,1281676,2,0,B|360:212|360:212|360:284|328:324|256:352|184:324|152:284|152:212|152:212|152:88,1,588.000005607605,8|8 +20,284,1283040,5,4 +8,208,1283191,1,0 +16,128,1283343,1,2 +80,80,1283494,1,8 +160,80,1283646,1,0 +228,120,1283797,1,2 +256,192,1283949,1,8 +284,264,1284100,1,0 +352,304,1284252,1,0 +432,304,1284403,1,8 +496,256,1284555,1,8 +504,176,1284706,1,0 +492,100,1284858,1,4 +208,192,1291222,5,0 +148,112,1291373,1,0 +148,112,1291449,1,0 +148,112,1291525,1,0 +52,132,1291676,1,0 +32,228,1291828,1,0 +100,292,1291979,1,0 +184,281,1292131,6,0,B|205:317|263:349|322:311|334:277,1,178.666658215332,4|2 +309,192,1292585,2,0,B|301:140|257:124|257:124|205:104|209:48,1,183.333327869574,8|0 +305,56,1293040,2,0,B|309:104|257:124|257:124|213:140|201:196,2,183.333327869574,2|0|0 +392,40,1293797,1,0 +464,96,1293949,1,2 +392,264,1294252,5,0 +336,328,1294403,1,8 +256,352,1294555,1,0 +176,328,1294706,1,0 +120,264,1294858,1,2 +120,120,1295161,1,0 +176,56,1295312,1,8 +256,32,1295464,1,0 +336,56,1295616,1,0 +392,120,1295767,1,2 +256,200,1296070,5,0 +256,200,1296222,1,8 +256,24,1296525,5,0 +256,24,1296676,1,2 +201,169,1296979,1,0 +331,76,1297282,1,2 +175,76,1297585,1,0 +297,171,1297888,1,0 +300,259,1298040,6,0,B|255:244|255:244|212:259,1,91.6666639347872,8|0 +212,349,1298343,2,0,B|256:363|256:363|299:349,1,91.6666639347872 +392,184,1298797,1,8 +346,101,1298949,1,8 +256,67,1299100,1,0 +165,101,1299252,1,8 +119,184,1299403,1,4 +256,276,1299706,5,0 +182,318,1299858,2,0,B|202:359|257:382|312:360|331:316,1,183.333327869574,2|0 +332,233,1300312,2,0,B|310:192|258:168|200:192|183:234,2,183.333327869574,2|0|0 +422,128,1301222,2,0,B|352:92|336:12|336:12|256:108|256:108|180:8|180:8|156:92|94:128,2,549.999983608723,2|2|4 +188,308,1303494,6,0,B|201:351|256:361|256:361|307:354|327:304,1,183.333327869574,8|0 +256,256,1303949,1,2 +360,80,1304252,1,0 +152,80,1304555,1,2 +68,233,1304858,2,0,B|52:304|140:352|191:289|191:289|209:334|255:347|302:334|320:291|320:291|370:351|463:307|443:225,2,549.999983608723,0|2|4 +256,68,1306979,5,0 +256,68,1307131,1,8 +256,252,1307434,1,0 +182,199,1307585,2,0,B|203:199|203:199|228:176|228:176|256:152|256:152|284:176|284:176|308:199|308:199|328:199,2,183.333327869574,2|0|0 +46,322,1308494,2,0,B|68:284|182:252|208:368|160:384|164:318|240:304|256:251|256:251|272:304|352:320|352:384|304:368|333:281|364:284|455:262|475:337|475:337,2,549.999983608723,2|2|4 +256,384,1310767,5,8 +332,219,1311070,1,0 +332,219,1311222,1,2 +179,217,1311525,1,0 +230,40,1311828,2,0,B|216:49|207:74|216:97|232:112|256:118|280:112|296:97|304:74|296:49|282:40,1,183.333327869574,2|0 +448,74,1312434,6,0,B|489:156,1,91.6666639347872,2|8 +444,238,1312737,2,0,B|416:326,1,91.6666639347872,0|8 +324,366,1313040,2,0,B|310:324|256:313|256:313|206:321|186:370,1,183.333327869574,8|0 +95,325,1313494,2,0,B|68:238,1,91.6666639347872,8|0 +23,156,1313797,2,0,B|64:74,1,91.6666639347872,8|4 +336,47,1314403,6,0,B|296:135|336:224,1,183.333327869574,8|0 +376,304,1314858,2,0,B|296:308|256:361|256:361|211:308|135:304,1,274.999991804362,2|8 +43,288,1315464,2,0,B|51:240|83:208,1,91.6666639347872,2|8 +174,224,1315767,6,0,B|215:135|175:47,1,183.333327869574,4|0 +83,51,1316222,2,0,B|139:107|127:200|43:240|-24:204,1,274.999991804362,8|2 +68,360,1316979,6,0,B|144:308,1,91.6666639347872,0|8 +256,372,1317282,2,0,B|256:280,1,91.6666639347872,8|0 +256,188,1317585,1,4 +444,360,1317888,6,0,B|368:308,1,91.6666639347872,0|8 +209,116,1318343,2,0,B|254:100|297:116,1,91.6666639347872 +344,43,1318646,2,0,B|256:2|167:43,1,183.333327869574,0|8 +44,176,1319252,1,0 +116,120,1319403,2,0,B|180:176|168:288,1,183.333327869574,2|0 +256,316,1319858,2,0,B|256:135,1,183.333327869574,8|0 +396,120,1320312,2,0,B|332:176|344:288,1,183.333327869574,2|0 +428,324,1320767,6,0,B|420:280|424:232,1,91.6666639347872,8|8 +464,84,1321070,2,0,B|472:128|468:176,1,91.6666639347872,0|4 +320,336,1321525,6,0,B|324:292|308:244,1,91.6666639347872,0|8 +256,172,1321828,1,0 +210,102,1321979,2,0,B|255:86|298:102,1,91.6666639347872 +191,339,1322434,6,0,B|187:295|202:249,1,91.6666639347872,0|8 +256,172,1322737,1,0 +312,100,1322888,1,0 +348,14,1323040,2,0,B|401:10|401:10|457:6|485:38|489:83,1,183.333327869574,2|0 +404,123,1323494,2,0,B|320:171|304:268,1,183.333327869574,8|0 +207,268,1323949,2,0,B|191:171|107:123,1,183.333327869574,2|0 +107,123,1324403,1,8 +192,92,1324555,5,0 +256,28,1324706,1,0 +320,92,1324858,1,4 +256,192,1325009,12,4,1326676 +60,192,1327131,5,0 +60,192,1327282,1,0 +160,136,1327434,1,0 +160,124,1327509,1,0 +160,112,1327585,5,2 +256,28,1327737,1,0 +352,112,1327888,1,0 +452,192,1328040,1,8 +352,272,1328191,1,0 +256,356,1328343,1,0 +160,272,1328494,1,4 +40,166,1328797,6,0,B|40:120|64:80,1,91.3333338232835,0|8 +255,146,1329252,2,0,B|268:176|244:208|256:236,1,91.3333338232835,0|2 +471,166,1329706,2,0,B|472:120|448:80,1,91.3333338232835,0|8 +364,312,1330161,5,0 +364,312,1330312,2,0,B|336:380|256:408|175:380|147:312,1,274.000001469851,4|8 +192,232,1330919,1,0 +256,168,1331070,1,0 +320,232,1331222,2,0,B|364:232|408:208|424:163|416:107,1,182.666667646567,2|0 +340,64,1331676,2,0,B|296:96|256:64|256:64|216:32|172:64,1,182.666667646567,8|2 +96,107,1332131,6,0,B|88:164|104:208|148:232|192:232,1,182.666667646567,4|0 +284,232,1332585,2,0,B|332:92|470:44,1,274.000001469851,8|2 +227,151,1333494,2,0,B|178:290|40:338,1,274.000001469851,8|4 +40,156,1334252,6,0,B|84:168|84:168|132:168,1,91.3333338232835,0|8 +179,91,1334555,2,0,B|203:55|256:27|308:55|332:91,1,182.666667646567,0|2 +360,180,1335009,1,0 +336,268,1335161,1,0 +256,308,1335312,1,8 +176,268,1335464,1,8 +152,180,1335616,1,0 +148,88,1335767,6,0,B|208:56|208:56|256:84|316:88,1,182.666667646567,4|0 +408,84,1336222,2,0,B|376:144|376:144|404:192|408:252,1,182.666667646567,8|0 +364,344,1336676,2,0,B|304:312|304:312|256:340|196:344,1,182.666667646567,2|0 +104,300,1337131,2,0,B|136:240|136:240|108:192|104:132,1,182.666667646567,8|0 +27,183,1337585,6,0,B|75:244|175:236|215:147|179:83,1,274.000001469851,4|8 +256,32,1338191,2,0,B|256:216,1,182.666667646567,0|2 +332,84,1338797,1,0 +332,83,1338949,2,0,B|296:148|336:236|436:244|484:183,1,274.000001469851,8|4 +256,192,1339555,12,6,1342131 +112,112,1342282,5,0 +168,40,1342434,1,0 +256,12,1342585,1,8 +344,40,1342737,1,0 +400,112,1342888,1,0 +332,170,1343040,6,0,B|312:129|257:106|202:128|183:172,1,182.666667646567,6|0 +181,260,1343494,2,0,B|201:301|256:324|311:302|330:258,1,182.666667646567,10|0 +256,216,1343949,1,0 +208,384,1344252,2,0,B|304:384|304:384,1,91.3333338232835,0|8 +256,216,1344706,1,0 +124,38,1345161,2,0,B|138:78|197:93|226:63|226:19|190:5|160:49|208:93|256:93|256:93|303:93|351:49|321:5|285:19|285:63|318:93|387:71|395:34,1,421.333338858287,2|0 +440,216,1346070,5,2 +388,304,1346222,1,10 +256,140,1346525,1,0 +204,212,1346676,2,0,B|212:264|256:280|256:280|308:300|304:356,1,182.666667646567 +208,348,1347131,2,0,B|204:300|256:280|256:280|300:264|312:208,1,182.666667646567,8|0 +256,140,1347585,1,0 +72,216,1347888,1,2 +124,304,1348040,1,10 +160,156,1348343,6,0,B|213:103|186:3|123:-2|81:55|123:108|202:81|257:14|257:14|310:81|390:108|432:55|390:-2|326:3|299:103|352:156,1,639.333336762985,0|2 +344,236,1349555,6,0,B|388:316,1,91.3333338232835,0|0 +256,364,1349858,2,0,B|256:252,1,91.3333338232835,8|0 +124,315,1350161,2,0,B|168:236,1,91.3333338232835,0|4 +44,44,1350767,1,8 +335,282,1351222,2,0,B|376:257|405:184|376:114|328:68|258:49|185:68|135:114|111:184|135:257|178:284,1,548.000002939701,2|2 +468,44,1352585,1,8 +357,277,1353040,6,0,B|339:348|254:387|171:346|154:277,1,274.000001469851,4|8 +22,192,1353797,2,0,B|5:-6|238:-24|305:41|372:108|388:158|354:192|256:441|156:192|122:158|138:108|205:41|272:-24|505:-6|483:194,1,1096.0000058794,0|0 +377,321,1355767,2,0,B|319:381|256:336|256:336|187:384|131:316,1,274.000001469851,2|2 +200,268,1356373,1,0 +140,212,1356525,1,0 +132,132,1356676,1,4 +180,64,1356828,1,0 +256,40,1356979,1,0 +332,64,1357131,1,6 +380,132,1357282,1,0 +372,212,1357434,1,0 +312,268,1357585,1,4 +52,80,1358494,6,0,B|52:37|113:29|132:69|132:69|150:110|197:110|214:69|214:69|229:29|279:29|296:69|296:69|312:110|360:110|376:69|376:69|397:29|458:37|458:81,2,548.000002939701,8|0|8 +256,192,1360767,1,0 +52,302,1361222,2,0,B|52:345|113:353|132:313|132:313|150:272|197:272|214:313|214:313|229:353|279:353|296:313|296:313|312:272|360:272|376:313|376:313|397:353|458:345|458:301,2,548.000002939701,0|8|0 +256,44,1363494,5,0 +244,104,1363949,1,8 +264,152,1364403,1,0 +244,208,1364858,1,4 +256,356,1365767,1,8 +256,356,1366373,5,0 +256,356,1366525,1,0 +256,356,1366676,1,0 +308,196,1367131,1,0 +176,288,1367585,1,8 +336,288,1368040,1,0 +204,196,1368494,1,0 +361,51,1369403,6,0,B|334:77|294:90|255:51|255:24|255:24|255:51|215:90|175:77|149:51,1,274.000001469851,8|0 +140,60,1370009,1,0 +127,69,1370161,1,0 +117,79,1370312,1,0 +256,192,1370767,1,0 +344,296,1371222,1,8 +320,324,1371373,1,0 +292,340,1371525,1,0 +260,344,1371676,1,8 +220,340,1371828,1,0 +192,324,1371979,1,0 +168,296,1372131,1,4 +256,192,1383040,12,0,1386676 +256,48,1387131,5,4 +256,216,1387585,1,0 +256,216,1388040,1,8 +176,236,1388191,1,0 +96,256,1388343,1,0 +40,200,1388494,6,0,B|20:156|40:112,1,91.3333338232835 +164,88,1388797,2,0,B|144:128|144:128|108:156,1,91.3333338232835,0|4 +210,327,1389403,6,0,B|256:344|300:328,1,91.3333338232835,0|0 +208,192,1389706,2,0,B|254:175|298:191,1,91.3333338232835,0|4 +472,200,1390161,5,0 +472,200,1390312,2,0,B|492:156|472:112,1,91.3333338232835 +348,88,1390616,2,0,B|368:128|368:128|404:156,1,91.3333338232835,0|4 +256,216,1391222,5,0 +256,216,1391676,1,8 +336,236,1391828,1,0 +416,256,1391979,1,0 +384,332,1392131,6,0,B|296:308,1,91.3333338232835 +128,332,1392434,2,0,B|216:308,1,91.3333338232835,0|4 +384,128,1393040,6,0,B|296:152,1,91.3333338232835 +128,128,1393343,2,0,B|216:152,1,91.3333338232835,0|4 +408,232,1393797,5,0 +408,232,1393949,2,0,B|316:232,1,91.3333338232835 +104,232,1394252,2,0,B|195:232,1,91.3333338232835,0|4 +195,232,1394858,1,0 +302,40,1395312,6,0,B|210:40,1,91.3333338232835,8|0 +296,116,1395616,2,0,B|380:152,1,91.3333338232835 +300,220,1395919,2,0,B|256:228|256:228|212:220,1,91.3333338232835 +216,116,1396222,2,0,B|48:188,1,182.666667646567,4|0 +80,312,1396676,5,8 +164,260,1396828,1,0 +256,300,1396979,1,0 +256,300,1397131,1,4 +395,232,1397282,6,0,B|353:313,1,91.3333338232835,0|0 +256,300,1397585,1,8 +159,313,1397737,2,0,B|117:232,1,91.3333338232835,0|0 +256,116,1398040,1,4 +256,116,1398494,1,0 +356,336,1398949,6,0,B|356:244,1,91.3333338232835,8|0 +256,348,1399252,2,0,B|256:256,1,91.3333338232835 +156,336,1399555,2,0,B|156:244,1,91.3333338232835 +256,116,1399858,1,4 +280,32,1400009,2,0,B|208:32,2,45.6666669116418 +356,84,1400312,1,8 +376,180,1400464,1,0 +348,276,1400616,1,0 +256,316,1400767,1,8 +164,276,1400919,1,0 +136,180,1401070,1,0 +152,88,1401222,6,0,B|112:24,2,45.6666669116418 +208,152,1401525,1,0 +256,72,1401676,2,0,B|256:24,2,45.6666669116418,8|0|0 +304,148,1401979,1,0 +360,88,1402131,2,0,B|400:24,2,45.6666669116418 +304,148,1402434,1,0 +256,216,1402585,2,0,B|256:308,1,91.3333338232835,8|0 +256,384,1402888,1,0 +176,352,1403040,5,2 +156,316,1403116,1,0 +136,280,1403191,1,0 +176,208,1403343,1,0 +184,128,1403494,2,0,B|204:84|256:60|308:84|328:128,1,182.666667646567,8|0 +336,208,1403949,1,8 +376,280,1404100,1,2 +356,316,1404176,1,0 +336,352,1404252,1,0 +256,384,1404403,5,8 +196,268,1404555,1,2 +316,268,1404706,1,0 +416,368,1404858,6,0,B|476:344|492:280|492:280|508:216,1,182.666667646567,4|0 +500,136,1405312,2,0,B|404:172|328:104,1,182.666667646567,8|0 +344,23,1405767,2,0,B|256:-16|167:23,1,182.666667646567,4|2 +11,135,1406373,6,0,B|107:171|180:105,1,182.666667646567,0|2 +330,277,1406979,2,0,B|404:212|500:248,1,182.666667646567,8|0 +180,277,1407585,2,0,B|107:212|11:247,1,182.666667646567,10|2 +120,332,1408040,5,8 +256,248,1408191,1,8 +392,332,1408343,1,0 +384,147,1408494,6,0,B|360:95|304:55|239:63|183:135|195:192|256:232|316:192|328:135|272:63|207:55|151:95|127:147,1,464.000007743836,4|2 +80,208,1409555,2,0,B|104:244|96:292,1,76.1333349488259 +12,180,1409858,2,0,B|12:136|40:100,1,76.1333349488259,8|0 +473,282,1410312,6,0,B|500:248|500:204,1,76.1333349488259,2|0 +415,95,1410616,2,0,B|408:140|432:176,1,76.1333349488259,0|8 +364,268,1410919,2,0,B|280:252,1,76.1333349488259,2|0 +148,116,1411222,2,0,B|232:132,1,76.1333349488259,2|0 +144,304,1411525,6,0,B|116:272|112:228,1,76.1333349488259,0|8 +368,80,1411828,2,0,B|396:112|400:156,1,76.1333349488259,2|8 +256,192,1412131,5,4 +256,192,1412282,12,8,1413494 +84,108,1413949,6,0,B|20:160,1,76.1333349488259,4|0 +84,251,1414252,2,0,B|128:180,1,76.1333349488259,8|2 +216,125,1414555,1,2 +216,125,1414631,1,0 +216,125,1414706,2,0,B|200:209,1,76.1333349488259,0|8 +312,208,1415009,2,0,B|296:125,1,76.1333349488259,0|2 +384,180,1415312,2,0,B|428:252,1,76.1333349488259,2|0 +493,160,1415616,2,0,B|428:108,1,76.1333349488259,0|4 +336,272,1416222,6,0,B|352:336|288:368|256:368|223:368|159:336|175:272,2,274.000001469851,2|2|8 +256,80,1417434,1,0 +193,107,1417585,2,0,B|181:86|174:41|209:-13|268:-15|316:8|345:44|324:108|313:114,1,274.000001469851,2|8 +496,256,1418494,1,2 +256,352,1418797,5,0 +216,228,1418949,1,8 +320,304,1419100,1,8 +192,304,1419252,1,8 +296,228,1419403,1,4 +16,256,1419858,5,2 +175,95,1420312,2,0,B|159:31|223:0|256:0|288:0|352:31|336:95,1,274.000001469851,2|8 +438,268,1421070,1,0 +361,333,1421222,2,0,B|334:307|294:294|255:333|255:360|255:360|255:333|215:294|175:307|149:333,1,274.000001469851,2|8 +80,288,1421828,2,0,B|108:248|160:236,1,91.3333338232835 +112,168,1422131,2,0,B|160:160|188:120,1,91.3333338232835,8|0 +256,76,1422434,1,0 +324,120,1422585,2,0,B|352:160|400:168,1,91.3333338232835,8|0 +357,237,1422888,2,0,B|400:248|432:288,1,91.3333338232835,0|4 +150,100,1423494,6,0,B|174:31|259:0|337:28|361:108,1,274.000001469851,2|2 +64,336,1424403,1,8 +256,212,1424706,1,0 +309,281,1424858,2,0,B|328:332|328:332|292:332|256:368|256:368|220:332|184:332|184:332|204:279,1,274.000001469851,2|8 +448,337,1425767,1,2 +180,88,1426222,6,0,B|203:42|256:31|310:43|333:90,1,182.666667646567,8|0 +362,187,1426676,2,0,B|324:295|164:293|148:177|148:177,3,274.000001469851,4|8|2|8 +40,360,1428494,1,2 +127,312,1428646,2,0,B|166:350|217:355,1,91.3333338232835,2|0 +305,353,1428949,2,0,B|346:350|385:312,1,91.3333338232835,8|8 +476,354,1429252,1,8 +488,248,1429403,5,8 +408,208,1429555,1,0 +320,144,1429706,1,0 +256,64,1429858,1,8 +192,144,1430009,1,0 +112,208,1430161,1,0 +24,248,1430312,1,4 +337,289,1430767,6,0,B|321:338|256:371|190:338|174:289,1,210.666669429143,2|0 +256,248,1431222,1,2 +256,56,1431525,1,0 +175,87,1431676,2,0,B|191:127|256:151|256:151|313:129|336:87,1,210.666669429143,8|0 +416,144,1432131,1,2 +416,336,1432434,2,0,B|368:312|368:312|344:264,1,105.333334714572,0|8 +166,266,1432888,2,0,B|144:312|144:312|96:336,1,105.333334714572,0|2 +96,144,1433343,5,0 +174,91,1433494,2,0,B|229:91|256:35|256:35|282:91|337:91,1,210.666669429143,8|0 +400,184,1433949,2,0,B|430:234|430:234|457:284|446:343|379:351|379:351,1,210.666669429143,2|0 +294,306,1434403,2,0,B|299:294|311:265|305:238|281:222|254:214|225:221|205:241|201:269|207:289|220:306,1,210.666669429143,8|0 +132,351,1434858,2,0,B|65:343|54:284|81:234|81:234|112:184,1,210.666669429143,2|0 +136,96,1435312,5,8 +215,45,1435464,2,0,B|222:20|255:3|288:20|296:45,1,105.333334714572,2|0 +376,96,1435767,1,2 +440,276,1436070,2,0,B|412:308|412:308|376:312|376:312|360:336,1,105.333334714572,0|8 +308,256,1436373,2,0,B|320:220|320:220|352:208|352:208|364:172,1,105.333334714572,2|0 +256,160,1436676,2,0,B|264:136|264:136|240:96|240:96|256:68|256:68,2,105.333334714572,8|0|0 +149,176,1437131,2,0,B|160:208|160:208|192:220|192:220|204:256,1,105.333334714572,8|0 +150,333,1437434,2,0,B|136:312|136:312|100:308|100:308|72:276,1,105.333334714572,0|4 +256,124,1437888,5,0 +176,92,1438040,2,0,B|192:43|257:10|323:43|339:92,1,210.666669429143,8|0 +360,192,1438494,2,0,B|136:192,1,210.666669429143,2|0 +176,292,1438949,2,0,B|192:341|257:374|323:341|339:292,1,210.666669429143,8|0 +416,348,1439403,5,2 +256,252,1439706,1,0 +256,252,1439858,1,8 +96,348,1440161,1,0 +96,348,1440312,1,2 +112,160,1440616,1,0 +164,80,1440767,1,8 +256,52,1440919,1,0 +348,80,1441070,1,0 +392,156,1441222,1,6 +256,192,1441373,12,2,1443040 +256,344,1443191,5,0 +344,312,1443343,1,10 +404,240,1443494,1,0 +404,144,1443646,1,8 +344,72,1443797,1,0 +256,40,1443949,1,8 +168,72,1444100,1,0 +108,144,1444252,1,8 +108,240,1444403,1,8 +168,312,1444555,5,8 +256,344,1444706,1,8 +344,312,1444858,1,4 +412,136,1445161,1,2 +452,52,1445312,1,8 +256,84,1445616,1,2 +256,176,1445767,1,0 +100,136,1446070,1,2 +60,52,1446222,1,8 +134,257,1446525,22,0,B|160:337|259:373|350:340|378:247,1,316.000004143715,2|2 +432,331,1447131,2,0,B|504:216|466:84|466:84,1,210.666669429143,8|0 +402,67,1447585,1,2 +256,188,1447888,1,0 +350,175,1448040,2,0,B|363:214|334:293|255:300|213:278,1,210.666669429143,8|0 +161,208,1448494,2,0,B|148:169|177:90|256:83|298:105,1,210.666669429143,2|0 +256,188,1448949,1,8 +112,68,1449252,1,0 +35,130,1449403,2,0,B|28:248|84:336,1,210.666669429143,2|0 +172,356,1449858,1,8 +300,236,1450161,38,0,B|323:218|338:177|323:136|295:111|254:100|213:111|185:136|170:177|185:218|209:236,1,316.000004143715,2|0 +104,228,1450767,1,8 +108,132,1450919,1,8 +164,56,1451070,1,0 +256,28,1451222,1,8 +348,56,1451373,1,8 +404,132,1451525,1,0 +408,228,1451676,1,8 +344,300,1451828,1,0 +256,332,1451979,1,8 +168,300,1452131,1,4 +44,44,1452585,21,2 +256,232,1453040,1,2 +312,60,1453343,1,0 +168,160,1453646,1,2 +348,160,1453949,1,2 +204,60,1454252,1,2 +256,136,1454403,1,8 +468,44,1454858,1,2 +448,232,1455161,5,0 +448,232,1455312,1,8 +296,352,1455616,1,0 +218,297,1455767,2,0,B|189:364|93:358|82:299|67:262|90:207|157:188|201:214|200:251,1,316.000004143715,2|8 +294,87,1456676,2,0,B|323:20|418:25|429:84|444:121|422:177|354:195|311:170|311:132,1,316.000004143715,2|8 +436,286,1457434,21,2 +350,317,1457585,1,8 +256,302,1457737,1,2 +185,247,1457888,1,2 +161,160,1458040,1,8 +177,66,1458191,1,0 +256,26,1458343,1,2 +334,66,1458494,1,10 +350,160,1458646,1,8 +326,247,1458797,1,0 +256,302,1458949,1,8 +161,317,1459100,1,8 +75,286,1459252,1,0 +40,200,1459403,38,0,B|8:160|16:88|64:48|136:56,1,210.666669429143,4|2 +200,112,1459858,1,8 +256,184,1460009,1,0 +312,112,1460161,1,2 +388,55,1460312,2,0,B|448:48|496:88|504:160|472:200,1,210.666669429143,0|0 +392,248,1460767,1,8 +296,288,1460919,2,0,B|289:263|256:246|223:263|215:288,1,105.333334714572,2|0 +128,240,1461222,1,0 +256,360,1461525,21,0 +256,360,1461676,1,8 +216,176,1461979,2,0,B|223:201|256:218|289:201|297:176,1,105.333334714572,2|0 +120,112,1462434,1,0 +168,32,1462585,1,8 +256,8,1462737,1,0 +344,32,1462888,1,0 +392,112,1463040,1,4 +256,192,1463191,12,2,1464858 +278,319,1465312,6,0,B|239:286|239:286|175:289|175:289,1,105.333334714572,8|0 +360,268,1465616,2,0,B|348:219|348:219|378:162|378:162,1,105.333334714572,2|8 +233,64,1465919,2,0,B|272:97|272:97|336:94|336:94,1,105.333334714572,0|8 +151,115,1466222,2,0,B|163:164|163:164|133:221|133:221,1,105.333334714572,8|0 +94,295,1466525,5,8 +194,352,1466676,2,0,B|203:291|254:272|254:272|315:249|310:184,1,210.666669429143,4|0 +328,96,1467131,1,8 +256,40,1467282,1,0 +184,96,1467434,1,0 +201,192,1467585,2,0,B|196:249|257:272|257:272|308:291|318:352,1,210.666669429143,2|0 +418,295,1468040,5,8 +472,216,1468191,2,0,B|416:192|424:128|424:128,1,105.333334714572 +344,80,1468494,2,0,B|304:96|264:80|256:48|256:48|248:80|208:96|168:80,1,210.666669429143,2|0 +168,176,1468949,2,0,B|216:208|216:208|256:184|256:184|296:208|296:208|344:176,1,210.666669429143,8|0 +256,280,1469403,5,2 +40,216,1469706,2,0,B|97:187|88:128|88:128,1,105.333334714572,0|8 +159,47,1470009,1,0 +257,24,1470161,1,0 +355,49,1470312,2,0,B|483:105|483:330|316:388|254:334|254:334|168:248|196:161|312:161|339:248|254:334|254:334|168:392|24:307|24:105|173:40,1,1264.00001657486,2|8 +264,76,1472282,5,8 +264,76,1472434,1,0 +264,76,1472585,1,8 +264,76,1472737,1,0 +264,76,1472888,1,8 +264,76,1473040,1,4 +400,320,1473494,1,6 +112,320,1473949,1,4 +256,192,1474100,12,0,1476676 +256,44,1505977,5,4 +172,96,1506172,1,4 +256,148,1506367,2,2,B|256:364,1,200,4|6 +100,332,1507536,6,0,B|80:216|132:128,1,200,0|8 +300,36,1508315,2,0,B|372:104|488:120,1,200 +472,220,1508899,1,0 +376,188,1509094,1,0 +216,308,1509484,2,0,B|112:308|16:376,1,200,8|0 +68,172,1510263,5,4 +220,44,1510652,1,0 +228,144,1510847,1,0 +308,204,1511042,1,8 +428,44,1511432,1,0 +488,236,1511821,1,0 +440,324,1512016,1,0 +348,284,1512211,1,0 +160,356,1512600,2,0,B|192:256|164:156,1,200,8|0 +348,76,1513380,5,6 +152,44,1513769,2,0,B|108:60|96:128,2,100,0|0|8 +256,216,1514549,1,0 +256,216,1514938,2,0,B|368:216,2,100 +64,164,1515717,2,0,B|124:72|224:52,1,200,8|0 +420,84,1516497,5,4 +384,280,1516886,1,0 +192,332,1517276,1,8 +68,176,1517665,1,0 +268,200,1518055,2,0,B|320:224|364:192,2,100 +116,104,1518834,5,8 +120,204,1519029,1,0 +220,188,1519224,1,0 +216,88,1519419,2,2,B|316:60|428:92,1,200 +364,176,1520003,1,0 +428,252,1520198,1,2 +260,364,1520587,5,0 +252,264,1520782,1,0 +156,288,1520977,2,2,B|116:188|180:88,1,200 +256,36,1521562,1,0 +396,176,1521951,5,8 +304,132,1522146,1,0 +204,124,1522341,1,0 +120,180,1522536,2,2,B|100:296|212:356,1,200 +256,268,1523120,1,0 +316,348,1523315,2,2,B|415:295|395:179,1,200 +296,168,1523899,1,0 +268,72,1524094,2,2,B|180:120|56:68,1,200 +32,164,1524678,1,0 +172,304,1525068,1,8 +216,216,1525263,5,0 +316,224,1525458,1,0 +332,124,1525652,2,2,B|460:112|492:216,1,200 +420,280,1526237,1,0 +336,336,1526432,2,2,B|240:352|128:336,1,200 +56,280,1527016,1,0 +68,180,1527211,2,2,B|172:116|204:20,1,200 +256,116,1527795,1,0 +432,212,1528185,1,8 +336,244,1528380,5,0 +408,316,1528574,1,0 +316,356,1528769,2,2,B|112:356,1,200 +16,356,1529354,1,0 +32,156,1529743,6,0,B|16:108|32:52,1,100,8|0 +104,128,1530133,2,0,B|120:180|176:208,1,100 +200,108,1530523,2,0,B|222:195|310:225|393:202|416:96,1,300,4|0 +476,184,1531302,1,8 +452,320,1531497,5,0 +360,360,1531691,1,0 +276,308,1531886,2,2,B|180:348|80:256,1,200 +32,184,1532471,1,0 +32,184,1532665,2,2,B|60:52|176:52,1,200 +260,64,1533250,1,0 +260,64,1533445,2,2,B|344:148|260:248,1,200 +196,316,1534029,2,0,B|80:316,2,100,0|0|8 +336,316,1534613,5,0 +432,296,1534808,1,0 +436,196,1535003,2,2,B|428:84|300:32,1,200 +256,116,1535587,1,0 +188,44,1535782,2,2,B|83:85|75:197,1,200 +176,184,1536367,2,0,B|184:240|135:282,1,100,0|2 +200,356,1536756,1,4 +256,164,1537146,1,0 +320,352,1537536,1,8 +448,292,1537730,6,0,B|412:244|444:184,2,100,0|0|2 +484,96,1538510,1,0 +392,64,1538704,1,0 +312,124,1538899,1,2 +216,300,1539289,1,0 +124,340,1539484,1,0 +108,240,1539678,1,2 +188,180,1539873,2,0,B|156:80|44:40,2,200,0|0|8 +280,72,1540847,5,2 +380,84,1541042,1,0 +424,172,1541237,1,2 +440,272,1541432,1,0 +372,344,1541626,2,2,B|264:384|188:292,1,200,2|0 +256,220,1542211,6,0,B|144:220,1,100,8|0 +168,120,1542600,2,0,B|56:120,1,100 +40,216,1542990,2,0,B|104:304|216:320,1,200,4|0 +256,232,1543574,1,0 +256,232,1543769,1,8 +388,272,1543964,5,0 +404,172,1544159,1,0 +364,80,1544354,2,2,B|160:80,1,200 +72,124,1544938,1,0 +160,168,1545133,2,2,B|108:268|192:360,1,200 +260,288,1545717,1,0 +336,352,1545912,1,2 +388,160,1546302,1,0 +484,184,1546497,1,0 +464,88,1546691,2,2,B|364:48|248:88,1,200 +256,180,1547276,1,0 +256,192,1547471,12,6,1549224 +408,32,1550782,5,6 +104,132,1551172,1,0 +408,228,1551562,1,8 +100,312,1551951,1,2 +256,272,1552341,5,0 +256,172,1552536,1,0 +256,272,1552730,1,0 +256,72,1553120,1,8 +56,72,1553510,6,2,B|84:164|20:264,1,200,2|6 +160,120,1554289,2,2,B|256:80|356:124,1,200,2|10 +492,268,1555068,2,2,B|429:169|457:77,1,200 +356,80,1555652,1,0 +260,60,1555847,1,2 +256,220,1556237,1,8 +256,220,1556626,1,0 +224,316,1556821,1,0 +124,308,1557016,5,6 +256,60,1557406,1,0 +380,312,1557795,1,8 +256,60,1558185,2,2,B|256:264,1,200,2|0 +256,260,1558769,1,0 +256,260,1558964,1,0 +256,192,1559354,12,0,1561302 +68,116,1561691,5,0 +168,116,1561886,1,8 +216,136,1561984,1,8 +260,116,1562081,1,8 +360,116,1562276,1,8 +324,208,1562471,1,8 +424,192,1562665,1,0 +360,116,1562860,1,0 +432,280,1563055,6,0,B|384:300|320:292,1,100,0|6 +184,160,1563639,2,0,B|128:160|104:108,2,100,0|0|8 +368,80,1564419,2,2,B|360:196|276:256,1,200 +228,168,1565003,1,0 +280,252,1565198,1,0 +100,336,1565587,6,2,B|32:272|32:136,1,200,10|2 +84,64,1566172,2,0,B|140:64|180:96,1,100,0|4 +256,276,1566756,1,2 +368,108,1567146,1,8 +488,268,1567536,2,2,B|440:348|304:328,1,200 +212,348,1568120,1,0 +200,248,1568315,2,2,B|136:164|12:176,1,200,2|10 +168,40,1569094,1,0 +256,84,1569289,2,0,B|276:28,2,50,0|0|4 +472,192,1569873,5,0 +256,336,1570263,1,8 +40,192,1570652,2,2,B|248:192,1,200,2|0 +240,192,1571237,1,0 +240,192,1571432,1,0 +256,192,1571821,12,0,1573769 +392,292,1574159,5,0 +360,156,1574354,1,8 +236,92,1574549,1,0 +128,180,1574743,1,0 +112,320,1574938,1,8 +240,264,1575133,1,0 +128,180,1575328,1,0 +284,152,1575523,5,0 +300,200,1575620,1,0 +316,248,1575717,1,4 +68,48,1585068,5,2 +132,280,1585652,1,2 +192,48,1586237,1,2 +432,192,1586626,5,2 +192,192,1587211,1,2 +316,88,1587600,5,0 +416,72,1587795,1,0 +316,88,1587990,2,2,B|344:196|288:288,1,200,2|2 +220,352,1588574,1,0 +200,256,1588769,2,2,B|124:192|12:168,1,200 +64,80,1589354,1,0 +64,80,1589549,1,2 +260,44,1589938,2,2,B|412:44,1,150,0|8 +488,104,1590717,5,0 +472,204,1590912,1,0 +376,236,1591107,1,2 +204,340,1591497,1,0 +248,252,1591691,1,0 +148,260,1591886,1,2 +28,100,1592276,1,0 +128,104,1592471,1,0 +208,44,1592665,2,2,B|324:32|380:132,1,200 +428,216,1593250,1,0 +484,24,1593639,1,8 +452,120,1593834,5,0 +428,216,1594029,1,0 +340,164,1594224,1,2 +256,344,1594613,1,0 +256,244,1594808,1,0 +256,344,1595003,1,2 +60,300,1595393,1,0 +156,276,1595587,1,0 +132,180,1595782,2,2,B|108:72|20:8,1,200 +20,316,1596756,1,8 +160,328,1596951,5,0 +260,348,1597146,1,0 +328,276,1597341,1,2 +300,180,1597536,1,0 +204,164,1597730,1,2 +204,164,1598315,1,8 +28,260,1598704,5,0 +80,172,1598899,1,0 +156,240,1599094,1,0 +320,168,1599484,1,0 +280,76,1599678,1,0 +380,84,1599873,1,8 +404,180,1600068,6,0,B|428:284,2,100,0|8|10 +256,44,1600847,1,0 +256,144,1601042,1,0 +256,44,1601237,1,2 +56,68,1601626,2,0,B|88:120|56:168,1,100 +52,264,1602016,2,2,B|96:364|232:352,1,200 +312,328,1602600,1,0 +152,208,1602990,1,8 +208,80,1603185,5,2 +304,100,1603380,1,0 +400,80,1603574,1,2 +464,268,1603964,1,0 +404,348,1604159,1,0 +304,352,1604354,1,2 +128,256,1604743,1,0 +224,280,1604938,1,0 +316,236,1605133,2,2,B|440:236|500:136,2,200,2|0|2 +224,280,1606107,1,8 +256,144,1606302,5,0 +160,120,1606497,1,0 +96,196,1606691,1,2 +292,232,1607081,1,0 +348,316,1607276,1,0 +444,292,1607471,1,2 +248,328,1607860,1,0 +248,328,1608055,2,2,B|148:292|108:176,1,200,2|0 +116,88,1608639,1,2 +200,144,1608834,2,0,B|252:164|312:144,2,100,0|0|8 +252,60,1609419,6,0,B|300:40|356:64,1,100,2|0 +440,100,1609808,2,0,B|420:148|456:216,1,100,2|0 +408,288,1610198,1,2 +124,192,1610782,5,8 +252,344,1611172,1,0 +156,316,1611367,1,0 +60,348,1611562,1,0 +44,148,1611951,2,0,B|112:68|224:64,1,200,0|8 +356,36,1612536,5,0 +328,132,1612730,1,0 +428,140,1612925,2,2,B|448:256|344:324,1,200 +276,256,1613510,1,0 +204,324,1613704,2,2,B|100:324|64:188,1,200 +36,104,1614289,1,0 +116,44,1614484,2,2,B|324:44,1,200 +416,52,1615068,1,0 +480,128,1615263,2,2,B|472:232|352:284,1,200 +356,180,1615847,2,2,B|296:172|272:244,2,100 +132,352,1616626,5,8 +60,232,1616821,1,8 +120,104,1617016,1,8 +240,32,1617211,1,8 +376,72,1617406,1,8 +416,208,1617600,1,0 +236,204,1617795,6,2,B|310:134|424:135,1,200,2|0 +472,328,1618574,1,8 +388,276,1618769,1,0 +476,228,1618964,1,0 +472,328,1619159,1,0 +324,340,1619354,6,0,B|220:364|124:320,1,200,6|0 +44,140,1620133,1,8 +132,188,1620328,1,0 +204,116,1620523,2,2,B|312:116|396:36,1,200 +456,120,1621107,1,0 +364,156,1621302,1,2 +468,328,1621691,1,8 +284,248,1622081,2,2,B|212:188|212:188|192:64,1,200,2|6 +28,192,1622860,5,2 +184,316,1623250,1,8 +248,124,1623639,2,2,B|352:60|458:182|384:292,1,300,2|0 +389,283,1624419,1,2 +200,216,1624808,1,8 +44,340,1625198,1,0 +44,340,1625393,5,0 +44,340,1625490,1,0 +44,340,1625587,2,0,B|88:136,1,200,6|0 +276,80,1626367,2,0,B|372:52|476:88,2,200,8|2|0 +184,124,1627341,1,0 +256,192,1627536,1,0 +256,192,1627925,12,0,1629873 +256,36,1630263,5,0 +292,56,1630458,1,8 +312,88,1630652,1,0 +316,128,1630847,1,0 +308,168,1631042,1,8 +296,208,1631237,1,0 +272,240,1631432,1,0 +244,268,1631626,1,0 +204,276,1631821,6,2,B|91:252|43:156,1,200,6|2 +304,48,1632600,2,0,B|428:72|444:204,2,200,8|2|0 +304,48,1633574,1,0 +304,48,1633769,1,2 +456,284,1634159,2,0,B|372:344|264:304,2,200,8|2|4 +240,104,1635328,6,2,B|140:108|72:204,1,200,2|8 +340,108,1636107,2,2,B|304:212|172:196,1,200 +180,196,1636691,1,0 +180,196,1636886,2,2,B|196:324|328:324,1,200,2|10 +452,84,1637665,1,0 +452,84,1637860,5,8 +452,84,1637958,1,8 +452,84,1638055,2,0,B|348:116|244:68,1,200,6|0 +64,124,1638834,1,8 +64,124,1639224,2,2,B|64:228|152:308,1,200 +244,316,1639808,1,0 +256,216,1640003,1,0 +256,192,1640393,12,8,1641951 +416,192,1642536,5,0 +416,192,1642730,2,8,B|432:116,2,66.6666666666667,0|8|8 +352,272,1643120,2,0,B|368:356,2,66.6666666666667,8|8|0 +292,192,1643510,2,0,B|272:120,2,66.6666666666667,0|8|8 +232,272,1643899,2,0,B|204:348,2,66.6666666666667,8|0|0 +132,296,1644289,1,4 +104,96,1644678,5,0 +196,136,1644873,1,0 +288,96,1645068,1,8 +456,208,1645458,1,0 +356,192,1645652,1,0 +264,228,1645847,2,2,B|152:228|60:324,2,200,10|2|10 +432,116,1647016,1,6 +264,228,1647406,5,8 +344,172,1647600,2,0,B|364:124,2,50 +248,152,1647990,1,0 +176,80,1648185,1,8 +76,96,1648380,1,0 +32,188,1648574,1,0 +84,272,1648769,1,0 +132,260,1648867,1,0 +176,280,1648964,6,2,B|248:344|368:312,1,200,10|2 +248,152,1649743,1,8 +424,56,1650133,2,2,B|320:28|224:56,1,200,2|10 +256,252,1650912,2,2,B|368:252|432:364,1,200,2|10 +220,344,1651691,5,2 +120,328,1651886,1,0 +128,228,1652081,1,8 +36,48,1652471,2,2,B|244:48,1,200,2|10 +436,60,1653250,2,2,B|420:160|468:268,1,200,2|10 +376,304,1653834,5,0 +292,192,1654029,1,0 +268,236,1654126,1,0 +220,248,1654224,1,0 +172,236,1654321,1,0 +148,192,1654419,1,8 +84,68,1654613,1,0 +32,196,1654808,5,0 +32,196,1655003,1,0 +32,196,1655198,1,10 +256,348,1655587,1,2 +476,192,1655977,1,10 +256,40,1656367,2,0,B|256:152,2,100,2|0|6 +160,192,1657146,5,0 +256,220,1657341,1,0 +340,164,1657536,1,8 +156,92,1657925,1,0 +80,156,1658120,1,0 +92,256,1658315,1,10 +276,176,1658704,6,2,B|312:288|196:344,2,200,2|10|2 +212,100,1659678,1,0 +308,68,1659873,1,8 +472,184,1660263,2,0,B|472:244|424:280,2,100,0|0|8 +376,360,1661042,1,0 +324,272,1661237,1,0 +324,272,1661334,1,0 +324,272,1661432,6,0,B|216:248|128:328,1,200,8|0 +52,268,1662016,1,0 +36,168,1662211,2,0,B|84:68|196:64,1,200,2|2 +256,144,1662795,1,0 +256,192,1662990,12,0,1666107 +256,192,1677016,12,4,1678574 +256,180,1678964,5,0 +256,180,1679159,1,0 +256,180,1679354,1,2 +160,308,1679743,1,0 +100,252,1679938,1,0 +56,184,1680133,2,0,B|140:92,1,100,2|0 +196,76,1680523,2,0,B|308:76,3,100,0|0|2|0 +376,76,1681302,2,0,B|412:124|396:176,1,100 +364,244,1681691,5,4 +208,272,1682081,2,0,B|208:392,2,100,0|0|2 +68,192,1682860,1,0 +140,156,1683055,1,0 +152,76,1683250,1,2 +256,200,1683639,1,0 +364,80,1684029,1,2 +428,128,1684224,1,0 +440,208,1684419,1,0 +392,272,1684613,1,0 +392,272,1684808,6,0,B|304:264|180:304,1,200,4|0 +256,152,1685587,1,2 +256,152,1685782,1,0 +256,152,1685977,1,0 +100,188,1686367,1,2 +256,228,1686756,1,0 +412,188,1687146,1,2 +364,124,1687341,1,0 +292,92,1687536,1,0 +220,124,1687730,1,0 +172,188,1687925,1,2 +472,312,1688315,5,0 +400,348,1688510,1,0 +300,348,1688704,1,8 +184,312,1688899,1,8 +136,180,1689094,1,8 +248,68,1689289,1,8 +400,164,1689484,1,6 +56,68,1690263,5,0 +32,132,1690393,1,0 +36,200,1690523,1,8 +68,256,1690652,1,8 +124,296,1690782,1,8 +192,300,1690912,1,0 +252,272,1691042,6,2,B|360:300|428:200,1,200,6|2 +300,48,1691821,1,8 +156,188,1692211,1,2 +284,240,1692406,1,0 +396,172,1692600,2,0,B|452:160|492:200,2,100,0|0|2 +256,316,1693380,1,8 +220,120,1693769,6,2,B|128:48|32:120,1,200,2|6 +56,316,1694549,2,2,B|260:316,1,200,2|10 +452,280,1695328,1,2 +424,184,1695523,1,0 +444,88,1695717,1,0 +348,120,1695912,1,0 +248,128,1696107,1,2 +256,328,1696497,1,8 +92,212,1696886,1,0 +92,212,1697081,5,0 +92,212,1697178,1,0 +92,212,1697276,2,2,B|191:234|304:212,2,200,6|2|10 +200,44,1698445,2,2,B|292:20|416:52,1,200 +444,136,1699029,1,0 +408,232,1699224,1,0 +256,192,1699613,12,0,1701562 +428,192,1701951,5,4 +376,192,1702049,1,0 +328,192,1702146,1,0 +280,192,1702243,1,0 +228,192,1702341,6,0,B|240:260,2,66.6666666666667,0|0|0 +132,228,1702730,2,0,B|100:300,2,66.6666666666667,0|0|0 +100,132,1703120,2,0,B|28:152,2,66.6666666666667 +192,88,1703510,6,2,B|284:44|404:92,1,200,6|2 +420,284,1704289,2,2,B|332:360|228:284,1,200,10|2 +156,352,1704873,1,0 +156,252,1705068,1,0 +60,280,1705263,1,0 +52,180,1705458,2,2,B|148:132|192:32,1,200,2|10 +360,284,1706237,6,2,B|448:204|384:92,2,200,2|6|2 +256,112,1707406,1,8 +184,300,1707795,2,2,B|96:268|56:136,1,200 +32,56,1708380,1,0 +132,56,1708574,2,2,B|352:56,1,200,2|10 +480,188,1709354,5,8 +460,288,1709549,1,8 +412,280,1709646,1,8 +380,240,1709743,1,6 +200,328,1710133,2,0,B|160:236|196:120,2,200,0|8|2 +100,152,1711302,1,0 +28,220,1711497,1,0 +16,120,1711691,1,8 +96,60,1711886,1,0 +196,56,1712081,2,2,B|308:32|400:88,1,200 +356,176,1712665,1,0 +308,264,1712860,1,4 +256,192,1712958,12,0,1714419 +256,308,1748243,6,0,B|256:364,2,54.9999983608723 +256,252,1749012,2,0,B|244:216|268:192|256:144,1,109.999996721745,0|0 +284,36,1750038,1,0 +228,36,1750294,1,0 +347,99,1750807,6,0,B|392:128|424:192|392:260|348:284,1,219.999993443489 +256,192,1752602,1,0 +164,100,1753115,2,0,B|120:124|88:192|120:256|164:284,1,219.999993443489 +332,292,1755166,54,0,B|320:352|256:392|192:352|180:292,1,219.999993443489 +176,236,1756448,1,0 +228,216,1756704,1,0 +284,216,1756961,1,0 +336,236,1757217,1,0 +436,188,1757730,1,0 +348,124,1758243,5,0 +308,84,1758499,2,0,B|256:68|256:68|204:84,1,109.999996721745,0|0 +204,140,1759268,2,0,B|200:184|256:220|312:184|308:140,1,164.999995082617,0|0 +356,332,1760807,6,0,B|324:360|288:364|256:336|256:336|224:364|188:360|156:332,1,219.999993443489,0|0 +204,272,1762345,2,0,B|256:300|308:272,1,109.999996721745,2|0 +336,188,1763371,2,0,B|304:168|256:188|256:188|208:208|176:196,1,165.99999386549,4|8 +100,164,1764140,6,0,B|76:132|74:87,1,82.9999969327451,0|8 +140,32,1764653,2,0,B|220:56,1,82.9999969327451,0|8 +300,76,1765166,1,0 +324,156,1765422,2,0,B|304:188|256:220|208:188|186:154,1,165.99999386549,2|8 +212,76,1766192,1,0 +292,55,1766448,2,0,B|372:32,1,82.9999969327451,2|0 +436,86,1766961,2,0,B|436:132|412:164,1,82.9999969327451,8|0 +336,236,1767474,2,0,B|256:196|176:236,2,165.99999386549,4|8|2 +416,252,1768756,5,0 +432,172,1769012,1,8 +348,156,1769268,2,0,B|260:155|212:76,1,165.99999386549,2|0 +299,76,1770038,2,0,B|251:155|163:155,1,165.99999386549,2|8 +80,144,1770807,1,0 +132,80,1771063,1,2 +52,68,1771320,1,0 +16,196,1771576,2,0,B|36:360,1,165.99999386549,4|8 +116,340,1772345,2,0,B|108:280|108:280|100:220|144:188,1,165.99999386549,2|0 +224,168,1773115,5,8 +288,216,1773371,1,0 +367,196,1773627,2,0,B|412:164|404:104|404:104|396:44,2,165.99999386549,2|8|8 +320,128,1774909,1,0 +256,72,1775166,1,2 +196,128,1775422,1,0 +180,208,1775679,6,0,B|200:284|272:284|272:284|308:284,1,165.99999386549,4|8 +392,288,1776448,2,0,B|372:364|300:364|300:364|264:364,1,165.99999386549,2|0 +180,360,1777217,2,0,B|156:272|64:256,1,165.99999386549,2|8 +40,176,1777986,5,0 +96,116,1778243,1,8 +176,100,1778499,1,0 +256,112,1778756,1,2 +344,192,1779012,1,0 +256,272,1779268,1,8 +168,192,1779525,1,0 +256,112,1779781,1,4 +324,44,1780038,54,0,B|408:32,1,82.9999969327451,0|8 +500,96,1780551,2,0,B|416:108,1,82.9999969327451,0|2 +364,192,1781063,2,0,B|388:272,1,82.9999969327451,0|8 +336,347,1781576,2,0,B|256:314|170:348,1,165.99999386549,4|0 +148,192,1782345,2,0,B|124:272,1,82.9999969327451,2|0 +64,216,1782858,5,8 +88,136,1783115,2,0,B|112:56,1,82.9999969327451,2|0 +196,52,1783627,2,0,B|236:76|256:108|256:108|276:76|316:52,1,165.99999386549,4|0 +364,120,1784397,5,2 +256,176,1784653,1,0 +148,120,1784909,1,2 +336,224,1785166,1,0 +176,224,1785422,1,2 +256,360,1785679,1,0 +256,276,1785935,1,8 +256,192,1786192,1,0 +344,136,1786448,6,0,B|360:52,1,82.9999969327451,8|0 +256,1,1786961,2,0,B|256:84,1,82.9999969327451,2|0 +168,136,1787474,2,0,B|152:52,1,82.9999969327451,8|0 +44,176,1787986,2,0,B|24:340,1,165.99999386549,4|8 +112,296,1788756,2,0,B|116:212,1,82.9999969327451,0|2 +204,81,1789268,2,0,B|204:164,1,82.9999969327451,0|8 +280,244,1789781,5,0 +468,208,1790038,2,0,B|488:44,1,165.99999386549,4|8 +400,88,1790807,2,0,B|396:172,1,82.9999969327451,0|2 +309,302,1791320,2,0,B|308:220,1,82.9999969327451,0|8 +256,136,1791833,1,0 +184,56,1792089,2,0,B|208:24|256:8|300:24|330:57,1,165.99999386549,4|8 +328,156,1792858,5,0 +256,224,1793115,2,0,B|176:276|208:368,1,165.99999386549,2|8 +305,366,1793884,2,0,B|338:275|254:224,1,165.99999386549,2|8 +256,124,1794653,1,8 +256,48,1795166,5,0 +256,244,1795422,1,8 +184,124,1795679,1,8 +328,124,1795935,1,8 +400,244,1796192,1,4 +340,336,1796448,6,2,B|316:280|256:248|196:280|171:338,1,219.999993443489,2|0 +64,352,1797217,2,0,B|40:244,1,109.999996721745,2|0 +92,148,1797730,1,8 +184,84,1797986,2,0,B|268:100|316:156|332:228,1,219.999993443489,4|0 +256,308,1798756,1,8 +180,228,1799012,2,0,B|197:155|245:99|329:83,1,219.999993443489,2|0 +432,120,1799781,1,8 +456,336,1800038,6,0,B|348:288|348:160,1,219.999993443489,4|0 +312,56,1800807,1,8 +200,56,1801063,1,0 +256,216,1801320,1,2 +256,104,1801576,1,0 +164,160,1801833,1,8 +108,68,1802089,1,0 +165,160,1802345,2,0,B|164:288|56:336,1,219.999993443489,4|8 +12,236,1803115,5,0 +64,216,1803243,2,0,B|144:236|200:304,1,164.999995082617,2|0 +308,276,1803884,1,8 +232,196,1804140,1,2 +96,132,1804397,2,0,B|72:75|124:3|204:35|212:103,1,219.999993443489,4|8 +300,36,1805166,1,0 +356,36,1805294,2,0,B|388:32|408:16|408:16|424:40|448:52,1,109.999996721745,2|0 +500,72,1805679,5,2 +492,180,1805935,1,8 +388,148,1806192,1,0 +416,252,1806448,2,0,B|440:309|388:381|308:349|300:281,1,219.999993443489,4|8 +208,220,1807217,2,0,B|199:152|119:120|67:192|91:249,1,219.999993443489,2|0 +176,320,1807986,1,8 +280,352,1808243,1,0 +404,276,1808499,5,4 +404,276,1808756,2,0,B|336:192,1,109.999996721745,2|8 +108,107,1809268,2,0,B|178:193,1,109.999996721745,2|0 +328,100,1809781,2,0,B|360:48|408:28,2,109.999996721745,0|8|2 +185,283,1810551,2,0,B|152:336|104:356,2,109.999996721745,0|2|8 +296,228,1811320,6,0,B|260:212|252:172|216:156,2,109.999996721745,0|2|8 +368,144,1812089,5,8 +308,52,1812345,1,8 +256,36,1812474,1,0 +204,52,1812602,1,4 +144,144,1812858,1,2 +92,240,1813115,1,8 +148,336,1813371,1,0 +256,344,1813627,2,0,B|308:324|324:264,1,109.999996721745,2|0 +268,168,1814140,5,8 +204,256,1814397,2,0,B|292:332|408:316,1,219.999993443489,4|0 +484,236,1815166,1,8 +492,124,1815422,2,0,B|464:52|368:32|312:100,1,219.999993443489,2|0 +216,156,1816192,1,8 +56,48,1816448,6,0,B|8:168|92:252,1,219.999993443489,4|0 +200,256,1817217,2,0,B|312:256,1,109.999996721745,8|0 +420,240,1817730,2,0,B|360:332,1,109.999996721745,2|0 +312,360,1818115,1,2 +200,360,1818371,1,0 +152,332,1818499,2,0,B|92:240,1,109.999996721745,2|4 +256,252,1819012,5,0 +208,100,1819268,1,8 +332,196,1819525,1,0 +180,196,1819781,1,2 +304,100,1820038,5,0 +256,168,1820294,1,8 +400,108,1820551,1,0 +420,160,1820679,1,0 +440,212,1820807,1,4 +356,284,1821063,2,0,B|304:288|256:244|256:244|208:288|156:284,1,219.999993443489,2|0 +52,320,1821833,1,2 +72,212,1822089,5,0 +92,160,1822217,1,0 +112,108,1822345,1,8 +156,8,1822602,2,0,B|207:4|255:48|255:48|303:4|354:7,1,219.999993443489,4|0 +352,120,1823371,1,8 +256,172,1823627,1,2 +160,120,1823884,1,0 +192,224,1824140,5,8 +180,276,1824268,1,0 +204,324,1824397,1,8 +256,344,1824525,1,0 +308,324,1824653,1,2 +332,276,1824781,1,0 +320,224,1824909,1,4 +152,140,1830294,6,0,B|232:111,1,83.5000010451675,0|8 +360,244,1830807,2,0,B|280:272,1,83.5000010451675,0|2 +124,240,1831320,2,0,B|204:212,1,83.5000010451675,0|8 +388,144,1831833,2,0,B|308:172,1,83.5000010451675,0|2 +208,60,1832345,2,0,B|236:140,1,83.5000010451675,0|8 +304,324,1832858,2,0,B|276:244,1,83.5000010451675,0|4 +440,232,1833627,5,8 +428,152,1833884,1,0 +360,200,1834140,1,2 +504,180,1834397,5,0 +492,100,1834653,1,8 +416,72,1834909,1,0 +332,68,1835166,2,0,B|292:68|292:68|256:44|256:44|220:68|220:68|180:68,1,167.000002090335,2|8 +96,72,1835935,1,0 +20,100,1836192,1,2 +8,180,1836448,1,0 +84,148,1836704,1,8 +176,284,1837217,6,0,B|343:284,2,167.000002090335,0|8|0 +100,164,1838499,6,0,B|180:192,1,83.5000010451675,2|8 +412,164,1839012,2,0,B|332:192,1,83.5000010451675,0|2 +76,72,1839525,2,0,B|156:100,1,83.5000010451675,0|8 +436,72,1840038,2,0,B|356:100,1,83.5000010451675,0|2 +256,52,1840551,1,0 +256,136,1840807,1,8 +256,176,1840935,1,0 +256,216,1841063,1,8 +256,300,1841320,1,4 +92,312,1841833,6,0,B|48:304|28:264,1,83.5000010451675,8|0 +104,232,1842345,1,2 +168,180,1842602,1,0 +192,100,1842858,1,8 +196,16,1843115,1,0 +116,36,1843371,2,0,B|120:124|42:176,2,167.000002090335,4|8|2 +176,152,1844653,6,4,B|256:136|256:136|338:152,1,167.000002090335,4|0 +395,36,1845422,2,0,B|392:124|468:178,1,167.000002090335,4|8 +492,96,1846192,2,0,B|368:205,1,167.000002090335,2|2 +292,172,1846961,1,8 +152,104,1847217,6,0,B|116:188|17:185,1,167.000002090335,2|0 +8,268,1847986,2,0,B|85:296,1,83.5000010451675,8|0 +221,264,1848499,2,0,B|143:235,1,83.5000010451675,2|0 +220,344,1849012,2,0,B|299:374,1,83.5000010451675,8|0 +432,356,1849525,5,4 +508,328,1849781,2,0,B|488:288|445:276,1,83.5000010451675,0|8 +364,268,1850294,2,0,B|358:176|289:122,1,167.000002090335 +352,68,1851063,2,0,B|296:8,1,83.5000010451675,8|0 +216,7,1851576,2,0,B|160:68,1,83.5000010451675,2|0 +80,88,1852089,2,0,B|44:168,1,83.5000010451675,8|0 +16,240,1852602,1,2 +32,312,1852858,2,0,B|104:332|124:260|189:280,1,167.000002090335 +323,280,1853627,6,0,B|388:260|408:332|481:311,1,167.000002090335,4|8 +456,240,1854397,2,0,B|388:260|408:332|340:352,1,167.000002090335,0|2 +256,280,1855166,1,8 +148,324,1855422,1,0 +104,220,1855679,1,2 +212,176,1855935,1,0 +256,280,1856192,5,8 +104,220,1856448,1,0 +164,64,1856704,1,2 +316,124,1856961,1,0 +316,124,1857089,1,8 +316,124,1857217,1,8 +420,252,1857474,1,8 +420,252,1857602,1,8 +420,252,1857730,5,4 +476,192,1857986,1,0 +500,272,1858243,2,0,B|496:332|424:344|424:344|372:352,1,167.000002090335,8|2 +300,312,1859012,1,0 +256,240,1859268,1,8 +212,312,1859525,1,0 +137,351,1859781,2,0,B|87:344|87:344|15:332|10:271,1,167.000002090335,4|8 +96,264,1860551,2,0,B|176:244,1,83.5000010451675,0|2 +124,180,1861063,2,0,B|200:148,2,83.5000010451675,0|8|0 +120,96,1861833,6,0,B|176:28|271:47,1,167.000002090335,4|8 +292,160,1862602,1,0 +256,264,1862858,1,2 +220,160,1863115,1,0 +312,224,1863371,1,8 +200,224,1863627,1,0 +243,48,1863884,6,0,B|336:28|393:97,1,167.000002090335,4|8 +460,168,1864653,1,0 +408,252,1864909,1,2 +424,348,1865166,1,0 +324,336,1865422,1,8 +244,280,1865679,1,8 +224,316,1865807,1,8 +188,336,1865935,5,4 +168,256,1866192,2,0,B|212:188|306:172,1,167.000002090335,2|0 +336,96,1866961,2,0,B|376:112|384:160,1,83.5000010451675,2|0 +424,232,1867474,1,8 +344,256,1867730,2,0,B|300:188|206:170,1,167.000002090335,4|0 +128,158,1868499,2,0,B|136:112|176:96,1,83.5000010451675,8|0 +120,12,1869012,2,0,B|112:58|72:74,1,83.5000010451675,2|0 +0,116,1869525,1,8 +40,188,1869781,1,0 +112,148,1870038,1,4 +256,64,1870551,6,0,B|288:132|224:236|256:310,2,250.500003135502,8|2|8 +256,64,1872217,1,0 +380,64,1872474,2,0,B|420:80,1,41.7500005225837 +440,192,1872858,2,0,B|376:164|376:164,1,41.7500005225837 +240,168,1873371,5,8 +204,216,1873499,1,8 +144,224,1873627,1,8 +92,188,1873756,1,0 +88,128,1873884,1,8 +124,76,1874012,1,8 +184,68,1874140,5,4 +292,76,1874397,2,0,B|364:88|360:168|360:168|356:260,1,219.999993443489,2|0 +324,364,1875166,1,2 +256,276,1875422,1,0 +188,364,1875679,1,8 +156,260,1875935,2,0,B|152:168|152:168|148:88|220:76,1,219.999993443489,2|0 +324,104,1876704,1,8 +256,192,1876961,2,0,B|184:104|72:80,1,219.999993443489,2|0 +168,24,1877730,1,8 +256,192,1877986,6,0,B|328:280|440:304,1,219.999993443489,4|0 +352,372,1878756,1,8 +252,328,1879012,2,0,B|216:280|160:276,1,109.999996721745,0|2 +28,300,1879525,2,0,B|64:348|120:352,1,109.999996721745,0|8 +76,224,1880038,1,0 +36,120,1880294,6,0,B|32:76|104:40|120:84|136:128|208:92|196:48,1,219.999993443489,4|8 +204,156,1881063,1,0 +216,208,1881192,2,0,B|228:244|256:244|284:244|296:208,1,109.999996721745,2|0 +308,156,1881576,1,2 +360,24,1881833,1,8 +452,132,1882089,1,2 +476,272,1882345,6,0,B|480:316|408:352|392:308|376:264|304:300|316:344,1,219.999993443489,4|8 +256,252,1883115,1,0 +200,344,1883371,1,2 +108,284,1883627,2,0,B|84:176,1,109.999996721745,0|8 +164,100,1884140,2,0,B|176:208,1,109.999996721745,0|2 +256,132,1884653,2,0,B|256:20,1,109.999996721745,0|8 +348,100,1885166,2,0,B|336:208,1,109.999996721745,0|2 +404,284,1885679,2,0,B|428:176,1,109.999996721745,0|8 +452,68,1886192,1,0 +256,40,1886448,5,4 +152,80,1886704,1,0 +256,196,1886961,1,8 +360,304,1887217,1,2 +256,344,1887474,1,0 +256,196,1887730,1,0 +104,192,1887986,5,8 +144,296,1888243,1,0 +256,196,1888499,1,0 +368,88,1888756,1,2 +408,192,1889012,1,8 +256,196,1889268,1,0 +104,192,1889525,1,2 +144,88,1889781,5,0 +256,40,1890038,1,8 +368,88,1890294,1,8 +396,136,1890422,1,0 +420,184,1890551,1,4 +416,296,1890807,2,0,B|368:312|316:288|316:288|256:256|196:288|196:288|144:312|96:296,1,329.999990165234,2|0 +148,200,1891833,1,0 +256,176,1892089,1,8 +403,79,1892345,6,0,B|456:100|456:100|432:152|456:204|456:204|403:224,1,219.999993443489,4|0 +256,256,1893115,1,8 +109,224,1893371,2,0,B|56:204|56:204|80:152|56:100|56:100|108:80,1,219.999993443489,2|0 +256,48,1894140,1,8 +344,196,1894397,6,0,B|300:264|204:264|160:196,1,219.999993443489,4|0 +152,84,1895166,1,8 +256,48,1895422,1,0 +360,84,1895679,1,2 +440,160,1895935,2,0,B|456:212,1,54.9999983608723,0|2 +412,312,1896320,2,0,B|396:260,1,54.9999983608723,0|2 +256,176,1896704,5,4 +208,328,1896961,1,0 +332,232,1897217,1,8 +180,232,1897474,1,0 +304,328,1897730,1,2 +256,256,1897986,1,0 +116,308,1898243,5,8 +80,264,1898371,1,0 +72,208,1898499,1,2 +84,156,1898627,1,0 +116,112,1898756,1,4 +312,12,1899268,5,8 +412,52,1899525,1,0 +324,120,1899781,1,2 +428,156,1900038,1,0 +428,336,1900294,5,8 +360,248,1900551,2,0,B|292:204|220:316|152:268,1,219.999993443489,4|0 +80,184,1901320,1,8 +188,160,1901576,1,0 +192,104,1901704,1,8 +196,48,1901833,1,8 +316,48,1902089,5,8 +320,104,1902217,1,8 +324,160,1902345,1,0 +340,212,1902474,1,8 +376,256,1902602,1,8 +424,280,1902730,1,0 +480,288,1902858,1,4 +256,132,1917730,5,0 +316,192,1917986,1,0 +256,252,1918243,1,8 +196,192,1918499,1,0 +256,92,1918756,5,2 +360,272,1919012,1,0 +152,272,1919268,1,4 +80,232,1919525,6,0,B|93:151,1,82.9999969327451,0|2 +56,47,1920038,2,0,B|16:120,2,82.9999969327451,0|8|0 +136,32,1920807,1,2 +208,68,1921063,1,0 +352,100,1921320,6,0,B|388:112|432:92|432:92|420:140|436:176,1,165.99999386549,4|2 +424,256,1922089,2,0,B|452:288|496:292,2,82.9999969327451,0|8|0 +360,204,1922858,2,0,B|312:272,1,82.9999969327451,2|0 +208,360,1923371,6,0,B|147:316|111:364|49:325,1,165.99999386549,4|2 +60,240,1924140,2,0,B|108:240|132:208,1,82.9999969327451,0|8 +148,88,1924653,2,0,B|152:132|193:153,1,82.9999969327451,0|2 +212,232,1925166,2,0,B|180:308,1,82.9999969327451 +256,336,1925679,1,0 +332,308,1925935,6,0,B|299:231,1,82.9999969327451,0|0 +312,148,1926448,1,8 +404,60,1926704,1,0 +376,180,1926961,1,2 +328,68,1927217,1,0 +436,132,1927474,1,4 +136,180,1927986,5,2 +108,60,1928243,1,0 +200,140,1928499,1,8 +76,132,1928756,1,0 +184,68,1929012,1,2 +136,180,1929268,1,0 +176,296,1929525,6,0,B|340:296,1,165.99999386549,4|2 +400,236,1930294,2,0,B|330:191,1,82.9999969327451,0|8 +256,152,1930807,1,0 +181,191,1931063,2,0,B|112:236,1,82.9999969327451,2|0 +80,128,1931576,6,0,B|112:48|112:48|188:24,1,165.99999386549,4|2 +256,100,1932345,1,0 +324,24,1932602,2,0,B|400:48|400:48|432:128,1,165.99999386549,8|2 +408,204,1933371,1,0 +388,240,1933499,1,0 +356,268,1933627,1,0 +308,200,1933884,1,0 +256,264,1934140,1,0 +204,200,1934397,1,0 +256,136,1934653,1,8 +104,204,1934909,5,0 +124,240,1935038,1,0 +156,268,1935166,1,0 +256,264,1935422,1,0 +256,280,1935679,1,0 +136,128,1950038,6,0,B|134:99|134:99,5,27.6666656442484 +208,128,1950551,2,0,B|208:95|208:95,5,27.6666656442484 +280,128,1951063,2,0,B|280:97|280:97,5,27.6666656442484 +352,128,1951576,2,0,B|352:99|352:99,5,27.6666656442484 +404,184,1952089,6,0,B|384:244|304:256|304:256|216:268,1,219.999993443489,4|8 +104,280,1952858,1,0 +128,328,1952986,2,0,B|188:328|228:364,1,109.999996721745,2|0 +287,368,1953371,2,0,B|328:332|388:332,1,109.999996721745,2|8 +356,228,1953884,6,0,B|384:184|356:124|356:124|384:68|356:16,1,219.999993443489,4|0 +256,60,1954653,1,8 +155,16,1954909,2,0,B|128:68|156:124|156:124|128:184|156:228,1,219.999993443489,2|0 +256,184,1955679,1,8 +448,128,1955935,6,0,B|468:208|416:288|348:296,1,219.999993443489,4|0 +176,200,1956704,1,8 +256,52,1956961,1,0 +336,200,1957217,1,2 +176,104,1957474,1,0 +336,104,1957730,1,8 +256,248,1957986,1,0 +64,127,1958243,6,0,B|44:208|96:288|164:296,1,219.999993443489,4|8 +208,196,1959012,1,2 +256,168,1959140,1,0 +304,196,1959268,1,2 +388,80,1959525,1,0 +256,20,1959781,1,8 +124,80,1960038,1,2 +76,204,1960294,5,4 +84,336,1960551,2,0,B|112:288,1,54.9999983608723,2|0 +160,244,1960807,1,10 +256,152,1961063,2,0,B|256:208,1,54.9999983608723,2|0 +256,272,1961320,1,2 +428,336,1961576,2,0,B|400:288,1,54.9999983608723,2|0 +352,244,1961833,1,10 +256,332,1962089,1,0 +160,244,1962345,5,2 +216,244,1962474,1,0 +272,232,1962602,1,0 +320,204,1962730,1,0 +344,156,1962858,1,8 +348,100,1962986,1,0 +328,48,1963115,1,0 +284,16,1963243,1,0 +228,16,1963371,5,2 +184,48,1963499,1,0 +164,100,1963627,1,0 +168,156,1963756,1,0 +192,204,1963884,1,8 +240,232,1964012,1,0 +296,244,1964140,1,0 +352,244,1964268,1,0 +408,236,1964397,5,4 +408,124,1964653,1,0 +256,148,1964909,1,8 +316,44,1965166,1,2 +196,44,1965422,1,0 +108,208,1965679,5,2 +256,312,1965935,1,8 +404,208,1966192,1,4 +256,192,1966448,12,4,1968499 +76,64,1969012,5,8 +180,104,1969268,1,0 +140,208,1969525,2,0,B|112:260|56:272,2,109.999996721745,2|0|8 +40,160,1970294,6,0,B|72:276|180:320,1,219.999993443489,4|0 +256,192,1971063,1,8 +332,64,1971320,2,0,B|440:108|472:224,1,219.999993443489,2|0 +256,288,1972089,1,8 +40,223,1972345,6,0,B|72:108|180:64,1,219.999993443489,4|0 +200,172,1973115,2,0,B|312:172,2,109.999996721745,8|0|2 +148,268,1973884,1,0 +204,272,1974012,2,0,B|256:288|256:288|308:272,1,109.999996721745,2|0 +364,268,1974397,1,2 +190,203,1974653,6,0,B|116:168|116:64|192:28,1,219.999993443489,4|8 +256,116,1975422,1,0 +320,28,1975679,2,0,B|396:64|396:168|320:204,1,219.999993443489,4|8 +256,292,1976448,1,0 +168,360,1976704,6,0,B|204:284|308:284|344:360,2,219.999993443489,4|8|2 +144,252,1977986,1,0 +40,216,1978243,1,8 +56,324,1978499,1,4 +256,44,1979012,1,0 +456,324,1979525,1,2 +192,244,1980038,5,8 +180,192,1980166,1,0 +204,144,1980294,1,8 +256,124,1980422,1,0 +308,144,1980551,1,2 +332,192,1980679,1,0 +320,244,1980807,1,4 +256,64,1994397,5,2 +336,320,1994825,1,0 +128,160,1995254,1,0 +384,160,1995682,1,0 +176,320,1996111,1,0 +256,192,1996539,1,0 +336,320,1996968,1,2 +336,144,1997397,6,0,B|320:101|256:69|192:101|176:149,1,200 +384,32,1998254,1,2 +256,192,1998682,1,0 +128,32,1999111,1,0 +176,240,1999539,2,0,B|192:283|256:315|320:283|336:235,1,200,2|0 +128,352,2000397,5,0 +256,192,2000825,1,0 +384,352,2001254,1,0 +472,200,2001682,2,0,B|456:96|456:96|384:32,1,200,0|2 +213,100,2002539,2,0,B|192:128|208:176|255:196|304:176|320:128|296:95,1,200 +126,33,2003397,2,0,B|56:96|56:96|40:200,1,200,2|0 +176,352,2004254,6,0,B|200:312|256:296|256:296|312:312|336:352,1,200,0|2 +301,182,2005111,1,0 +213,182,2005325,1,0 +304,24,2005754,2,0,B|349:50|349:50|368:96,1,100,0|2 +208,24,2006397,2,0,B|163:50|163:50|144:96,1,100 +339,233,2007254,6,0,B|380:288|348:384|255:424|157:384|125:288|173:223,1,400,2|0 +86,73,2008539,2,0,B|108:33|161:17|214:22|256:77|256:77|299:21|352:13|416:31|429:79|429:79,1,400,2|0 +336,248,2009825,2,0,B|320:202|256:170|192:202|176:245,1,200,2|0 +176,336,2010468,2,0,B|191:381|255:413|319:381|335:338,1,200 +256,296,2011111,5,2 +336,136,2011539,1,0 +176,136,2011968,1,0 +256,176,2012182,1,0 +336,136,2012397,2,0,B|368:80|336:32|304:16|304:16|256:52|256:52|208:16|208:16|176:32|136:80|180:144,1,400,2|0 +94,276,2013682,2,0,B|134:359|222:383|262:386|300:380|377:360|420:275,1,400,2|0 +256,192,2014968,5,2 +104,112,2015397,1,0 +184,64,2015611,2,0,B|199:18|263:-13|327:18|343:61,1,200 +408,112,2016254,1,2 +256,192,2016682,5,0 +168,360,2017111,1,0 +256,320,2017325,1,0 +340,360,2017539,2,0,B|395:298|408:225|358:155|311:129|254:113|210:125|154:141|108:209|110:255|111:328|188:373,1,600,2|2 +32,240,2019254,2,0,B|32:140,1,100 +104,84,2019682,1,0 +176,248,2020111,2,0,B|200:288|256:304|256:304|312:288|336:248,1,200,2|0 +336,156,2020754,2,0,B|312:116|256:100|256:100|200:116|176:156,1,200 +256,200,2021397,5,2 +356,348,2021825,1,0 +480,240,2022254,2,0,B|480:140,1,100,2|0 +408,84,2022682,1,0 +300,228,2023111,6,0,B|321:256|305:304|258:324|209:304|193:256|217:223,1,200,0|2 +256,148,2023754,1,0 +256,60,2023968,1,0 +100,84,2024397,1,2 +100,84,2024611,1,0 +100,84,2024825,1,0 +175,247,2025254,2,0,B|190:293|254:324|318:293|334:250,2,200,2|0|0 +342,361,2026539,5,2 +256,200,2026968,1,0 +256,200,2027182,1,0 +169,361,2027611,1,0 +169,361,2027825,1,2 +64,203,2028254,6,0,B|92:107|92:107|168:43,1,200,0|2 +343,42,2029111,2,0,B|420:107|420:107|448:203,1,200 +336,339,2029968,1,2 +256,312,2030182,1,0 +176,340,2030397,2,0,B|160:282|194:232|256:224|256:224|296:208|328:160|296:112|256:104|216:112|176:160|216:208|256:224|256:224|320:232|355:286|334:348,1,600,0|2 +440,192,2032111,5,0 +344,40,2032539,1,0 +256,16,2032754,1,0 +168,40,2032968,1,2 +72,192,2033397,1,0 +211,312,2033825,2,0,B|190:340|206:388|253:408|302:388|318:340|294:307,1,200,0|2 +208,156,2034682,5,0 +256,24,2034897,1,0 +304,156,2035111,1,2 +184,72,2035325,1,0 +324,76,2035539,1,0 +408,236,2035968,5,2 +256,340,2036397,1,0 +104,236,2036825,1,2 +172,68,2037254,1,0 +172,68,2037468,1,0 +340,68,2037897,1,0 +340,68,2038111,1,0 +256,200,2038539,5,2 +336,360,2038968,2,0,B|312:320|256:304|256:304|200:320|176:360,1,200,0|2 +104,196,2039825,1,0 +256,100,2040254,1,2 +408,200,2040682,1,0 +256,192,2040897,12,0,2043254 +256,24,2044325,5,2 +301,102,2044539,2,0,B|322:130|306:178|259:198|210:178|194:130|218:97,1,200 +340,232,2045397,1,2 +256,260,2045611,1,0 +172,232,2045825,1,4 +76,360,2046254,1,0 +436,360,2047111,1,2 +334,144,2047539,6,0,B|320:183|265:230|188:199|179:142|179:142,1,200,0|2 +212,52,2048182,2,0,B|224:38|241:23|296:26|305:57|305:57,1,100 +64,336,2049682,5,2 +173,204,2050111,2,0,B|187:236|247:285|320:257|341:200|341:200,1,200,0|2 +374,109,2050754,2,0,B|347:44|270:-14|156:19|137:117|137:117,1,300 +448,336,2052254,1,2 +256,192,2052682,5,0 +192,250,2052897,2,0,B|157:294|184:334|233:346|256:312|256:312|282:348|328:336|364:292|309:241,2,300,0|2|0 +56,324,2054611,1,0 +56,324,2054825,5,2 +176,96,2055254,2,0,B|200:56|256:40|256:40|312:56|336:96,1,200,0|2 +256,144,2055897,1,0 +336,188,2056111,2,0,B|312:228|256:244|256:244|200:228|176:188,1,200 +344,356,2057397,2,0,B|312:320|276:336|256:356|256:356|236:332|192:320|160:368,1,200,2|0 +256,264,2058039,1,0 +359,34,2058682,6,0,B|413:71|379:165|309:209|236:120|188:73|200:24|245:-2|264:-12|283:-2|302:16|321:73|283:120|231:211|109:185|106:73|123:44|171:20,1,600,2|2 +256,208,2060397,1,0 +212,372,2060825,1,2 +300,372,2061039,1,0 +136,168,2061682,6,0,B|163:233|240:291|354:258|373:160|373:160,1,300,0|0 +337,73,2062539,2,0,B|323:41|263:-8|190:20|169:77|169:77,1,200,2|0 +254,129,2063182,1,0 +176,352,2063825,1,2 +256,316,2064039,1,0 +336,352,2064254,1,0 +256,192,2064468,12,0,2065968 +46,270,2066397,6,0,B|106:194|106:194|46:110,1,200,2|0 +299,34,2067254,2,0,B|320:62|304:110|257:130|208:110|192:62|216:29,1,200,2|0 +454,270,2068111,2,0,B|394:194|394:194|454:110,1,200,2|0 +298,350,2068968,2,0,B|319:322|303:274|256:254|207:274|191:322|215:355,1,200,4|0 +480,60,2070254,6,0,B|480:107|412:116|391:71|391:71|372:26|320:26|301:71|301:71|284:116|230:116|211:71|211:71|194:26|140:26|123:71|123:71|99:116|33:107|33:58,2,600 +256,200,2073254,5,0 +168,360,2073682,1,0 +340,360,2074111,2,0,B|395:298|408:225|358:155|311:129|254:113|210:125|154:141|108:209|110:255|111:328|188:373,2,600,8|8|8 +472,200,2077325,6,0,B|472:100,1,100,8|8 +392,56,2077754,1,0 +336,128,2077968,2,0,B|312:168|256:184|256:184|200:168|176:128,1,200,8|0 +40,200,2078825,2,0,B|40:100,1,100,8|0 +116,52,2079254,1,4 +177,271,2079682,6,0,B|201:231|257:215|257:215|313:231|337:271,1,200 +299,355,2080325,2,0,B|283:372|256:377|256:377|227:372|213:354,1,100,0|8 +144,90,2080968,6,0,B|153:55|199:44|221:77|199:100|209:146|242:133|255:48|255:48|265:133|298:146|310:100|288:77|310:44|364:50|366:88,1,400,0|8 +340,268,2082254,1,0 +256,304,2082468,1,8 +172,268,2082682,1,0 +328,360,2083111,5,8 +256,196,2083539,1,0 +184,360,2083968,1,0 +112,194,2084397,2,0,B|172:135|127:69|127:69|216:94|257:0|257:0|292:94|382:69|382:69|339:136|399:194,2,600,8|8|8 +206,348,2087397,6,0,B|310:348,1,100,8|8 +355,271,2087825,2,0,B|154:271,1,200,8|8 +208,40,2088682,6,0,B|312:40,1,100,8|8 +357,117,2089111,2,0,B|156:117,1,200,8|4 +52,260,2089968,1,0 +212,344,2090397,2,0,B|224:358|241:373|296:370|305:339|305:339,1,100,0|2 +256,268,2090825,1,8 +460,260,2091254,1,0 +416,84,2091682,5,2 +352,148,2091897,1,0 +328,60,2092111,1,8 +160,148,2092539,1,0 +96,84,2092754,1,8 +184,60,2092968,1,0 +129,290,2093397,6,0,B|157:341|243:400|353:360|384:290|384:290,1,300,8|0 +300,228,2094254,2,0,B|288:242|271:257|216:254|207:223|207:223,1,100,2|0 +256,144,2094682,1,8 +148,44,2095111,6,0,B|72:112|72:112|56:208,1,200 +80,288,2095754,1,0 +168,324,2095968,2,0,B|192:360|232:360|256:344|256:344|276:360|320:360|344:324,1,200,8|0 +456,208,2096825,2,0,B|440:112|440:112|364:44,1,200,2|8 +256,192,2097682,1,0 +301,268,2097897,2,0,B|256:288|256:288|210:268,1,100,8|0 +48,344,2098539,5,8 +192,48,2099182,2,0,B|160:89|184:161|254:190|327:161|351:89|315:40,1,300,2|8 +464,344,2100468,1,0 +256,272,2100897,5,2 +256,360,2101111,1,8 +172,208,2101539,2,0,B|186:176|246:127|319:155|340:212|340:212,1,200,0|0 +123,97,2102397,2,0,B|158:52|257:5|353:49|389:100,1,300,8|8 +388,99,2103254,1,0 +332,296,2103682,1,8 +256,340,2103897,1,0 +180,296,2104111,1,0 +176,208,2104325,1,0 +256,160,2104539,1,0 +336,208,2104754,1,0 +256,248,2104968,5,8 +256,36,2105611,1,0 +256,248,2106039,5,2 +176,304,2106254,2,0,B|200:344|256:360|256:360|312:344|336:304,1,200,8|0 +411,139,2107111,2,0,B|370:42,1,100,2|0 +299,99,2107539,2,0,B|320:127|304:175|257:195|208:175|192:127|216:94,1,200,8|0 +139,46,2108182,2,0,B|101:139,1,100,8|0 +128,288,2108825,2,0,B|256:368|256:368|384:288,1,300,8|8 +300,232,2109682,2,0,B|256:256|256:256|212:232,1,100,8|0 +256,152,2110111,1,4 +108,52,2110539,5,2 +204,204,2110968,2,0,B|210:255|210:255|254:287|302:255|302:255|306:203,1,200,0|8 +412,60,2111825,1,2 +412,60,2112039,1,0 +440,224,2112468,1,0 +440,224,2112682,2,0,B|416:324|416:324|328:368|328:368,1,200,8|2 +184,368,2113539,2,0,B|97:324|97:324|73:224,1,200,0|8 +176,76,2114397,2,0,B|200:116|256:132|256:132|312:116|336:76,1,200,2|8 +256,32,2115039,1,0 +256,32,2115254,5,4 +432,192,2115682,2,0,B|404:171|356:187|336:234|356:283|404:299|437:275,1,200,2|0 +256,360,2116539,1,8 +80,276,2116968,2,0,B|108:297|156:281|176:234|156:185|108:169|75:193,1,200,2|0 +176,40,2117825,5,8 +336,40,2118254,1,0 +256,96,2118468,1,8 +176,40,2118682,1,0 +256,200,2119111,1,8 +208,348,2119539,5,8 +176,260,2119754,1,8 +256,200,2119968,1,8 +336,260,2120182,1,0 +304,348,2120397,1,12 +348,72,2120825,6,0,B|288:72|288:72|256:48|256:48|224:72|224:72|164:72,1,200,2|0 +160,352,2121682,6,0,B|128:338|79:278|107:205|164:184|164:184,1,200,8|2 +256,172,2122325,2,0,B|256:372,1,200,0|2 +352,352,2122968,2,0,B|384:338|433:278|405:205|348:184|348:184,1,200,8|0 +256,32,2123825,5,2 +96,152,2124254,1,8 +164,336,2124682,1,2 +348,336,2125111,1,0 +416,152,2125539,1,0 +256,192,2125647,12,0,2127682 +348,80,2127897,6,0,B|288:80|288:80|256:56|256:56|224:80|224:80|164:80,1,200,2|0 +172,288,2128754,2,0,B|186:256|246:207|319:235|340:292|340:292,1,200,0|0 +256,344,2129397,1,8 +192,152,2129825,2,0,B|156:56,1,100,8|0 +256,68,2130254,1,8 +320,152,2130468,2,0,B|356:56,1,100,0|4 +426,311,2131111,6,0,B|404:351|351:367|298:362|256:307|256:307|213:363|160:371|96:353|83:305|83:305,1,400,0|8 +256,192,2132397,5,0 +340,32,2132825,1,2 +256,64,2133039,1,0 +172,32,2133254,1,8 +256,284,2133897,1,8 +182,323,2134111,2,0,B|256:387|256:387|336:323,1,200,0|8 +320,152,2134968,2,0,B|292:208|292:208|256:188|220:208|220:208|196:152,1,200 +144,76,2135611,2,0,B|196:64|232:20|232:20|256:56|256:56|276:20|276:20|320:64|368:76,1,300 +404,252,2136682,5,0 +256,356,2137111,1,8 +108,252,2137539,1,0 +164,172,2137754,2,0,B|224:140|256:172|304:220|288:268|224:268|208:220|256:172|288:140|348:172,2,300,0|2|0 +256,28,2139468,5,0 +256,28,2139682,1,8 +396,140,2140111,1,8 +344,216,2140325,1,8 +256,240,2140539,1,0 +168,216,2140754,1,8 +116,140,2140968,1,12 +113,306,2141397,2,0,B|128:352|192:368|224:336|224:288|184:272|152:320|204:368|256:368|256:368|308:368|360:320|328:272|288:288|288:336|324:368|400:344|403:296,1,456.000004348755,0|8 +256,144,2142682,1,0 +256,56,2142897,1,0 +344,360,2143539,6,0,B|294:310|319:215|378:210|418:265|378:315|304:290|254:225|254:225|204:290|129:315|89:265|129:210|189:215|214:310|164:360,1,600,0|8 +172,68,2145254,2,0,B|186:36|246:-13|319:15|340:72|340:72,1,200,0|2 +373,163,2145897,2,0,B|346:228|269:286|155:253|136:155|136:155,2,300,0|0|2 +440,224,2147397,5,8 +213,335,2147825,2,0,B|236:352|256:360|256:360|277:351|304:331,1,100,0|2 +76,228,2148682,1,8 +256,192,2148789,12,2,2151254 +60,85,2151682,6,0,B|32:134|31:182,1,100,2|8 +120,156,2152111,2,0,B|98:269|152:358,1,200,0|8 +451,298,2152968,6,0,B|479:249|480:201,1,100,8|8 +391,227,2153397,2,0,B|413:114|359:25,1,200,8|4 +256,192,2154254,5,0 +33,334,2155111,6,0,B|33:287|101:278|122:323|122:323|141:368|193:368|212:323|212:323|229:278|283:278|302:323|302:323|319:368|373:368|390:323|390:323|414:278|480:287|480:336,1,600,8|8 +256,152,2157039,1,8 +176,108,2157254,2,0,B|192:65|256:33|320:65|336:113,2,200,8|8|8 +256,264,2158539,1,8 +80,336,2158968,6,0,B|132:368|160:336|176:320|176:320|192:336|208:352|232:344|232:344|256:368|280:344|280:344|304:352|320:336|336:320|336:320|352:336|380:368|432:336,1,400,8|0 +340,172,2160254,2,0,B|381:116|349:21|256:-18|159:21|127:116|175:181,1,400,8|0 +157,353,2161539,2,0,B|358:353,1,200,8|0 +306,276,2162182,2,0,B|202:276,1,100,8|0 +56,176,2162825,5,8 +157,31,2163254,2,0,B|358:31,1,200,0|8 +306,108,2163897,2,0,B|202:108,1,100,0|4 +256,280,2164539,1,0 +456,176,2164968,5,0 +380,228,2165182,1,0 +464,268,2165397,1,8 +300,364,2165825,2,0,B|321:336|305:288|258:268|209:288|193:336|217:369,1,200 +256,192,2166682,1,8 +56,176,2167111,1,0 +132,228,2167325,1,8 +48,264,2167539,1,0 +256,192,2167968,5,8 +300,20,2168397,2,0,B|321:48|305:96|258:116|209:96|193:48|217:15,1,200 +97,157,2169254,2,0,B|128:223|176:255|256:301|335:255|383:223|415:160,1,400,8|0 +437,320,2170539,2,0,B|368:384|256:416|139:386|72:316,1,400,8|0 +165,176,2171825,2,0,B|195:207|256:237|316:207|346:176,1,200,8|0 +352,88,2172468,2,0,B|296:0,1,100,8|0 +213,5,2172897,2,0,B|159:89,1,100,8|8 +48,232,2173539,5,8 +24,320,2173754,1,0 +104,360,2173968,1,8 +176,304,2174182,1,0 +136,224,2174397,1,4 +76,56,2174825,2,0,B|128:20|112:100|207:51|191:51|191:51|223:83|255:50|255:50|287:83|330:51|314:51|314:51|384:100|384:20|442:59,1,400,0|8 +464,232,2176111,5,8 +488,320,2176325,1,0 +408,360,2176539,1,8 +336,304,2176754,1,0 +376,224,2176968,1,8 +312,56,2177397,2,0,B|416:104|416:104,1,100 +200,56,2178039,2,0,B|96:104|96:104,1,100,0|8 +176,264,2178682,2,0,B|232:272|256:216|256:216|280:272|336:264,1,200 +344,360,2179325,1,0 +344,360,2179539,2,0,B|312:396|276:380|256:360|256:360|236:384|192:396|160:348,2,200,4|0|0 +367,36,2180825,6,0,B|398:21|475:23|512:92|491:149|491:149,1,200,8|2 +456,240,2181468,2,0,B|392:271|296:264|232:164|282:78|282:78,1,300,0|2 +256,336,2182754,1,0 +256,336,2182968,1,0 +256,152,2183397,1,8 +145,36,2183825,2,0,B|114:21|37:23|0:92|21:149|21:149,1,200,8|2 +56,240,2184468,2,0,B|120:271|216:264|280:164|230:78|230:78,1,300,0|2 +388,164,2185539,5,0 +256,360,2185968,1,8 +124,164,2186397,1,2 +180,308,2186825,1,0 +256,272,2187039,1,0 +332,308,2187254,1,8 +256,24,2187897,5,8 +256,216,2188325,1,0 +336,172,2188539,2,0,B|312:132|256:116|256:116|200:132|176:172,2,200,8|0|0 +428,337,2189825,2,0,B|397:384|334:368|272:337|319:306|319:259|303:243|256:228|209:243|194:259|194:306|241:337|178:368|116:384|85:337,1,456.000004348755,4|0 +16,176,2191111,2,0,B|59:186|103:161|113:118|113:118|114:83|115:49|81:30|46:46|28:80|44:116|78:117|113:118|113:118|157:111|184:69|177:25,1,456.000004348755,8|0 +334,24,2192397,2,0,B|327:69|354:111|398:118|398:118|433:117|467:116|483:80|465:46|430:30|396:49|397:83|398:118|398:118|408:161|452:186|496:176,1,456.000004348755,8|0 +464,254,2193468,1,0 +404,328,2193682,5,8 +256,192,2194111,1,0 +176,124,2194325,1,8 +208,36,2194539,1,8 +304,36,2194754,1,0 +336,124,2194968,1,12 +96,226,2195397,2,0,B|112:308|179:376|252:395|355:368|404:296|422:226,1,456.000004348755,0|8 +256,104,2196682,5,0 +44,48,2197111,1,0 +104,116,2197325,1,0 +176,56,2197539,2,0,B|192:13|256:-19|320:13|336:61,1,200,8|0 +336,148,2198182,2,0,B|320:191|256:223|192:191|176:143,1,200,8|0 +256,104,2198825,5,8 +164,300,2199254,1,0 +348,300,2199682,1,0 +256,192,2200111,12,8,2201397 +256,192,2201504,12,8,2202682 +256,192,2202789,12,4,2205254 +384,80,2225825,5,4 +128,80,2226468,1,2 +132,308,2227111,1,8 +384,308,2227754,1,2 +256,192,2228182,5,0 +336,148,2228397,1,8 +336,60,2228611,1,0 +256,24,2228825,1,2 +176,60,2229039,1,0 +176,148,2229254,1,0 +256,192,2229468,1,0 +320,256,2229682,2,0,B|351:297|327:368|257:398|185:368|161:297|196:248,1,300,8|2 +108,228,2230539,5,0 +72,208,2230682,1,0 +52,168,2230825,1,0 +56,128,2230968,2,0,B|64:76|112:28|176:36|212:76|212:76,1,200,8|0 +288,120,2231611,2,0,B|348:140|388:104|388:104,1,100,2|0 +468,96,2232039,1,0 +440,180,2232254,2,0,B|395:224|395:268|395:313|440:357,1,200,8|2 +256,364,2233111,2,0,B|256:156,1,200,0|8 +72,180,2233968,2,0,B|116:224|116:268|116:313|72:357,2,200,2|0|8 +48,136,2234968,1,0 +56,88,2235111,1,0 +88,60,2235254,2,0,B|112:32|148:32|172:68|172:68|196:100|236:104|260:72,1,200,2|0 +344,48,2235897,5,0 +428,80,2236111,2,0,B|496:88|508:160|492:220|440:240|372:224|372:224,1,200,4|0 +452,308,2236754,2,0,B|404:328|344:296|328:244|328:204|356:176|356:176,1,200,2|0 +336,100,2237397,2,0,B|312:60|256:44|256:44|200:60|176:100,1,200,8|0 +164,188,2238039,2,0,B|156:176|184:204|184:244|168:296|108:328|60:308,1,200,2|0 +76,220,2238682,1,8 +88,132,2238897,1,0 +172,100,2239111,5,2 +212,109,2239218,1,0 +245,142,2239325,1,0 +304,208,2239539,1,0 +388,172,2239754,1,0 +468,212,2239968,2,0,B|500:248|500:304|468:364|388:344|388:344,1,200,8|2 +368,328,2240539,1,0 +345,310,2240682,1,0 +314,311,2240825,1,0 +285,326,2240968,1,0 +252,331,2241111,1,0 +230,317,2241254,2,0,B|193:288|193:230|252:200|252:200|310:171|310:113|252:80,1,300,4|2 +176,48,2242111,6,0,B|136:92|80:76|80:76,1,100,0|0 +80,156,2242539,1,8 +168,324,2242968,5,2 +344,324,2243397,1,0 +432,156,2243825,1,4 +256,32,2244254,1,2 +176,76,2244468,2,0,B|192:119|256:151|320:119|336:71,1,200,8|0 +407,131,2245111,5,0 +388,154,2245218,1,0 +366,175,2245325,1,0 +341,192,2245432,1,0 +313,202,2245539,1,0 +283,210,2245647,1,0 +256,212,2245754,1,0 +229,210,2245861,1,0 +199,202,2245968,1,0 +171,192,2246075,1,0 +146,175,2246182,1,0 +124,154,2246289,1,0 +105,131,2246397,1,4 +52,240,2246825,5,2 +140,320,2247254,1,0 +256,348,2247682,1,8 +372,320,2248111,1,2 +460,240,2248539,1,0 +488,156,2248754,1,0 +404,172,2248968,6,0,B|320:128|320:128|304:20,1,200,8|2 +207,23,2249611,1,0 +207,23,2249825,2,0,B|192:128|192:128|108:172,1,200,0|8 +336,292,2250682,6,0,B|322:324|262:373|189:345|168:288|168:288,1,200,2|0 +135,197,2251325,2,0,B|162:132|239:74|353:107|372:205|372:205,1,300,2|0 +152,36,2252397,1,2 +360,36,2252825,1,8 +256,192,2253254,5,0 +192,250,2253468,2,0,B|157:294|184:334|233:346|256:312|256:312|282:348|328:336|364:292|309:241,2,300,2|8|0 +56,324,2255182,5,2 +56,324,2255397,1,8 +176,96,2255825,2,0,B|200:56|256:40|256:40|312:56|336:96,1,200,2|0 +256,144,2256468,1,0 +336,188,2256682,2,0,B|312:228|256:244|256:244|200:228|176:188,1,200,4|0 +456,324,2257539,1,0 +256,364,2257968,1,8 +56,324,2258397,1,2 +92,232,2258611,6,0,B|140:232|152:194|150:166|150:166|182:167|220:143|206:87,1,200,0|0 +303,101,2259254,2,0,B|298:142|329:167|361:166|361:166|359:194|371:232|420:232,1,200,2|0 +376,312,2259897,2,0,B|324:324|324:324|300:372,1,100,8|0 +208,365,2260325,2,0,B|188:324|188:324|136:312,1,100,0|8 +56,128,2260968,5,2 +256,104,2261397,1,0 +304,20,2261611,1,0 +208,20,2261825,1,8 +372,132,2262254,2,0,B|345:197|268:255|154:222|135:124|135:124,1,300,2|0 +56,188,2263111,2,0,B|76:240|144:300|220:308,1,200,8|0 +304,306,2263754,2,0,B|372:294|436:240|456:188,1,200,2|0 +456,187,2264397,1,2 +256,192,2264504,12,8,2265682 +256,192,2265789,12,10,2266968 +184,124,2267397,5,8 +256,76,2267611,1,8 +328,124,2267825,1,8 +304,212,2268039,1,0 +212,212,2268254,1,8 +256,352,2268682,5,8 +80,68,2269111,1,8 +432,64,2269539,1,12 +466,303,2269968,2,0,B|466:182|332:145|256:220|256:220|142:315|199:391|256:411|313:391|370:315|256:220|256:220|180:145|9:172|46:321|46:321,1,1000,0|8 +256,32,2272754,1,8 +176,76,2272968,2,0,B|192:119|256:151|320:119|336:71,1,200,8|8 +256,200,2273825,5,0 +168,360,2274254,1,0 +340,360,2274682,2,0,B|395:298|408:225|358:155|311:129|254:113|210:125|154:141|108:209|110:255|111:328|188:373,2,600,8|8|8 +472,200,2277897,6,0,B|472:100,1,100,8|8 +392,56,2278325,1,8 +336,128,2278539,2,0,B|312:168|256:184|256:184|200:168|176:128,1,200,4|0 +40,200,2279397,2,0,B|40:100,1,100,2|0 +116,52,2279825,1,4 +177,271,2280254,6,0,B|201:231|257:215|257:215|313:231|337:271,1,200 +299,355,2280897,2,0,B|283:372|256:377|256:377|227:372|213:354,1,100,0|8 +144,90,2281539,6,0,B|153:55|199:44|221:77|199:100|209:146|242:133|255:48|255:48|265:133|298:146|310:100|288:77|310:44|364:50|366:88,1,400,0|8 +340,268,2282825,5,0 +256,304,2283039,1,8 +172,268,2283254,1,0 +328,360,2283682,5,8 +256,196,2284111,1,0 +184,360,2284539,1,0 +256,196,2284968,5,4 +256,192,2285075,12,0,2286254 +256,192,2286361,12,0,2287539 +256,192,2287647,12,0,2290111 +192,144,2308992,6,0,B|160:96|96:80,2,100,2|0|0 +256,112,2309663,2,0,B|256:0,2,100,2|0|0 +320,144,2310335,2,0,B|352:96|416:80,2,100,2|0|0 +256,192,2311006,1,0 +176,304,2311678,2,0,B|208:352|256:368|256:368|304:352|336:304,1,200,4|4 +416,128,2312574,6,0,B|416:64|352:48,2,100,2|0|0 +256,144,2313245,2,0,B|256:32,2,100,2|0|0 +96,128,2313917,2,0,B|96:64|160:48,2,100,2|0|0 +256,144,2314589,1,0 +164,336,2315260,2,0,B|208:305|256:345|256:345|304:305|348:335|348:335,1,200,4|4 +256,256,2316156,5,0 +208,176,2316380,1,0 +112,192,2316603,1,2 +64,112,2316827,2,0,B|112:96|144:48,2,100,0|8|0 +192,112,2317499,2,0,B|256:32|384:48,1,200,2|0 +352,128,2318171,1,0 +336,208,2318394,2,0,B|336:272|400:304,1,100,2|0 +464,304,2318842,2,0,B|464:240|400:208,1,100,8|0 +352,128,2319290,5,2 +208,80,2319514,1,0 +112,192,2319738,2,0,B|64:224|80:288,1,100 +256,256,2320186,2,0,B|208:240|144:256,1,100,2|0 +112,192,2320633,1,8 +80,112,2320857,1,0 +160,80,2321081,2,0,B|256:128|352:80,1,200,2|0 +400,160,2321753,5,0 +352,240,2321977,2,0,B|351:240|307:270|259:230|259:230|211:270|167:239,1,200,2|8 +96,176,2322648,1,0 +64,256,2322872,2,0,B|64:304|80:368|176:368|208:352,1,200,2|4 +192,272,2323544,5,0 +256,208,2323768,1,2 +320,272,2323991,1,0 +311,354,2324215,2,0,B|336:368|432:368|448:304|448:256,1,200,8|0 +416,176,2324887,2,0,B|384:112|416:48,2,100,0|0|0 +320,192,2325559,1,2 +224,192,2325783,2,0,B|224:256|176:288,1,100,0|8 +160,128,2326230,2,0,B|160:64|112:32,1,100,0|2 +224,192,2326678,1,0 +160,128,2326902,1,4 +64,128,2327126,5,0 +192,48,2327350,1,2 +224,192,2327574,1,0 +304,112,2327797,2,0,B|400:48|512:80,1,200,8|2 +464,160,2328469,2,0,B|432:208|432:272,2,100,0|0|0 +464,336,2329141,1,2 +384,304,2329365,1,0 +304,256,2329589,2,0,B|256:288|208:256,1,100,8|0 +124,304,2330036,2,0,B|188:96,1,200,2|4 +156,16,2330708,6,0,B|188:128,1,100,0|2 +272,128,2331156,1,0 +352,176,2331380,2,0,B|304:288|368:384,1,200,8|0 +153,368,2332051,2,0,B|208:288|160:176,1,200 +64,176,2332723,2,0,B|96:224|96:272,1,100,2|0 +192,84,2333171,2,0,B|160:132|160:180,1,100,8|0 +256,192,2333618,1,2 +160,336,2334066,6,0,B|256:384|352:336,2,200,4|0|8 +160,256,2335186,1,2 +160,256,2335409,2,0,B|256:320|352:256,1,200,4|0 +344,168,2336081,6,0,B|360:116|332:72,1,100,0|4 +256,144,2336529,1,0 +256,144,2336641,1,0 +256,144,2336753,1,12 +192,80,2336977,1,0 +128,144,2337200,2,0,B|160:192|128:240,1,100,8|0 +240,336,2337648,6,0,B|192:240|256:144,1,200,4|2 +320,96,2338320,2,0,B|368:64|416:64,2,100,0|8|0 +380,164,2338991,1,0 +380,164,2339215,2,0,B|300:248|180:204,1,200,2|2 +284,108,2339887,1,8 +284,108,2340111,2,0,B|304:220|244:304,1,200,8|2 +160,236,2340783,1,2 +64,288,2341006,6,0,B|48:240|64:176,1,100,0|4 +48,16,2341454,2,0,B|64:64|48:128,1,100,0|2 +128,144,2341902,2,0,B|240:112,1,100,0|8 +304,128,2342350,1,0 +256,304,2342797,6,0,B|336:384|464:352,2,200,0|0|0 +381,253,2343917,2,0,B|381:189|333:157,1,100,8|0 +253,205,2344365,2,0,B|269:253|253:317,1,100,2|0 +173,253,2344812,5,4 +32,128,2345036,2,0,B|32:64|80:32,1,100,0|2 +160,80,2345484,2,0,B|144:128|160:192,1,100,0|8 +240,192,2345932,1,0 +288,112,2346156,1,2 +368,272,2346380,6,0,B|384:208|336:176,1,100,0|0 +288,256,2346827,2,0,B|272:320|320:352,1,100,0|2 +288,256,2347275,1,0 +352,176,2347499,1,8 +392,80,2347723,2,0,B|320:80|256:32|256:32|192:80|104:80,1,300,0|4 +80,160,2348618,5,0 +64,256,2348842,2,0,B|192:240,1,100,2|0 +224,320,2349290,2,0,B|96:336,1,100,8|0 +346,300,2349738,2,0,B|273:227|161:243,1,200,2|0 +176,144,2350409,1,0 +224,64,2350633,5,2 +400,48,2350857,1,0 +336,192,2351081,1,0 +256,80,2351305,5,0 +352,64,2351529,1,0 +320,160,2351753,1,0 +240,256,2351977,6,0,B|144:176|208:48,1,224.999993294478,4|2 +140,112,2352872,2,0,B|120:204|27:226,1,149.999995529652,8|0 +48,220,2353544,1,0 +88,300,2353768,1,2 +168,344,2353991,1,8 +256,364,2354215,2,0,B|336:348,1,74.9999977648259,0|0 +420,344,2354663,6,0,B|356:280|404:200,1,149.999995529652,8|2 +464,144,2355335,1,0 +384,108,2355559,2,0,B|316:68|240:120,1,150.000005722046,0|2 +260,208,2356230,1,0 +260,208,2356454,2,0,B|276:112|212:48|132:32|68:80,1,299.999991059304,10|0 +132,144,2357574,6,0,B|168:140|184:188,2,75.0000028610231,8|2|8 +140,328,2358245,2,0,B|140:232|252:200,1,149.999995529652,8|2 +216,212,2358917,1,8 +372,328,2359141,2,0,B|372:232|260:200,1,149.999995529652,4|2 +256,132,2359812,1,0 +184,80,2360036,2,0,B|256:48|256:48|328:80,2,149.999995529652,8|2|0 +108,128,2361156,1,8 +96,216,2361380,6,0,B|224:312,1,149.999995529652,2|8 +256,224,2362051,1,2 +416,216,2362275,2,0,B|288:312,2,149.999995529652,0|4|2 +420,128,2363394,1,8 +336,92,2363618,2,0,B|288:44|224:28|144:44|96:92|80:156,2,299.999991059304,8|0|8 +288,176,2365633,5,0 +160,256,2365857,1,4 +304,320,2366081,1,0 +288,176,2366305,5,6 +224,80,2366529,2,0,B|160:112|96:96,1,100,2|0 +48,48,2366977,2,2,B|16:96|48:160,1,100,2|0 +128,176,2367424,2,2,B|144:240|112:272,1,100,0|2 +160,368,2367872,2,2,B|240:288|224:176,1,200 +128,176,2368544,5,0 +227,187,2368768,2,2,B|259:139|307:123,1,100 +464,48,2369215,2,0,B|432:80|368:96,1,100,2|0 +368,192,2369663,2,2,B|480:224|480:352,1,200,6|2 +384,320,2370335,5,0 +288,336,2370559,1,2 +192,352,2370783,1,0 +96,352,2371006,2,0,B|128:304|96:256,1,100,2|0 +97,258,2371454,2,2,B|0:192|48:64,1,200 +144,80,2372126,1,0 +240,112,2372350,5,0 +336,80,2372574,1,2 +416,128,2372797,1,0 +416,32,2373021,1,2 +416,128,2373245,2,2,B|320:192|304:288,1,200,4|0 +384,320,2373917,2,0,B|288:256|160:304,1,200,2|0 +112,336,2374589,1,0 +80,256,2374812,1,0 +80,256,2375036,2,2,B|48:128|144:80,1,200,2|2 +208,144,2375708,6,2,B|256:160|320:144,1,100,0|2 +432,80,2376156,2,2,B|381:66|333:82,1,100 +240,64,2376603,1,0 +144,64,2376827,2,2,B|64:128|80:272,1,200,6|0 +32,176,2377499,1,0 +32,176,2377723,2,2,B|112:256|32:384,1,200,6|0 +120,296,2378394,2,2,B|196:196|325:267,1,200,0|4 +480,296,2379066,2,0,B|428:304|380:276,1,100 +432,96,2379514,5,0 +336,192,2379738,1,4 +472,220,2379962,1,0 +428,112,2380186,1,4 +352,184,2380409,1,0 +456,208,2380633,1,4 +256,192,2381081,6,2,B|160:112,1,100 +96,112,2381529,1,2 +96,112,2381753,1,0 +48,192,2381977,1,2 +48,192,2382200,2,2,B|204:316,1,200 +288,320,2382872,2,0,B|352:304|352:240,2,100,0|0|2 +288,320,2383544,1,0 +256,144,2383768,6,0,B|256:192|288:256,2,100,2|0|4 +192,64,2384439,2,2,B|184:121|126:149,1,100,2|2 +32,144,2384887,2,0,B|80:192|64:272,1,100,2|0 +128,320,2385335,1,2 +32,320,2385559,1,0 +128,320,2385783,6,2,B|176:224|304:256,1,200,6|0 +416,240,2386454,2,0,B|360:136|240:176,1,200,0|0 +188,92,2387126,1,4 +288,48,2387350,1,0 +368,112,2387574,1,0 +264,168,2387797,5,6 +368,112,2388021,2,2,B|432:96|480:32,2,100,0|2|2 +331,208,2388693,2,2,B|224:272|203:384,1,200,0|2 +208,358,2389365,1,0 +304,360,2389589,2,2,B|277:248|186:198,1,200,6|2 +128,128,2390260,1,0 +164,48,2390484,2,0,B|208:17|256:57|256:57|304:17|348:47|348:47,1,200,2|0 +384,128,2391156,1,2 +128,128,2391603,1,4 +256,192,2391827,12,0,2394066 +256,48,2401678,5,0 +256,48,2401790,1,0 +256,48,2401902,1,0 +256,48,2402014,1,0 +256,48,2402126,1,4 +208,112,2402350,6,0,B|256:144|304:112,1,100,0|2 +344,176,2402797,1,0 +344,176,2403021,2,0,B|312:208|256:224|192:208|152:168,1,200,8|0 +64,160,2403693,1,2 +32,240,2403917,1,0 +160,176,2404141,2,0,B|224:176|256:128,1,100,0|2 +160,96,2404589,2,0,B|128:48|160:-16,1,100,0|8 +240,32,2405036,2,0,B|309:113|453:97,1,200 +432,192,2405708,1,4 +384,272,2405932,5,0 +336,352,2406156,1,2 +256,304,2406380,2,0,B|256:192,1,100,0|8 +176,176,2406827,1,0 +176,176,2407051,2,0,B|192:48|64:32,2,200,2|0|2 +256,144,2408171,1,2 +256,144,2408394,2,0,B|272:32|400:32,1,200,8|2 +448,208,2409066,1,0 +448,208,2409290,6,0,B|432:144|448:96,1,100,4|0 +352,144,2409738,2,0,B|368:192|352:256,1,100,2|0 +272,288,2410186,2,0,B|256:224|272:176,1,100,8|0 +176,224,2410633,2,0,B|192:272|176:336,1,100,2|0 +96,320,2411081,5,0 +64,224,2411305,1,0 +80,128,2411529,2,0,B|176:64,1,100,2|0 +256,96,2411977,1,8 +353,76,2412200,2,0,B|449:12,1,100,2|0 +416,144,2412648,1,2 +416,144,2412872,6,0,B|464:240|416:352,2,200,8|0|8 +336,176,2413991,1,0 +240,176,2414215,1,2 +288,256,2414439,1,0 +240,176,2414663,1,0 +144,176,2414887,1,0 +192,256,2415111,1,10 +240,176,2415335,5,0 +240,176,2415447,1,0 +240,176,2415559,1,12 +144,48,2415783,1,0 +336,48,2416006,1,8 +240,176,2416230,1,0 +240,176,2416454,1,4 +304,240,2416678,5,0 +352,320,2416902,2,0,B|384:272|448:256,1,100,2|0 +432,176,2417350,2,0,B|320:144|320:16,1,200,8|2 +240,48,2418021,2,0,B|208:160|64:160,1,200,0|2 +48,256,2418693,1,2 +96,352,2418917,1,0 +96,352,2419141,2,0,B|144:240|256:240,2,200,8|0|4 +208,352,2420260,5,0 +304,352,2420484,1,2 +400,352,2420708,1,0 +400,352,2420932,2,0,B|352:240|240:240,1,200,8|0 +176,192,2421603,5,0 +144,112,2421827,1,2 +240,128,2422051,1,0 +240,128,2422275,2,0,B|352:128|416:16,1,200,0|8 +464,144,2422947,1,0 +416,272,2423171,1,2 +256,352,2423618,5,4 +160,336,2423842,2,0,B|112:240|176:144,1,200 +112,96,2424514,2,0,B|160:64|208:64,2,100,8|0|2 +288,80,2425186,1,0 +368,128,2425409,1,0 +352,224,2425633,1,0 +432,352,2425857,6,0,B|416:304|448:256,1,100,2|0 +256,208,2426305,2,0,B|256:320,1,100,8|0 +80,352,2426753,2,0,B|96:304|64:256,1,100,2|0 +64,160,2427200,1,4 +144,112,2427424,2,0,B|272:80,2,100,0|2|0 +192,192,2428096,2,0,B|208:320,1,100,8|0 +307,291,2428544,2,0,B|320:192,1,100,2|0 +256,96,2428991,5,0 +208,176,2429215,1,8 +304,176,2429439,1,0 +256,64,2429663,1,0 +176,176,2429887,1,4 +336,176,2430111,1,0 +388,272,2430335,1,0 +256,304,2430559,1,0 +128,272,2430783,6,0,B|128:144|48:64,1,224.999993294478,4|0 +168,88,2431678,2,0,B|252:100|312:40,1,150.000005722046,8|0 +396,40,2432350,1,8 +452,108,2432574,1,0 +416,192,2432797,1,0 +328,176,2433021,1,8 +320,88,2433245,1,0 +416,192,2433469,6,0,B|467:195|491:221,1,74.9999977648259,8|0 +420,280,2433917,2,0,B|384:364|288:344,1,150.000005722046,0|4 +324,260,2434589,1,0 +324,260,2434812,2,0,B|332:180|402:139,2,149.999995529652,0|8|0 +300,348,2435932,1,8 +220,200,2436156,1,0 +400,140,2436380,6,0,B|352:140|320:108,2,74.9999977648259,8|8|0 +348,32,2437051,2,0,B|348:120|260:144,1,150.000005722046,8|0 +260,232,2437723,1,0 +260,60,2437947,2,0,B|163:69|157:170,1,149.999995529652,4|0 +156,244,2438618,1,0 +256,336,2438842,2,0,B|352:336|360:248,2,150.000005722046,8|0|0 +256,336,2439962,1,8 +268,248,2440186,6,0,B|168:124,1,150.000005722046,0|8 +120,204,2440857,1,0 +80,124,2441081,2,0,B|168:112|196:40,2,150.000005722046,0|4|0 +120,204,2442200,1,8 +168,280,2442424,2,0,B|216:328|280:344|360:328|408:280|424:216,2,299.999991059304,8|0|0 +224,208,2444439,5,0 +352,128,2444663,1,0 +224,64,2444887,1,0 +128,80,2445111,6,2,B|80:112|96:192,1,100,6|2 +48,256,2445559,1,0 +96,336,2445783,2,0,B|160:320|224:368,1,100,0|2 +288,352,2446230,1,0 +368,320,2446454,1,2 +288,352,2446678,2,2,B|240:256|288:160,1,200 +288,64,2447350,2,0,B|176:48,1,100 +352,128,2447797,2,2,B|464:144,1,100,2|0 +400,224,2448245,5,2 +400,320,2448469,2,2,B|304:272|192:320,1,200,6|0 +128,352,2449141,2,2,B|144:288|128:240,1,100,2|0 +80,64,2449589,2,2,B|64:128|80:176,1,100,2|2 +176,192,2450036,1,0 +176,192,2450260,2,2,B|64:224|48:352,1,200 +128,256,2450932,6,0,B|240:304,1,100 +288,368,2451380,1,2 +384,320,2451603,2,0,B|475:280,1,100 +464,176,2452051,6,2,B|352:176|288:48,1,200,6|0 +302,73,2452723,1,2 +180,56,2452947,1,0 +152,180,2453171,1,2 +276,204,2453394,1,0 +152,180,2453618,1,2 +32,256,2453842,2,2,B|80:368|224:352,1,200,0|2 +256,288,2454514,1,0 +320,352,2454738,6,2,B|384:336|400:256,2,100,0|2|2 +256,288,2455409,1,0 +320,224,2455633,2,2,B|384:112|512:144,1,200,4|0 +400,128,2456305,1,0 +400,128,2456529,2,2,B|272:112|256:0,1,200,2|0 +176,32,2457200,2,2,B|192:160|64:208,1,200,0|2 +64,288,2457872,1,0 +64,288,2458096,6,0,B|128:288|176:336,1,100 +352,348,2458544,1,4 +240,352,2458768,1,0 +288,272,2458991,1,0 +304,256,2459103,1,0 +320,240,2459215,1,0 +336,224,2459327,1,0 +352,208,2459439,1,4 +256,48,2459887,6,0,B|176:128,2,100,0|2|2 +320,112,2460559,2,2,B|240:192,1,100 +384,176,2461006,2,2,B|240:320,1,200 +160,336,2461678,1,0 +80,288,2461902,1,0 +64,192,2462126,6,0,B|48:144|64:80,1,100,2|0 +128,144,2462574,2,2,B|144:192|128:256,1,100,2|0 +208,208,2463021,2,0,B|224:80|352:64,1,200,2|0 +416,96,2463693,1,0 +384,176,2463917,2,0,B|432:384,2,200,2|2|0 +304,224,2465036,1,0 +304,224,2465260,6,0,B|336:336,1,100 +192,240,2465708,2,0,B|160:128,1,100 +32,112,2466156,1,0 +144,32,2466380,1,0 +144,32,2466603,6,2,B|192:64|240:48,2,100,6|0|0 +144,128,2467275,2,2,B|224:192|208:320,1,200 +304,304,2467947,1,0 +304,304,2468171,2,2,B|289:188|369:124,1,200 +416,48,2468842,5,4 +256,32,2469066,1,0 +96,48,2469290,1,4 +192,128,2469514,1,0 +320,128,2469738,1,0 +256,240,2469962,1,0 +256,240,2470409,1,0 +256,192,2470633,12,0,2472872 +256,64,2487424,5,0 +256,64,2487648,1,0 +432,192,2488096,5,4 +368,256,2488320,2,0,B|368:368,2,100,0|0|8 +336,176,2488991,2,0,B|240:112,2,100,0|0|8 +256,224,2489663,2,0,B|160:160,2,100,0|0|8 +176,272,2490335,2,0,B|112:272|80:336,2,100,0|0|8 +336,272,2491006,2,0,B|400:272|432:336,2,100,0|0|8 +384,192,2491678,5,4 +416,112,2491902,1,0 +384,32,2492126,1,0 +256,32,2492350,5,8 +256,128,2492574,1,0 +256,224,2492797,1,0 +128,192,2493021,5,8 +96,112,2493245,1,0 +128,32,2493469,1,0 +256,32,2493693,6,0,B|256:160,3,100,8|0|0|8 +352,128,2494589,1,0 +432,176,2494812,2,0,B|384:208|400:288,1,100,8|0 +448,336,2495260,6,0,B|456:296|440:264|380:264|380:264|296:264,1,200,4|8 +124,256,2495932,2,0,B|116:216|132:184|192:184|192:184|276:184,1,200,0|8 +416,176,2496603,2,0,B|424:136|408:104|348:104|348:104|264:104,1,200,0|8 +164,104,2497275,2,0,B|100:24,2,100,0|0|8 +100,184,2497947,2,0,B|4:104,2,100,0|0|8 +256,192,2498618,1,0 +256,192,2498842,12,4,2500633 +384,48,2500857,6,0,B|368:112|384:160,1,100 +336,272,2501305,1,0 +336,272,2501529,2,0,B|272:64,1,200,4|0 +176,64,2502200,2,0,B|64:80,1,100,0|4 +64,176,2502648,6,0,B|32:304,1,100,8|0 +144,192,2503096,2,0,B|112:304,1,100,0|8 +224,208,2503544,2,0,B|192:320,1,100,0|8 +384,240,2503991,6,0,B|416:112,1,100 +304,224,2504439,2,0,B|336:112,1,100,8|0 +224,208,2504887,2,0,B|256:95,1,100,0|8 +176,48,2505335,5,0 +80,80,2505559,1,8 +48,176,2505783,1,0 +64,272,2506006,5,4 +256,352,2506454,1,0 +448,272,2506902,1,4 +352,96,2507350,1,0 +160,96,2507797,1,4 +256,272,2508245,2,0,B|292:185|228:158|260:74,2,200,0|4|0 +256,192,2509589,12,4,2513171 +336,48,2526380,5,0 +304,80,2526603,1,0 +272,112,2526827,1,0 +240,144,2527051,1,0 +208,176,2527275,1,0 +128,240,2527499,5,6 +48,304,2527723,2,2,B|144:336,1,100,2|0 +304,320,2528171,2,2,B|208:288,1,100,2|0 +304,224,2528618,1,2 +336,144,2528842,1,0 +304,224,2529066,2,2,B|496:288,1,200 +464,192,2529738,6,0,B|432:144|464:80,1,100 +256,64,2530186,2,2,B|368:80,1,100 +176,32,2530633,1,0 +176,32,2530857,2,2,B|176:160|16:192,1,200,6|0 +32,352,2531529,6,2,B|80:240,1,100,2|0 +208,304,2531977,1,2 +160,208,2532200,1,0 +71,261,2532424,1,0 +208,304,2532648,2,2,B|272:304|272:304|320:296|320:296|408:296,1,200,2|2 +448,204,2533320,6,0,B|320:204,1,100 +256,56,2533768,2,0,B|300:160,1,100,2|0 +220,216,2534215,1,0 +220,216,2534439,2,2,B|132:216|132:216|84:224|84:224|20:224,1,200,6|0 +80,308,2535111,1,2 +80,308,2535335,1,0 +80,308,2535559,2,2,B|132:276|148:216|120:164|72:152,1,200,2|0 +71,152,2536230,2,2,B|84:104|140:76|204:92|228:144,1,200,2|0 +380,136,2536902,5,0 +228,144,2537126,1,0 +308,208,2537350,1,2 +404,304,2537574,2,0,B|280:332,1,100,0|2 +116,256,2538021,2,2,B|192:232|192:232|248:232|248:232|324:204,1,200,6|0 +224,156,2538693,1,0 +224,156,2538917,2,2,B|300:132|300:132|356:132|356:132|432:104,1,200,6|0 +352,36,2539589,6,0,B|256:28|256:28|152:40,2,200 +312,164,2540708,1,0 +176,128,2540932,1,4 +56,156,2541156,5,0 +88,296,2541380,1,4 +220,204,2541603,1,0 +220,204,2541827,1,4 +420,224,2542275,5,0 +420,224,2542499,2,2,B|408:84,1,100,2|0 +328,68,2542947,1,2 +228,72,2543171,1,0 +328,68,2543394,2,2,B|344:272,1,200 +264,332,2544066,2,0,B|208:340|160:308,1,100 +72,336,2544514,6,2,B|192:316|180:184,1,200,2|0 +80,208,2545186,2,2,B|68:86|188:66,1,200,6|0 +284,48,2545857,2,0,B|384:40,2,100,0|2|0 +304,148,2546529,1,2 +208,116,2546753,1,0 +176,212,2546977,6,2,B|-8:316,1,200,2|0 +100,336,2547648,2,2,B|284:232,1,200,2|0 +376,248,2548320,2,0,B|436:248|460:200,2,100 +384,148,2548991,5,6 +364,48,2549215,1,0 +264,56,2549439,1,2 +192,124,2549663,2,2,B|144:228|208:320,1,200,0|2 +315,314,2550335,1,0 +315,314,2550559,2,2,B|376:228|328:124,1,200 +396,52,2551230,6,0,B|508:108,1,100 +328,124,2551678,2,0,B|240:80,1,100 +96,132,2552126,2,0,B|208:188,1,100 +256,292,2552574,1,4 +256,292,2552797,1,0 +256,192,2553021,12,4,2555708 +357,168,2579508,5,4 +232,96,2579732,1,2 +152,234,2579956,1,0 +280,300,2580179,1,0 +280,300,2580851,5,4 +152,234,2581075,1,2 +232,96,2581299,1,0 +357,168,2581523,1,0 +256,192,2582194,5,2 +256,192,2582418,1,0 +256,192,2582642,1,2 +208,364,2583090,6,0,B|224:378|256:394|288:378|304:362,1,100,4|0 +256,296,2583538,1,2 +200,232,2583762,2,0,B|163:179|192:112|255:92|304:104|346:153|336:200|312:232|312:232,1,300,0|4 +368,301,2584657,2,0,B|411:263|413:197,1,100,0|2 +405,123,2585105,1,0 +144,301,2585777,2,0,B|101:263|99:197,1,100,4|0 +107,123,2586224,1,4 +256,192,2586672,5,0 +256,192,2586784,1,0 +256,192,2586896,1,0 +256,192,2587120,1,0 +256,280,2587344,1,0 +451,140,2588015,6,0,B|465:124|481:92|465:60|449:44,1,100 +362,48,2588463,2,0,B|349:59|333:91|349:123|363:139,1,100 +336,328,2589359,1,0 +256,368,2589582,1,0 +176,328,2589806,1,0 +148,140,2590254,2,0,B|162:124|178:92|162:60|146:44,1,100 +59,48,2590702,2,0,B|46:59|30:91|46:123|60:139,1,100 +209,344,2591597,6,0,B|255:362|255:362|302:344,1,100 +301,243,2592045,2,0,B|254:225|254:225|207:244,1,100 +332,76,2592941,5,0 +256,20,2593165,1,0 +180,76,2593388,1,0 +212,156,2593612,1,0 +300,156,2593836,1,0 +300,156,2593948,1,0 +300,156,2594060,1,0 +376,204,2594284,5,0 +468,196,2594508,1,0 +504,276,2594732,1,0 +440,344,2594956,1,0 +360,296,2595179,1,0 +304,373,2595403,2,0,B|288:387|256:403|224:387|208:371,1,100,0|0 +152,296,2595851,1,0 +72,344,2596075,1,0 +8,276,2596299,1,0 +44,196,2596523,1,0 +136,204,2596747,1,0 +176,124,2596971,5,0 +208,92,2597082,1,0 +252,76,2597194,1,0 +296,92,2597306,1,0 +324,124,2597418,1,0 +256,184,2597642,1,0 +340,240,2597866,2,0,B|368:280|368:280|420:296|420:296,2,100 +256,284,2598538,2,0,B|256:388|256:388,2,100 +172,240,2599209,2,0,B|144:280|144:280|92:296|92:296,2,100 +256,180,2599881,1,0 +360,256,2600105,5,0 +360,256,2600217,1,0 +360,256,2600329,1,0 +360,256,2600441,1,0 +360,256,2600553,1,0 +360,256,2600665,1,0 +360,256,2600777,1,0 +360,256,2600888,1,0 +360,257,2601000,6,0,B|347:343|241:378,2,150,4|0|0 +400,240,2601784,1,0 +448,226,2601896,1,0 +277,64,2602344,1,0 +229,78,2602456,1,0 +181,92,2602568,1,0 +157,188,2602791,6,0,B|71:175|36:69,2,150 +145,237,2603575,1,0 +127,283,2603687,1,0 +284,159,2604135,1,0 +302,113,2604247,1,0 +314,65,2604359,1,0 +397,119,2604582,6,0,B|420:34|505:13,2,150 +444,136,2605366,1,0 +491,152,2605478,1,0 +346,290,2605926,1,0 +299,272,2606038,1,0 +252,252,2606150,1,0 +221,156,2606374,6,0,B|246:79|180:5,2,150 +179,163,2607157,1,0 +129,170,2607269,1,0 +17,336,2607717,1,0 +66,331,2607829,1,0 +115,323,2607941,1,0 +196,265,2608165,6,0,B|289:271|311:373,2,150 +205,215,2608948,1,0 +214,165,2609060,1,0 +401,233,2609508,1,0 +413,184,2609620,1,0 +426,135,2609732,1,0 +415,36,2609956,6,0,B|290:22|248:130,2,200 +216,8,2611299,1,0 +35,94,2611747,5,0 +58,137,2611859,1,0 +78,182,2611971,2,0,B|141:186|158:255,1,100 +99,323,2612418,1,0 +183,376,2612642,1,0 +183,376,2612866,1,0 +249,301,2613090,6,0,B|388:315,1,100 +429,251,2613538,1,0 +429,251,2613762,1,0 +375,167,2613985,1,0 +388,67,2614209,1,0 +196,65,2614433,6,0,B|171:20,7,50,0|0|0|0|0|0|0|0 +218,111,2615329,2,0,B|163:231|296:295,1,200,4|0 +347,216,2616000,1,0 +438,257,2616224,1,0 +414,354,2616448,5,0 +414,354,2616560,1,0 +414,354,2616672,2,0,B|175:368,1,200 +214,365,2617232,1,0 +214,365,2617344,1,0 +118,336,2617568,1,0 +161,246,2617791,1,0 +80,186,2618015,2,0,B|68:67|191:31,1,200 +180,34,2618575,1,0 +180,34,2618687,1,0 +230,121,2618911,5,0 +230,121,2619023,1,0 +230,121,2619135,2,0,B|363:104,1,100 +321,208,2619582,1,0 +321,208,2619694,1,0 +321,208,2619806,2,0,B|454:191,1,100 +482,274,2620254,6,0,B|281:299,1,200 +283,299,2620814,1,0 +283,299,2620926,1,0 +208,365,2621150,1,0 +122,312,2621374,1,0 +195,244,2621597,1,0 +195,244,2621709,1,0 +195,244,2621821,2,0,B|209:139,1,100 +148,63,2622269,1,0 +75,131,2622493,5,0 +75,131,2622605,1,0 +75,131,2622717,2,0,B|61:236,1,100 +87,327,2623165,1,0 +175,372,2623388,2,0,B|301:374|320:255,1,200 +409,218,2624060,1,0 +409,218,2624284,5,0 +103,218,2624732,1,0 +409,218,2625179,1,0 +103,218,2625627,1,0 +256,48,2626075,5,0 +256,48,2626187,1,0 +256,48,2626299,2,0,B|281:167,1,100 +186,191,2626747,1,0 +234,278,2626971,2,0,B|218:342|129:338,1,100 +88,268,2627418,1,0 +88,268,2627642,1,0 +43,178,2627866,5,0 +43,178,2627978,1,0 +43,178,2628090,2,0,B|66:72,1,100 +179,45,2628538,2,0,B|156:151,1,100 +240,255,2628985,2,0,B|263:149,1,100 +420,100,2629433,1,0 +420,100,2629545,1,0 +420,100,2629657,1,4 +340,310,2630105,6,0,B|316:352|256:374|204:357|173:311,1,200,0|0 +172,74,2631000,2,0,B|196:32|256:10|308:27|339:73,1,200,0|0 +339,73,2631560,1,0 +339,73,2631672,1,0 +43,206,2632120,6,0,B|66:312,1,100 +179,339,2632568,2,0,B|156:233,1,100 +240,129,2633015,2,0,B|263:235,1,100,0|4 +398,343,2633687,2,0,B|433:355|475:325|475:280|454:238|395:234|371:270,1,200 +393,60,2634582,2,0,B|357:47|315:77|315:122|336:164|395:168|419:132,1,200 +414,138,2635142,1,0 +414,138,2635254,1,0 +242,86,2635702,6,0,B|220:38|220:38|166:28|166:28,1,100 +119,101,2636150,1,0 +36,64,2636374,2,0,B|-24:160|36:252,1,200,0|4 +336,356,2637269,2,0,B|312:312|256:300|256:300|200:312|176:356,1,200 +476,251,2638165,2,0,B|536:160|476:64,1,200 +476,64,2638724,1,0 +476,64,2638836,1,0 +256,116,2639284,5,0 +328,172,2639508,1,0 +300,256,2639732,1,0 +212,256,2639956,1,0 +184,172,2640179,1,0 +108,128,2640403,6,0,B|80:64|80:64,2,50,0|0|0 +176,296,2640851,2,0,B|148:360|148:360,2,50 +256,96,2641299,2,0,B|256:48|256:48,2,50 +336,296,2641747,2,0,B|364:360|364:360,2,50 +404,128,2642194,2,0,B|432:64|432:64,2,50 +296,208,2642642,22,0,B|288:232|256:240|224:232|216:208,1,100 +256,120,2643090,1,0 +140,268,2643314,1,0 +172,296,2643426,1,0 +212,316,2643538,1,0 +256,324,2643650,1,0 +300,316,2643762,1,0 +340,296,2643874,1,0 +372,268,2643985,1,4 +152,152,2644433,6,0,B|130:104|130:104|76:94|76:94,1,100 +256,100,2644881,2,0,B|256:-8,1,100 +360,152,2645329,2,0,B|382:104|382:104|436:94|436:94,1,100 +209,344,2646224,6,0,B|255:362|255:362|302:344,1,100 +303,243,2646672,2,0,B|256:225|256:225|209:244,1,100 +40,50,2647344,22,0,B|61:104|116:123|179:104|196:45,1,200 +296,160,2648015,2,0,B|288:136|256:128|224:136|216:160,1,100 +317,50,2648463,2,0,B|333:104|396:123|451:104|472:50,1,200,0|0 +296,160,2649135,2,0,B|328:216|328:216|280:232|257:262|257:262|232:232|185:214|185:214|222:152,1,300 +304,348,2650030,6,0,B|256:376|204:348,1,100 +424,192,2650478,1,0 +257,53,2650702,1,0 +88,192,2650926,1,0 +88,192,2651038,1,0 +88,192,2651150,1,4 +297,350,2651597,6,0,B|297:302|297:302|337:262,1,100 +217,350,2652045,2,0,B|217:302|217:302|177:262,1,100 +417,115,2652717,22,0,B|367:16|260:-22|138:16|95:118,1,400,0|0 +172,238,2653836,2,0,B|198:283|257:300|314:282|339:237,1,200,0|0 +256,152,2654508,1,0 +256,192,2654732,12,0,2656299 +114,110,2656971,6,0,B|231:63,1,100 +398,274,2657418,2,0,B|281:321,1,100 +257,327,2657754,1,0 +207,329,2657866,1,0 +160,311,2657978,1,0 +136,266,2658090,1,0 +143,216,2658202,1,0 +179,181,2658314,2,0,B|280:89|156:-1,1,200,4|0 +376,255,2658985,6,0,B|367:325|432:349,1,100 +450,247,2659433,2,0,B|459:177|394:153,1,100 +312,172,2659881,2,0,B|259:272|112:233,1,200 +243,9,2660553,6,0,B|234:79|299:103,1,100 +367,44,2661000,1,0 +451,98,2661224,2,0,B|460:168|395:192,1,100 +454,275,2661672,2,0,B|225:269,1,200 +122,144,2662344,6,0,B|222:146,1,100 +220,311,2662791,2,0,B|420:317,1,200 +291,72,2663463,2,0,B|92:67,1,200 +96,233,2664135,5,0 +69,321,2664359,1,0 +155,346,2664582,1,0 +182,261,2664806,1,0 +96,234,2665030,1,0 +182,262,2665254,2,0,B|398:231,1,200 +506,369,2665926,6,0,B|497:299|449:257,1,100 +500,182,2666374,1,0 +427,113,2666597,2,0,B|436:43|492:10,1,100 +372,3,2667045,2,0,B|267:26|234:157,1,200 +385,212,2667717,6,0,B|381:273|324:303,1,100 +399,33,2668165,2,0,B|294:56|261:187,1,200 +79,197,2668836,2,0,B|184:174|217:43,1,200 +302,18,2669508,5,0 +376,85,2669732,2,0,B|427:96|465:165,2,100 +305,156,2670403,2,0,B|347:255|469:286,1,200 +231,107,2671075,6,0,B|145:108|111:163,2,100 +248,8,2671747,2,0,B|132:2|44:73,1,200 +22,95,2672306,1,0 +11,143,2672418,1,0 +35,186,2672530,1,0 +84,195,2672642,6,0,B|148:201|156:271,1,100,4|0 +252,240,2673090,1,0 +235,338,2673314,2,0,B|358:357|418:242,1,200 +175,277,2673985,6,0,B|110:267|73:328,1,100 +0,256,2674433,1,0 +82,199,2674657,2,0,B|47:88|92:-9,1,200 +216,125,2675329,6,0,B|294:191,1,100 +338,100,2675777,2,0,B|494:232,1,200 +463,325,2676448,1,0 +463,325,2676672,2,0,B|422:365|353:347,1,100 +275,25,2677568,5,0 +275,25,2677791,1,0 +275,25,2678015,2,0,B|303:70|297:135,1,100 +44,299,2678911,6,0,B|108:297|155:246,1,100 +47,322,2679359,2,0,B|111:320|158:269,1,100 +237,272,2679806,5,0 +237,272,2679918,1,0 +237,272,2680030,2,0,B|352:306,1,100 +370,207,2680478,1,0 +444,273,2680702,2,0,B|493:237|487:181,2,100 +425,371,2681374,6,0,B|214:354,1,200 +133,262,2682045,2,0,B|332:278,1,200 +358,196,2682717,2,0,B|252:187,1,100 +208,183,2683053,1,0 +158,178,2683165,1,0 +108,173,2683277,1,0 +58,166,2683388,2,0,B|20:124|41:55,1,100 +108,2,2683836,2,0,B|146:44|125:113,1,100 +222,57,2684284,6,0,B|433:40,1,200,0|0 +492,111,2684956,2,0,B|293:127,1,200 +235,209,2685627,2,0,B|341:200,1,100 +263,129,2686075,1,0 +213,134,2686187,1,0 +163,141,2686299,2,0,B|125:183|146:252,1,100 +256,30,2697717,5,0 +110,125,2697941,1,0 +133,290,2698165,1,0 +299,333,2698388,1,0 +421,211,2698612,1,0 +342,54,2698836,5,0 +169,54,2699060,1,0 +90,211,2699284,1,0 +212,333,2699508,1,0 +378,290,2699732,1,0 +401,125,2699956,1,0 +256,30,2700179,1,0 +256,192,2700403,5,0 +256,192,2700515,1,0 +256,192,2700627,1,0 +256,192,2700739,1,0 +256,192,2700851,1,0 +256,192,2700963,1,0 +256,192,2701075,1,0 +256,192,2701187,1,0 +256,192,2701299,1,4 +326,324,2701635,6,0,B|306:358|256:377|213:363|187:324,1,164.999995082617,0|0 +60,280,2702194,1,0 +76,148,2702418,2,0,B|88:92|88:92|132:52,1,109.999996721745 +209,147,2702866,2,0,B|219:123|254:115|289:122|302:146,1,109.999996721745 +256,188,2703202,1,0 +256,240,2703314,1,0 +384,56,2703538,2,0,B|424:92|424:92|436:148,1,109.999996721745 +326,311,2703985,2,0,B|306:345|256:364|213:350|187:311,2,164.999995082617 +256,192,2704881,5,0 +256,144,2704993,1,0 +256,96,2705105,1,0 +130,80,2705329,2,0,B|119:56|84:48|50:55|37:79,1,109.999996721745 +209,259,2705777,2,0,B|219:282|254:290|289:284|302:260,1,109.999996721745 +475,79,2706224,2,0,B|462:55|427:48|392:56|382:80,1,109.999996721745 +408,296,2706672,6,0,B|464:264,2,54.9999983608723 +300,336,2707120,2,0,B|286:360|256:366|256:366|225:360|212:336,1,109.999996721745 +192,228,2707568,2,0,B|211:192|257:182|257:182|303:192|322:228,2,164.999995082617 +104,296,2708463,2,0,B|48:264,2,54.9999983608723 +136,108,2708911,5,0 +256,32,2709135,1,0 +376,108,2709359,1,0 +336,260,2709582,1,0 +176,260,2709806,1,0 +256,152,2710030,1,0 +256,152,2710254,5,0 +404,348,2710702,1,0 +108,348,2711150,1,0 +175,131,2711597,6,0,B|192:71|257:48|320:72|338:134,1,219.999993443489,0|0 +256,156,2712157,2,0,B|256:232,1,54.9999983608723 +356,280,2712493,2,0,B|372:332|372:332|436:360|436:360,2,109.999996721745 +256,364,2713165,1,0 +156,280,2713388,2,0,B|140:332|140:332|76:360|76:360,2,109.999996721745 +156,280,2713948,1,0 +156,280,2714060,1,0 +209,160,2714284,2,0,B|219:136|254:128|289:135|302:159,1,109.999996721745 +95,106,2714732,5,0 +124,65,2714844,1,0 +161,33,2714956,1,0 +206,15,2715068,1,0 +256,8,2715179,1,0 +306,15,2715291,1,0 +351,33,2715403,1,0 +388,65,2715515,1,0 +417,106,2715627,1,4 +340,310,2716075,6,0,B|316:352|256:374|204:357|173:311,1,200,0|0 +340,129,2716971,2,0,B|316:87|256:65|204:82|173:128,1,200,0|0 +256,176,2717530,2,0,B|256:232|256:232,1,50 +400,336,2718090,6,0,B|440:224,1,100 +256,176,2718538,2,0,B|256:276,1,100 +112,336,2718985,2,0,B|72:224,1,100,0|4 +176,88,2719657,6,0,B|200:44|256:32|256:32|312:44|336:88,1,200 +336,296,2720553,2,0,B|312:340|256:352|256:352|200:340|176:296,1,200 +256,252,2721112,2,0,B|256:184|256:184,1,50 +160,48,2721672,5,0 +216,120,2721896,2,0,B|224:96|256:88|288:96|296:120,1,100 +352,48,2722344,1,0 +256,204,2722791,5,4 +160,356,2723239,1,0 +352,356,2723687,1,0 +340,157,2724135,2,0,B|316:115|256:93|204:110|173:156,1,200,0|0 +256,204,2724694,2,0,B|256:260|256:260,1,50 +416,92,2725254,5,0 +348,28,2725478,1,0 +256,8,2725702,1,0 +164,28,2725926,1,0 +96,92,2726150,1,0 +160,164,2726374,5,0 +144,212,2726485,1,0 +104,244,2726597,1,0 +208,316,2726821,2,0,B|190:336|190:336|180:360,2,50 +304,316,2727269,2,0,B|322:336|322:336|332:360,2,50 +408,244,2727717,1,0 +368,212,2727829,1,0 +352,164,2727941,1,0 +184,80,2728165,5,0 +80,104,2728388,1,0 +328,80,2728612,5,0 +432,104,2728836,1,0 +256,32,2729060,5,0 +256,104,2729284,1,0 +270,190,2729508,1,0 +270,190,2729620,1,0 +270,190,2729732,1,0 +270,190,2729844,1,0 +270,190,2729956,6,0,B|271:312|126:334,1,200,4|0 +344,248,2730627,2,0,B|402:270|419:337,2,100 +409,169,2731299,1,0 +310,151,2731523,2,0,B|325:32|457:27,1,200 +297,226,2732194,6,0,B|286:279|226:297,2,100 +204,186,2732866,1,0 +131,117,2733090,1,0 +208,53,2733314,2,0,B|432:48,1,200 +226,288,2733985,6,0,B|160:280|141:204,1,100 +276,358,2734433,2,0,B|393:349|414:209,1,200 +236,26,2735105,2,0,B|119:35|98:175,1,200 +166,229,2735777,5,0 +84,285,2736000,2,0,B|65:344|-6:353,2,100 +48,190,2736672,1,0 +118,118,2736896,1,0 +118,118,2737008,1,0 +118,118,2737120,2,0,B|326:103,1,200,4|0 +455,238,2737791,6,0,B|393:233|379:150,2,100 +476,139,2738463,1,0 +458,301,2738687,2,0,B|338:294|324:163,1,200 +476,139,2739359,1,0 +476,139,2739582,1,0 +416,356,2739806,6,0,B|295:340|272:206,1,200 +96,28,2740478,2,0,B|216:43|240:178,1,200 +145,200,2741150,1,0 +218,268,2741374,2,0,B|330:261,2,100 +169,355,2742045,6,0,B|389:363,1,200 +419,366,2742605,1,0 +468,367,2742717,1,0 +500,272,2742941,1,0 +448,186,2743165,1,0 +397,184,2743277,1,0 +347,181,2743388,1,0 +369,83,2743612,5,0 +318,82,2743724,1,0 +268,78,2743836,1,0 +217,77,2743948,1,0 +166,75,2744060,1,0 +116,71,2744172,1,0 +66,68,2744284,6,0,B|22:166|85:277,1,200,4|0 +174,237,2744956,1,0 +152,334,2745179,1,0 +152,334,2745403,2,0,B|259:358,1,100 +316,280,2745851,2,0,B|435:312|488:212,1,200 +194,111,2746523,5,0 +274,50,2746747,1,0 +194,111,2746971,1,0 +194,111,2747194,1,0 +261,185,2747418,1,0 +206,269,2747642,2,0,B|236:385|393:359,1,200 +438,298,2748314,6,0,B|440:198,1,100 +330,214,2748762,2,0,B|336:14,1,200 +209,285,2749433,2,0,B|214:86,1,200 +445,24,2750105,5,0 +345,30,2750329,1,0 +245,36,2750553,1,0 +145,41,2750777,1,0 +150,140,2751000,1,0 +50,153,2751224,2,0,B|21:275|129:337,1,200 +444,267,2751896,5,0 +345,254,2752120,1,0 +345,254,2752344,1,0 +444,267,2752568,1,0 +345,254,2752791,1,0 +285,335,2753015,2,0,B|161:325|165:199,1,200 +80,150,2753687,6,0,B|40:183|33:247,1,100 +139,102,2754135,2,0,B|234:49|359:83,1,200 +373,282,2754806,2,0,B|278:335|153:301,1,200 +147,211,2755478,5,0 +78,284,2755702,2,0,B|4:294|-11:364,2,100 +20,201,2756374,2,0,B|62:102|17:-2,1,200 +207,276,2757045,6,0,B|272:283|323:217,2,100 +156,362,2757717,2,0,B|249:393|381:350,1,200 +401,346,2758277,1,0 +443,319,2758388,1,0 +467,275,2758500,1,4 +480,228,2758612,5,4 +304,57,2759060,2,0,B|335:101|310:159|256:176|213:166|177:124|184:84|207:56|207:56,1,259.999995350838,0|0 +32,228,2759956,1,0 +298,356,2760403,2,0,B|312:296|312:296|256:256|256:256|199:296|199:296|215:357|215:357,1,259.999995350838 +368,112,2761299,5,0 +256,48,2761523,1,0 +144,112,2761747,1,0 +223,233,2761971,2,0,B|232:217|256:211|282:220|290:232,1,74.9999977648259 +256,304,2762194,1,0 +474,73,2762642,6,0,B|430:90|431:171|489:190|489:190|430:215|427:293|489:319,1,299.999991059304 +37,311,2763538,6,0,B|80:288|82:215|23:190|23:190|81:171|82:90|38:73,1,299.999991059304 +256,296,2764433,5,0 +256,24,2764881,1,0 +308,169,2765105,1,0 +184,88,2765329,1,0 +336,88,2765553,1,0 +336,88,2765665,1,0 +336,88,2765777,1,0 +212,168,2766000,1,0 +80,224,2766224,5,0 +144,328,2766448,1,0 +256,368,2766672,1,0 +368,328,2766896,1,0 +432,224,2767120,1,0 +298,192,2767344,2,0,B|302:215|288:248|259:253|233:252|210:230|206:209|215:190|215:190,1,149.999995529652,0|0 +192,82,2767791,2,0,B|256:42|256:42|320:82,1,149.999995529652 +397,162,2768239,6,0,B|465:191|465:191|484:274,1,149.999995529652 +440,362,2768687,1,0 +344,312,2768911,1,0 +308,348,2769023,1,0 +256,360,2769135,1,0 +204,348,2769247,1,0 +168,312,2769359,1,0 +72,364,2769582,1,0 +30,265,2769807,2,0,B|47:191|47:191|115:162,1,149.999995529652 +96,60,2770254,5,0 +196,96,2770478,2,0,B|205:120|244:118|256:89|256:89|265:118|306:118|315:97,1,149.999995529652 +420,60,2770926,1,0 +404,164,2771150,1,0 +318,240,2771374,2,0,B|299:208|254:191|215:204|191:239,1,149.999995529652,0|0 +208,340,2771821,1,0 +256,316,2771933,1,0 +304,340,2772045,1,0 +388,168,2772269,5,0 +356,128,2772381,1,0 +308,100,2772493,1,0 +256,88,2772605,1,0 +204,100,2772717,1,0 +156,128,2772829,1,0 +124,168,2772941,1,4 +256,296,2773165,5,0 +256,296,2773277,1,0 +256,296,2773388,1,0 +120,360,2773612,1,0 +28,240,2773836,1,0 +112,116,2774060,1,0 +256,152,2774284,1,0 +256,296,2774508,5,0 +256,296,2774620,1,0 +256,296,2774731,1,0 +392,360,2774955,1,0 +484,240,2775179,1,0 +400,116,2775403,1,0 +320,16,2775627,6,0,B|301:48|256:65|217:52|193:17,1,149.999995529652,0|0 +112,120,2776075,1,0 +204,240,2776299,1,0 +256,220,2776411,1,0 +304,240,2776523,1,4 +196,344,2776747,2,0,B|213:376|255:385|255:385|297:376|315:344,1,149.999995529652 +436,252,2777194,5,0 +396,108,2777418,1,0 +256,56,2777642,1,0 +116,108,2777866,1,0 +76,252,2778090,1,0 +76,252,2778202,1,0 +76,252,2778314,1,0 +208,348,2778538,5,0 +256,208,2778762,1,0 +304,348,2778985,1,0 +180,264,2779209,1,0 +332,264,2779433,1,0 +348,124,2779657,1,0 +312,80,2779769,1,0 +256,60,2779881,1,0 +200,80,2779993,1,0 +164,124,2780105,1,4 +76,240,2780329,5,0 +256,160,2780553,1,0 +436,244,2780777,1,0 +192,368,2781000,2,0,B|211:336|256:319|295:332|319:367,2,149.999995529652 +192,192,2781672,1,0 +256,192,2781784,1,0 +320,192,2781896,1,0 +320,16,2782120,6,0,B|301:48|256:65|217:52|193:17,2,149.999995529652 +424,120,2782791,1,0 +256,192,2783015,1,0 +96,120,2783239,1,0 +256,352,2783463,1,0 +256,192,2783687,6,0,B|252:203|238:234|285:241|301:236|315:230|336:212|323:182|328:171|332:161|326:145|310:125|295:132|283:107|277:112|244:105|219:108|204:131|189:147|180:169|180:169|169:197|172:220|178:254|191:280|206:310|255:317|286:330|322:338|357:307|381:282|403:250|408:216|414:197|422:176|425:150|406:108|386:57|353:37|305:22|251:26|214:22|174:41|139:77|121:113|107:146|107:146|97:176|87:233|95:284|124:325|166:371|200:383|250:410|330:406|384:383|417:348|445:311|483:242|479:162,1,1799.99994635582 +478,147,2786485,1,0 +472,126,2786597,1,0 +466,104,2786709,1,0 +457,83,2786821,1,0 +444,64,2786933,1,0 +432,44,2787045,1,0 +415,28,2787157,1,0 +397,14,2787269,1,4 +256,80,2801597,5,4 +256,192,2801709,12,0,2804284 +366,72,2804508,5,0 +422,120,2804732,1,0 +422,192,2804956,1,0 +366,239,2805179,2,0,B|253:192|145:240,1,224.999993294478,4|0 +113,306,2806075,2,0,B|258:390|408:299,1,300 +494,192,2807418,1,0 +398,79,2807866,2,0,B|258:-6|114:78,1,299.999991059304,4|4 +256,192,2808874,12,0,2811896 +64,152,2812120,5,0 +64,232,2812344,1,4 +256,192,2812456,12,0,2814135 +424,116,2814359,5,0 +426,153,2814471,1,0 +411,187,2814582,1,0 +380,208,2814694,1,0 +342,205,2814806,1,0 +309,186,2814918,1,0 +272,177,2815030,1,0 +234,178,2815142,1,0 +199,192,2815254,1,0 +177,222,2815366,1,0 +167,258,2815478,1,0 +171,293,2815590,1,0 +195,321,2815702,1,0 +227,339,2815814,1,0 +264,339,2815926,6,0,B|306:298|375:323,1,100 +441,263,2816374,1,0 +362,201,2816597,2,0,B|347:124|383:92,2,100 +272,248,2817269,1,0 +201,177,2817493,5,0 +201,177,2817605,1,0 +201,177,2817717,2,0,B|93:194,2,100 +289,129,2818388,1,0 +312,32,2818612,5,0 +410,30,2818836,1,0 +204,32,2819060,1,0 +106,30,2819284,1,0 +29,94,2819508,6,0,B|14:141|65:193,1,100 +57,184,2819844,1,0 +57,184,2819956,1,0 +52,284,2820179,5,0 +52,284,2820291,1,0 +52,284,2820403,2,0,B|170:273,1,100 +151,274,2820739,1,0 +151,274,2820851,1,0 +232,333,2821075,5,0 +232,333,2821187,1,0 +232,333,2821299,2,0,B|298:328|314:249,1,100 +306,275,2821635,1,0 +306,275,2821747,1,0 +401,305,2821971,5,0 +401,305,2822082,1,0 +401,305,2822194,2,0,B|382:81,1,200 +349,69,2822754,1,0 +303,47,2822866,1,0 +254,60,2822978,1,0 +232,105,2823090,6,0,B|234:166|174:188,1,100 +147,220,2823426,1,0 +111,255,2823538,1,0 +204,291,2823762,5,0 +239,326,2823874,1,0 +274,361,2823985,2,0,B|398:345,1,100 +421,363,2824321,1,0 +468,379,2824433,1,0 +462,279,2824657,5,0 +437,235,2824769,1,0 +392,211,2824881,2,0,B|379:150|437:120,1,100 +471,99,2825217,1,0 +480,49,2825329,1,0 +387,10,2825553,5,0 +337,16,2825665,1,0 +288,27,2825777,2,0,B|282:137|177:182,1,200 +235,263,2826448,1,0 +134,263,2826672,2,0,B|109:321|132:372,1,100,4|0 +127,360,2827008,1,0 +127,360,2827120,1,0 +225,343,2827344,5,0 +321,367,2827568,1,0 +338,268,2827791,1,0 +338,268,2827903,1,0 +338,268,2828015,2,0,B|479:251,1,100 +373,124,2828463,6,0,B|273:135,1,100 +189,80,2828911,1,0 +149,111,2829023,1,0 +139,160,2829135,1,0 +157,206,2829247,1,0 +196,236,2829359,1,0 +245,243,2829471,1,0 +290,262,2829582,1,0 +316,304,2829694,1,0 +307,353,2829806,1,0 +263,377,2829918,1,0 +213,381,2830030,1,0 +166,361,2830142,1,0 +116,366,2830254,1,4 +48,296,2830478,5,0 +17,256,2830590,1,0 +19,206,2830702,1,0 +54,168,2830814,1,0 +100,160,2830926,1,0 +145,180,2831038,1,0 +194,188,2831150,1,0 +243,181,2831262,1,0 +285,154,2831374,1,0 +302,107,2831485,1,0 +291,58,2831597,1,0 +255,22,2831709,1,0 +205,14,2831821,1,0 +160,36,2831933,1,0 +136,80,2832045,1,0 +194,188,2832269,5,0 +226,222,2832381,1,0 +232,273,2832493,1,0 +204,314,2832605,1,0 +155,328,2832717,1,0 +101,243,2832941,1,0 +53,227,2833053,1,0 +28,183,2833165,1,0 +112,132,2833388,1,0 +130,87,2833500,1,0 +176,62,2833612,1,0 +224,71,2833724,1,0 +255,111,2833836,1,0 +340,144,2834060,5,0 +390,145,2834172,1,0 +434,121,2834284,1,0 +492,202,2834508,2,0,B|456:227|438:286|453:314,1,100 +360,348,2834956,1,0 +360,348,2835068,1,0 +360,348,2835180,1,0 +296,288,2835403,2,0,B|288:312|256:320|224:312|216:288,1,100 +152,348,2835851,1,0 +152,348,2835963,1,0 +152,348,2836075,1,0 +256,208,2836299,5,0 +170,101,2836523,2,0,B|203:58|256:44|312:56|344:104,3,200,0|0|4|0 +404,192,2838090,5,0 +384,200,2838202,1,0 +368,212,2838314,1,0 +356,228,2838426,1,0 +348,248,2838538,1,0 +344,268,2838650,1,0 +348,288,2838762,1,0 +356,308,2838874,1,0 +368,324,2838985,1,0 +384,336,2839097,1,0 +404,344,2839209,1,0 +256,196,2839657,5,0 +108,192,2839881,5,0 +128,200,2839993,1,0 +144,212,2840105,1,0 +156,228,2840217,1,0 +164,248,2840329,1,0 +168,268,2840441,1,0 +164,288,2840553,1,0 +156,308,2840665,1,0 +144,324,2840776,1,0 +128,336,2840888,1,0 +108,344,2841000,1,0 +216,124,2841448,6,0,B|224:148|256:156|288:148|296:124,1,100 +296,123,2841784,1,0 +296,123,2841896,1,0 +256,36,2842120,1,0 +216,260,2842344,6,0,B|224:236|256:228|288:236|296:260,1,100 +256,348,2842791,1,0 +256,192,2842847,12,4,2843687 +256,192,2843799,12,0,2844582 +176,104,2845030,5,0 +256,48,2845254,1,0 +336,104,2845478,1,0 +308,200,2845702,1,0 +204,200,2845926,1,0 +183,297,2846150,2,0,B|198:352|258:373|316:351|333:294,1,200,0|0 +424,344,2846821,6,0,B|448:296|448:296|496:280,1,100 +424,208,2847269,1,0 +456,112,2847493,1,0 +372,48,2847717,1,0 +293,106,2847941,2,0,B|316:139|297:184|256:197|223:189|195:157|201:126|218:105|218:105,1,200,0|0 +140,48,2848612,1,0 +56,112,2848836,1,0 +88,208,2849060,1,0 +256,352,2849508,1,0 +338,300,2849732,2,0,B|310:254|257:240|202:251|172:305,1,200 +120,216,2850403,5,0 +208,168,2850627,1,0 +256,156,2850739,1,0 +304,168,2850851,1,0 +392,216,2851075,1,0 +396,116,2851299,1,0 +304,56,2851523,1,0 +256,44,2851635,1,0 +208,56,2851747,1,4 +116,116,2851971,1,0 +120,216,2852194,5,0 +208,268,2852418,2,0,B|184:276|176:308|184:340|208:348,1,100 +303,348,2852866,2,0,B|328:340|336:308|328:276|304:268,1,100 +392,216,2853314,6,0,B|336:188|332:132|332:132|384:121|408:60,1,200 +308,32,2853985,1,0 +204,32,2854209,1,0 +111,75,2854433,2,0,B|134:120|180:132|180:132|176:188|120:216,1,200 +216,280,2855105,2,0,B|227:258|255:252|255:252|283:258|295:280,1,100 +256,192,2855385,12,0,2856224 +256,192,2856280,12,0,2857120 +333,71,2857568,6,0,B|328:134|394:164,1,100 +179,313,2858015,2,0,B|184:250|118:220,1,100 +96,197,2858351,1,0 +74,151,2858463,1,0 +87,102,2858575,1,0 +129,75,2858687,1,0 +178,79,2858799,1,0 +218,108,2858911,2,0,B|298:184|412:151,1,200,4|0 +163,154,2859582,6,0,B|192:206|164:266,2,100 +93,81,2860254,1,0 +23,153,2860478,2,0,B|-22:249|34:367,1,200 +308,324,2861150,6,0,B|210:318,2,100 +353,234,2861821,2,0,B|362:164|297:140,1,100 +247,222,2862269,2,0,B|41:209,1,200 +126,25,2862941,6,0,B|102:71|96:129,1,100 +278,101,2863388,2,0,B|293:199|248:304,1,200 +428,259,2864060,2,0,B|404:145|420:45,1,200 +243,29,2864732,6,0,B|369:47,2,100 +143,15,2865403,1,0 +107,50,2865515,1,0 +105,100,2865627,1,0 +138,137,2865739,1,0 +184,155,2865851,1,0 +216,193,2865963,1,0 +227,241,2866075,2,0,B|261:337|415:331,1,200,4|0 +359,235,2866747,2,0,B|395:120,1,100 +474,190,2867194,2,0,B|510:75,1,100 +269,128,2867642,2,0,B|202:341,1,200 +460,196,2868314,6,0,B|496:81,1,100 +255,134,2868762,2,0,B|188:347,1,200 +195,324,2869433,1,0 +256,192,2869545,12,0,2873239 +256,96,2873463,5,0 +256,96,2873575,1,0 +256,96,2873687,1,0 +256,96,2873911,1,0 +256,96,2874135,1,0 +256,288,2874359,5,0 +256,288,2874471,1,0 +256,288,2874582,1,0 +256,288,2874806,1,0 +256,288,2875030,1,0 +352,192,2875254,5,0 +352,192,2875366,1,0 +352,192,2875478,1,0 +352,192,2875702,1,0 +352,192,2875926,1,0 +160,192,2876150,5,0 +160,192,2876262,1,0 +160,192,2876374,1,0 +160,192,2876597,1,0 +160,192,2876821,1,0 +296,56,2877045,5,0 +304,56,2877157,1,0 +312,56,2877269,1,0 +216,56,2877493,1,0 +200,56,2877717,1,0 +216,328,2877941,5,0 +208,328,2878053,1,0 +200,328,2878165,1,0 +296,328,2878389,1,0 +312,328,2878613,1,0 +256,192,2878724,12,0,2880403 +392,128,2880627,5,0 +392,128,2880739,1,0 +392,128,2880851,1,0 +392,248,2881075,1,0 +392,128,2881299,1,0 +120,256,2881523,5,0 +120,256,2881635,1,0 +120,256,2881747,1,0 +120,136,2881971,1,0 +120,256,2882194,1,0 +320,328,2882418,5,0 +320,328,2882530,1,0 +320,328,2882642,1,0 +200,328,2882866,1,0 +320,328,2883090,1,0 +192,56,2883314,5,0 +192,56,2883426,1,0 +192,56,2883538,1,0 +312,56,2883762,1,0 +192,56,2883985,1,0 +256,192,2884209,5,0 +256,192,2884321,1,0 +256,192,2884433,1,0 +256,192,2884657,1,0 +256,192,2884881,1,0 +256,192,2885105,5,0 +256,192,2885217,1,0 +256,192,2885329,1,0 +256,192,2885553,1,0 +256,192,2885777,1,0 +64,344,2886224,5,0 +96,344,2886336,1,0 +128,344,2886448,1,0 +160,344,2886560,1,0 +192,344,2886672,1,0 +224,344,2886784,1,0 +256,344,2886896,1,0 +288,344,2887008,1,0 +320,344,2887120,1,0 +352,344,2887232,1,0 +384,344,2887344,1,0 +416,344,2887456,1,0 +448,344,2887568,1,0 +256,192,2887679,12,0,2889359 +176,192,2901769,6,0,B|196:288|272:340|364:360,1,240.000005722046 +332,84,2903251,1,0 +428,136,2903621,1,2 +336,192,2903991,1,0 +428,252,2904362,1,2 +336,192,2904732,6,0,B|316:288|240:340|148:360,1,240.000005722046 +180,84,2906214,1,0 +84,136,2906584,1,2 +176,192,2906954,1,0 +84,252,2907325,1,2 +176,192,2907695,6,0,B|196:96|272:44|364:24,1,240.000005722046 +332,300,2909176,1,0 +428,248,2909547,1,2 +336,192,2909917,1,0 +428,132,2910288,1,2 +336,192,2910658,6,0,B|316:96|240:44|148:24,1,240.000005722046 +180,324,2912139,1,0 +332,324,2912510,1,2 +176,192,2912880,1,0 +204,236,2913065,1,0 +256,248,2913251,1,2 +308,236,2913436,1,0 +336,192,2913621,5,0 +76,324,2914362,1,0 +236,96,2915102,1,0 +340,128,2915473,2,0,B|308:164|304:200|352:248,1,120.000002861023,2|0 +240,276,2916214,1,2 +176,192,2916584,5,0 +436,324,2917325,1,0 +276,96,2918065,1,0 +172,128,2918436,2,0,B|204:164|208:200|160:248,1,120.000002861023,2|0 +272,276,2919176,1,2 +336,192,2919547,5,0 +76,60,2920288,1,0 +236,288,2921028,1,0 +340,256,2921399,2,0,B|308:220|304:184|352:136,1,120.000002861023,2|0 +240,108,2922139,1,2 +176,192,2922510,5,0 +436,60,2923251,1,0 +316,312,2923991,1,0 +228,296,2924362,2,0,B|228:280|228:280|228:208|280:208|280:120|280:120|280:104,1,200 +196,88,2925473,1,0 +174,95,2940288,6,0,B|194:52|255:27|316:48|338:97,2,200,2|8|2 +256,144,2942139,1,0 +208,224,2942510,1,8 +304,224,2942880,1,0 +347,302,2943251,2,0,B|308:333|270:317|255:302|255:302|240:317|199:333|164:302,1,200,2|8 +88,155,2944732,5,2 +68,67,2945102,1,0 +149,28,2945473,1,8 +210,93,2945843,1,0 +181,184,2946214,2,0,B|191:220|255:244|255:244|319:220|333:183,1,200,2|8 +424,229,2947695,5,2 +444,317,2948065,1,0 +363,356,2948436,1,8 +302,291,2948806,1,0 +331,200,2949176,2,0,B|321:164|257:140|257:140|194:160|181:202,1,200,2|8 +352,88,2950658,1,2 +256,48,2951028,1,0 +152,88,2951399,1,8 +44,56,2951769,21,8 +44,56,2951954,1,0 +44,56,2952139,1,4 +160,348,2952880,1,8 +36,172,2953436,1,0 +36,172,2953621,1,0 +192,140,2953991,1,0 +320,244,2954362,1,8 +476,212,2954732,1,0 +476,212,2954917,2,0,B|424:8|112:76|168:296,1,500,0|8 +320,244,2956214,1,0 +476,212,2956584,5,0 +320,244,2956954,1,0 +192,140,2957325,1,8 +36,172,2957695,1,0 +36,172,2957880,2,0,B|88:376|400:308|344:88,1,500,0|8 +192,140,2959176,1,0 +112,276,2959547,5,0 +256,344,2959917,1,0 +400,276,2960288,1,8 +340,136,2960658,2,0,B|364:66|291:34|256:69|256:69|221:34|148:66|172:136,2,299.999991059304 +460,270,2962510,1,0 +421,325,2962695,1,0 +360,300,2962880,1,0 +256,256,2963251,1,8 +152,300,2963621,1,0 +91,325,2963806,1,0 +52,270,2963991,5,0 +352,56,2964732,1,8 +116,92,2965288,1,0 +116,92,2965473,1,0 +176,240,2965843,1,0 +336,240,2966214,1,8 +396,92,2966584,1,0 +396,92,2966769,2,0,B|492:128|532:196|532:304|448:392|348:384|260:320,1,500,0|8 +396,92,2968065,5,0 +396,92,2968251,1,0 +396,92,2968436,1,0 +336,240,2968806,1,0 +176,240,2969176,1,8 +116,92,2969547,1,0 +116,92,2969732,2,0,B|20:128|-20:196|-20:304|64:392|164:384|252:320,1,500,0|8 +256,36,2971399,5,0 +176,172,2971769,1,0 +336,172,2972139,1,8 +432,300,2972510,2,0,B|356:399|257:327|257:327|158:399|83:300,1,400 +256,236,2973621,1,8 +432,172,2973991,2,0,B|356:73|257:144|257:144|158:73|83:172,1,400 +256,236,2975102,1,8 +256,60,2975473,1,8 +256,60,2975658,1,0 +256,60,2975843,5,4 +378,372,2976584,2,0,B|348:306|260:264|172:297|136:371,1,300,8|0 +156,204,2977325,2,0,B|372:204,1,200,8|8 +296,32,2978065,2,0,B|314:70|296:101|268:115|240:115|212:101|194:70|212:32,1,200,8|0 +126,127,2978621,2,0,B|174:192|256:213|337:192|385:127,1,300 +432,304,2979547,5,8 +256,352,2979917,1,0 +80,304,2980288,1,8 +181,159,2980658,2,0,B|191:195|255:219|255:219|319:195|333:158,1,200,0|8 +127,79,2981399,2,0,B|143:14|207:-1|272:14|304:46|288:95|256:111|223:95|207:46|239:14|304:-1|368:14|384:79,1,400 +480,224,2982510,5,8 +360,322,2982880,2,0,B|325:339|290:339|256:322|221:304|204:252|221:201|256:183|290:201|308:252|290:304|256:322|221:339|187:339|152:322,1,400 +32,224,2983991,1,8 +173,146,2984362,2,0,B|181:115|213:90|254:84|254:84|281:74|303:41|281:9|257:3|229:9|201:41|227:74|254:84|254:84|297:90|324:111|338:152,1,400 +448,288,2985473,1,8 +256,368,2985843,5,8 +184,312,2986028,1,8 +208,224,2986214,1,0 +304,224,2986399,1,8 +328,312,2986584,1,8 +334,99,2986954,2,0,B|317:52|255:28|199:50|176:101,1,200,4|0 +256,136,2987510,1,0 +256,136,2987695,5,4 +256,352,2988436,1,8 +412,108,2988991,1,0 +412,194,2989176,2,0,B|362:199|313:154|308:94|344:51,1,200,8|0 +167,51,2989917,2,0,B|203:94|198:154|149:199|100:194,1,200,8|0 +100,108,2990473,1,0 +256,204,2990843,1,0 +330,254,2991028,2,0,B|320:290|256:314|256:314|192:290|178:253,1,200,0|8 +364,344,2991769,5,0 +420,140,2992139,1,0 +256,48,2992510,1,0 +92,140,2992880,1,8 +148,344,2993251,1,0 +256,48,2993991,5,0 +432,336,2994732,1,0 +80,332,2995473,1,0 +256,304,2995843,1,8 +172,152,2996214,2,0,B|136:76|172:14|227:-12|283:-12|338:14|374:76|338:152,1,400 +472,276,2997325,1,8 +311,381,2997695,2,0,B|311:325|255:307|255:307|200:288|200:233,1,200,0|8 +256,168,2998251,1,8 +311,232,2998436,2,0,B|311:288|256:307|256:307|201:325|201:381,1,200,8|8 +39,276,2999176,1,8 +39,276,2999362,1,8 +39,276,2999547,1,4 +256,192,2999639,12,8,3001769 +256,192,3002510,5,4 +468,56,3008436,5,4 +352,348,3009176,1,8 +476,172,3009732,1,0 +476,172,3009917,1,0 +320,140,3010288,1,0 +192,244,3010658,1,8 +36,212,3011028,1,0 +36,212,3011214,2,0,B|88:8|400:76|344:296,1,500,0|8 +36,212,3012880,5,0 +192,244,3013251,1,0 +320,140,3013621,1,8 +476,172,3013991,1,0 +476,172,3014176,2,0,B|424:376|112:308|168:88,1,500,0|8 +320,140,3015473,1,0 +400,276,3015843,5,0 +256,344,3016214,1,0 +112,276,3016584,1,8 +172,136,3016954,2,0,B|148:66|221:34|256:69|256:69|291:34|364:66|340:136,2,299.999991059304 +256,272,3018806,1,0 +412,300,3019176,1,0 +256,272,3019547,1,8 +100,300,3019917,1,0 +100,300,3020102,1,0 +100,300,3020288,5,0 +376,99,3021028,2,0,B|349:30|255:-8|170:25|135:103,1,300,8|0 +176,180,3021769,2,0,B|193:227|255:251|311:229|334:178,1,200,0|0 +488,264,3022510,1,8 +336,348,3022880,1,0 +256,372,3023065,1,0 +176,348,3023251,1,0 +256,52,3023991,5,8 +24,264,3024547,1,0 +24,264,3024732,1,0 +120,112,3025102,1,0 +256,228,3025473,1,8 +392,112,3025843,1,0 +336,180,3026028,2,0,B|308:136|239:99|166:123|80:208|151:317|208:352|279:356|344:292|344:245,1,500,0|8 +448,352,3027325,5,0 +255,229,3027695,1,0 +64,352,3028065,1,0 +32,128,3028436,5,8 +173,13,3028806,2,0,B|137:89|173:151|228:177|284:177|339:151|375:89|339:13,1,400 +480,128,3029917,1,8 +352,288,3030288,5,0 +160,288,3030658,1,0 +336,184,3031028,1,8 +256,216,3031214,1,0 +176,184,3031399,1,8 +304,96,3031769,21,8 +208,96,3031954,1,0 +256,32,3032139,1,4 +256,32,3032880,37,8 +48,280,3033436,1,0 +48,280,3033621,1,0 +192,212,3033991,1,0 +328,292,3034362,1,8 +464,216,3034732,1,0 +464,216,3034917,2,0,B|397:316|291:313|235:285|185:249|132:157|191:49,1,500,0|8 +320,48,3036214,1,0 +256,196,3036584,5,0 +320,336,3036954,1,0 +416,208,3037325,1,8 +256,195,3037695,2,0,B|122:154|122:154|189:218|155:337|25:311,2,400 +256,196,3039917,1,0 +256,36,3040288,1,8 +256,195,3040658,2,0,B|389:154|389:154|322:218|356:337|486:311,1,400 +476,152,3041769,1,8 +352,52,3042139,5,0 +316,108,3042325,1,0 +256,136,3042510,1,0 +196,108,3042695,1,8 +160,52,3042880,1,0 +256,232,3043251,1,8 +256,40,3043621,1,0 +256,40,3043806,1,0 +256,40,3043991,5,4 +256,40,3044732,1,8 +464,280,3045288,1,0 +464,280,3045473,1,0 +320,212,3045843,1,0 +184,292,3046214,1,8 +48,216,3046584,1,0 +48,216,3046769,2,0,B|114:316|220:313|276:285|326:249|379:157|320:49,1,500,0|8 +192,48,3048065,1,0 +256,196,3048436,5,0 +192,336,3048806,1,0 +96,208,3049176,1,8 +256,196,3049547,2,0,B|389:236|389:236|322:173|356:54|486:80,2,400 +256,196,3051769,1,0 +256,355,3052139,1,8 +256,196,3052510,2,0,B|122:236|122:236|189:173|155:54|25:80,1,400 +36,239,3053621,1,8 +160,339,3053991,5,0 +196,283,3054176,1,0 +256,255,3054362,1,0 +316,283,3054547,1,8 +352,339,3054732,1,0 +256,159,3055102,1,8 +256,351,3055473,1,0 +256,351,3055658,1,0 +256,351,3055843,5,4 +256,36,3056584,1,8 +256,260,3057139,1,0 +256,260,3057325,2,0,B|256:112,1,132.00000125885 +312,96,3057880,1,0 +316,160,3058065,1,0 +256,188,3058251,1,0 +196,160,3058436,1,0 +200,96,3058621,1,0 +256,64,3058806,5,4 +332,348,3059547,2,0,B|289:366|256:333|256:308|256:308|256:333|222:366|181:348,1,200,8|0 +80,192,3060288,1,8 +256,88,3060658,1,0 +432,192,3061028,1,8 +340,39,3061399,2,0,B|376:115|340:177|285:203|229:203|174:177|138:115|174:39,2,400 +432,192,3063251,5,8 +256,296,3063621,1,0 +80,192,3063991,1,8 +172,345,3064362,2,0,B|136:269|172:207|227:181|283:181|338:207|374:269|338:345,2,400 +356,48,3066584,6,0,B|156:48,1,200,0|8 +52,196,3067325,1,0 +174,338,3067695,2,0,B|321:183|321:183|256:126|256:126|190:183|190:183|337:338,1,600,8|0 +464,192,3069176,1,8 +464,192,3069362,1,8 +464,192,3069547,1,0 +341,61,3069917,6,0,B|309:102|257:126|200:102|170:59,1,200,8|0 +19,154,3070658,2,0,B|49:231|123:301|196:315|255:330|314:315|392:300|461:231|492:152,1,600,4|0 +480,336,3072139,5,8 +384,80,3072510,1,0 +256,288,3072880,1,8 +128,80,3073251,1,0 +32,336,3073621,1,8 +97,274,3073806,1,0 +171,219,3073991,2,0,B|202:175|257:161|311:175|342:219,1,200,0|8 +344,39,3074732,6,0,B|311:82|258:96|203:82|171:39,1,200,0|8 +160,224,3075473,1,0 +352,224,3075843,1,8 +256,352,3076214,1,0 +256,352,3076954,5,0 +256,192,3077325,1,8 +120,76,3077695,2,0,B|147:143|226:120|256:102|256:37|256:37|256:102|292:120|368:144|400:65,1,400 +376,248,3078806,5,8 +256,344,3079176,1,0 +256,140,3079547,1,0 +136,248,3079917,1,0 +256,44,3080288,1,8 +376,248,3080658,1,0 +340,172,3080843,1,8 +256,140,3081028,1,8 +172,172,3081214,1,8 +136,248,3081399,1,8 +256,344,3081769,21,8 +488,104,3082510,2,0,B|500:97|521:64|516:9|478:-2|456:-23|369:-26|316:12|357:88|357:122|390:190|423:190|491:190|495:255|495:288|495:288|496:323|465:380|423:389|358:386|328:339|323:322|323:289|325:257|345:218|345:218|56:190|256:-177|457:190|157:221|157:221|189:250|198:289|190:322|190:338|156:389|90:389|51:373|21:337|19:289|19:289|20:240|33:208|90:190|123:190|156:122|156:88|169:17|140:-9|52:-29|18:-4|-9:55|4:88|27:110,1,2200,4|0 +72,192,3103251,5,0 +168,332,3103621,1,0 +344,332,3103991,1,0 +440,192,3104362,1,0 +256,148,3104732,1,0 +256,148,3105102,1,0 +168,296,3105473,5,0 +200,348,3105658,1,0 +256,364,3105843,1,0 +312,348,3106028,1,0 +344,296,3106214,2,0,B|272:208|348:88|472:128,1,264.0000025177 +500,268,3107510,1,0 +500,268,3107695,1,0 +400,236,3108065,1,0 +300,204,3108436,1,0 +300,100,3108806,1,0 +168,88,3109176,6,0,B|240:176|164:296|40:256,1,264.0000025177 +12,116,3110473,1,0 +12,116,3110658,1,0 +112,148,3111028,1,0 +212,180,3111399,1,0 +212,284,3111769,1,0 +344,288,3112139,6,0,B|410:277|421:196|403:192|403:192|421:189|410:108|344:97,2,264.0000025177 +256,192,3113991,1,0 +168,96,3114362,2,0,B|101:106|90:187|108:191|108:191|90:194|101:275|168:286,1,264.0000025177 +344,284,3115473,1,0 +256,192,3115843,1,0 +168,100,3116214,1,0 +196,44,3116399,1,0 +256,20,3116584,1,0 +316,44,3116769,1,0 +344,100,3116954,1,0 +256,192,3117325,1,0 +168,300,3117695,1,0 +168,300,3117880,1,0 +168,300,3118065,6,0,B|208:344|312:364|448:344|444:164|432:108|372:56|288:-28|144:4|64:152|140:248,2,800,4|8|8 +256,192,3121121,12,8,3122510 +256,192,3122602,12,8,3123991 +256,192,3124084,12,8,3126214 +108,240,3126584,5,0 +168,72,3126954,1,0 +348,72,3127325,1,0 +404,240,3127695,1,8 +256,360,3128065,1,8 +192,312,3128251,1,8 +212,232,3128436,1,8 +300,232,3128621,1,0 +320,312,3128806,1,8 +344,56,3129176,6,0,B|340:104|340:104|288:136,1,100,8|0 +216,131,3129547,2,0,B|171:103|171:103|167:55,1,100,8|0 +256,44,3129917,5,4 +256,44,3130658,1,8 +464,280,3131214,1,0 +464,280,3131399,1,0 +320,212,3131769,1,0 +184,292,3132139,1,8 +48,216,3132510,1,0 +48,216,3132695,2,0,B|115:316|221:313|277:285|327:249|380:157|321:49,1,500,0|8 +192,48,3133991,1,0 +256,196,3134362,5,0 +192,336,3134732,1,0 +96,208,3135102,1,8 +256,195,3135473,2,0,B|390:154|390:154|323:218|357:337|487:311,2,400 +256,196,3137695,5,0 +256,36,3138065,1,8 +256,195,3138436,2,0,B|123:154|123:154|190:218|156:337|26:311,1,400 +36,152,3139547,1,8 +160,52,3139917,1,0 +196,108,3140102,1,0 +256,136,3140288,1,0 +316,108,3140473,1,8 +352,52,3140658,1,0 +256,232,3141028,5,8 +256,40,3141399,1,0 +256,40,3141584,1,0 +256,40,3141769,1,4 +378,372,3142510,6,0,B|348:306|260:264|172:297|136:371,1,300,8|0 +156,204,3143251,2,0,B|372:204,1,200,8|8 +296,32,3143991,2,0,B|314:70|296:101|268:115|240:115|212:101|194:70|212:32,1,200,8|0 +126,127,3144547,2,0,B|174:192|256:213|337:192|385:127,1,300 +428,304,3145473,5,8 +256,364,3145843,1,0 +84,304,3146214,1,0 +332,212,3146584,6,0,B|322:176|258:152|258:152|192:172|180:213,1,200,0|8 +104,72,3147325,2,0,B|189:109|256:42|256:-7|256:-7|256:42|322:109|406:72,1,400 +480,224,3148436,1,8 +360,322,3148806,2,0,B|325:339|290:339|256:322|221:304|204:252|221:201|256:183|290:201|308:252|290:304|256:322|221:339|187:339|152:322,1,400 +32,224,3149917,5,8 +173,146,3150288,2,0,B|181:115|213:90|254:84|254:84|281:74|303:41|281:9|257:3|229:9|201:41|227:74|254:84|254:84|297:90|324:111|338:152,1,400 +492,232,3151399,1,8 +352,344,3151769,2,0,B|312:312|312:312|304:264,1,100,8|0 +392,256,3152139,2,0,B|384:208|384:208|344:176,1,100,8|0 +328,88,3152510,1,8 +256,144,3152695,1,0 +184,88,3152880,1,8 +168,176,3153065,2,0,B|128:208|128:208|120:256,1,100,0|8 +208,264,3153436,2,0,B|200:312|200:312|160:344,1,100,0|4 +160,56,3154362,5,8 +396,92,3154917,1,0 +396,92,3155102,1,0 +336,240,3155473,1,0 +176,240,3155843,1,8 +116,91,3156214,2,0,B|51:116|28:160|20:208|72:284|148:287|204:212,1,300 +176,240,3156954,1,0 +288,116,3157325,1,8 +116,92,3157695,5,0 +116,92,3157880,1,0 +116,92,3158065,1,0 +176,240,3158436,1,0 +336,240,3158806,1,8 +396,91,3159176,2,0,B|460:116|484:160|492:208|440:284|363:287|308:212,1,300 +336,240,3159917,2,0,B|372:288|288:332|256:256|256:256|224:332|140:288|176:240,1,300 +175,240,3160658,1,0 +256,80,3161028,5,0 +388,320,3161399,1,0 +124,320,3161769,1,8 +96,104,3162139,2,0,B|132:10|259:-40|374:4|421:109,1,400 +256,192,3163251,1,8 +96,280,3163621,2,0,B|132:373|259:424|374:379|421:274,1,400 +366,112,3164732,6,0,B|320:92|320:92|300:48,1,100,8|0 +212,46,3165102,2,0,B|192:92|192:92|146:112,1,100,8|0 +207,184,3165473,2,0,B|146:207|146:207|67:176|67:176|99:348|99:348|177:317|177:317|224:348|224:348|256:333|256:333|287:348|287:348|334:317|334:317|412:348|412:348|444:176|444:176|365:207|365:207|303:184,1,1000,4|0 +256,24,3167695,5,8 +396,91,3168065,2,0,B|461:116|484:160|492:208|440:284|364:287|308:212,1,300 +336,240,3168806,1,0 +224,116,3169176,1,8 +396,92,3169547,5,0 +396,92,3169732,1,0 +396,92,3169917,1,0 +336,240,3170288,1,0 +176,240,3170658,1,8 +116,91,3171028,2,0,B|52:116|28:160|20:208|72:284|149:287|204:212,1,300 +176,240,3171769,2,0,B|140:288|224:332|256:256|256:256|288:332|372:288|336:240,1,300 +337,240,3172510,1,0 +256,80,3172880,5,0 +124,320,3173251,1,0 +388,320,3173621,1,8 +416,104,3173991,2,0,B|380:10|253:-40|138:4|91:109,1,400 +256,192,3175102,1,8 +104,304,3175473,2,0,B|189:267|256:334|256:383|256:383|256:334|322:267|406:304,1,400,8|0 +386,195,3176460,5,0 +309,126,3176583,2,0,B|341:62,2,66.6666666666667,8|0|8 +203,126,3176955,2,0,B|171:62,2,66.6666666666667,8|0|8 +126,195,3177325,1,4 diff --git a/osu.Game.Tests/osu.Game.Tests.csproj b/osu.Game.Tests/osu.Game.Tests.csproj index 60ce67c7f6..3a15b5e6b1 100644 --- a/osu.Game.Tests/osu.Game.Tests.csproj +++ b/osu.Game.Tests/osu.Game.Tests.csproj @@ -30,6 +30,9 @@ false + + $(SolutionDir)\packages\DeepEqual.1.6.0.0\lib\net40\DeepEqual.dll + $(SolutionDir)\packages\NUnit.3.8.1\lib\net45\nunit.framework.dll True @@ -147,6 +150,7 @@ + \ No newline at end of file diff --git a/osu.Game.Tests/packages.config b/osu.Game.Tests/packages.config index ecc44f0c70..e09f2a07ba 100644 --- a/osu.Game.Tests/packages.config +++ b/osu.Game.Tests/packages.config @@ -4,6 +4,7 @@ Copyright (c) 2007-2017 ppy Pty Ltd . Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE --> + From 851c20aff0be3c55fc84c47d8b137de3cbc59222 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 7 Dec 2017 11:17:32 +0900 Subject: [PATCH 021/122] Add a few comments --- osu.Game/Audio/SampleInfo.cs | 4 ++++ osu.Game/IO/Serialization/IJsonSerializable.cs | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/osu.Game/Audio/SampleInfo.cs b/osu.Game/Audio/SampleInfo.cs index f8b5bf33d9..3c3a64dbb2 100644 --- a/osu.Game/Audio/SampleInfo.cs +++ b/osu.Game/Audio/SampleInfo.cs @@ -15,6 +15,10 @@ namespace osu.Game.Audio public const string HIT_NORMAL = @"hitnormal"; public const string HIT_CLAP = @"hitclap"; + /// + /// The that is used for and + /// if the values have not already been provided by the hitobject. + /// [JsonIgnore] public SoundControlPoint ControlPoint; diff --git a/osu.Game/IO/Serialization/IJsonSerializable.cs b/osu.Game/IO/Serialization/IJsonSerializable.cs index 8d10f0b291..38e7f47656 100644 --- a/osu.Game/IO/Serialization/IJsonSerializable.cs +++ b/osu.Game/IO/Serialization/IJsonSerializable.cs @@ -20,6 +20,10 @@ namespace osu.Game.IO.Serialization public static T DeepClone(this T obj) where T : IJsonSerializable => Deserialize(Serialize(obj)); + /// + /// Creates the default that should be used for all s. + /// + /// public static JsonSerializerSettings CreateGlobalSettings() => new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore, From b0684cb194c11a24e6293e38bee98d3f4fc94191 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 7 Dec 2017 12:02:34 +0900 Subject: [PATCH 022/122] Add storyboard test case but disable for now --- .../Beatmaps/Formats/OsuJsonDecoderTest.cs | 23 +- ...ow - Rengetsu Ouka (_Kiva) [Yuki YukI].osu | 1231 +++++++++++++++++ osu.Game.Tests/osu.Game.Tests.csproj | 1 + 3 files changed, 1245 insertions(+), 10 deletions(-) create mode 100644 osu.Game.Tests/Resources/Kozato snow - Rengetsu Ouka (_Kiva) [Yuki YukI].osu diff --git a/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs index c3ebcb9e7c..5a66a7047d 100644 --- a/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs @@ -19,13 +19,14 @@ namespace osu.Game.Tests.Beatmaps.Formats [TestFixture] public class OsuJsonDecoderTest { - private const string beatmap_1 = "Soleily - Renatus (Gamu) [Insane].osu"; - private const string beatmap_2 = "Within Temptation - The Unforgiving (Armin) [Marathon].osu"; + private const string normal = "Soleily - Renatus (Gamu) [Insane].osu"; + private const string marathon = "Within Temptation - The Unforgiving (Armin) [Marathon].osu"; + private const string with_sb = "Kozato snow - Rengetsu Ouka (_Kiva) [Yuki YukI].osu"; [Test] public void TestDecodeMetadata() { - var beatmap = decodeAsJson(beatmap_1); + var beatmap = decodeAsJson(normal); var meta = beatmap.BeatmapInfo.Metadata; Assert.AreEqual(241526, meta.OnlineBeatmapSetID); Assert.AreEqual("Soleily", meta.Artist); @@ -43,7 +44,7 @@ namespace osu.Game.Tests.Beatmaps.Formats [Test] public void TestDecodeGeneral() { - var beatmap = decodeAsJson(beatmap_1); + var beatmap = decodeAsJson(normal); var beatmapInfo = beatmap.BeatmapInfo; Assert.AreEqual(0, beatmapInfo.AudioLeadIn); Assert.AreEqual(false, beatmapInfo.Countdown); @@ -57,7 +58,7 @@ namespace osu.Game.Tests.Beatmaps.Formats [Test] public void TestDecodeEditor() { - var beatmap = decodeAsJson(beatmap_1); + var beatmap = decodeAsJson(normal); var beatmapInfo = beatmap.BeatmapInfo; int[] expectedBookmarks = @@ -78,7 +79,7 @@ namespace osu.Game.Tests.Beatmaps.Formats [Test] public void TestDecodeDifficulty() { - var beatmap = decodeAsJson(beatmap_1); + var beatmap = decodeAsJson(normal); var difficulty = beatmap.BeatmapInfo.BaseDifficulty; Assert.AreEqual(6.5f, difficulty.DrainRate); Assert.AreEqual(4, difficulty.CircleSize); @@ -91,7 +92,7 @@ namespace osu.Game.Tests.Beatmaps.Formats [Test] public void TestDecodeColors() { - var beatmap = decodeAsJson(beatmap_1); + var beatmap = decodeAsJson(normal); Color4[] expected = { new Color4(142, 199, 255, 255), @@ -109,7 +110,7 @@ namespace osu.Game.Tests.Beatmaps.Formats [Test] public void TestDecodeHitObjects() { - var beatmap = decodeAsJson(beatmap_1); + var beatmap = decodeAsJson(normal); var curveData = beatmap.HitObjects[0] as IHasCurve; var positionData = beatmap.HitObjects[0] as IHasPosition; @@ -128,8 +129,10 @@ namespace osu.Game.Tests.Beatmaps.Formats Assert.IsTrue(beatmap.HitObjects[1].Samples.Any(s => s.Name == SampleInfo.HIT_CLAP)); } - [TestCase(beatmap_1)] - [TestCase(beatmap_2)] + [TestCase(normal)] + [TestCase(marathon)] + // Currently fails: + // [TestCase(with_sb)] public void TestParity(string beatmap) { var beatmaps = decode(beatmap); diff --git a/osu.Game.Tests/Resources/Kozato snow - Rengetsu Ouka (_Kiva) [Yuki YukI].osu b/osu.Game.Tests/Resources/Kozato snow - Rengetsu Ouka (_Kiva) [Yuki YukI].osu new file mode 100644 index 0000000000..38db42fddc --- /dev/null +++ b/osu.Game.Tests/Resources/Kozato snow - Rengetsu Ouka (_Kiva) [Yuki YukI].osu @@ -0,0 +1,1231 @@ +osu file format v9 + +[General] +AudioFilename: Kozato snow.mp3 +AudioLeadIn: 1000 +PreviewTime: 173263 +Countdown: 0 +SampleSet: Soft +StackLeniency: 0.5 +Mode: 0 +LetterboxInBreaks: 0 + +[Editor] +Bookmarks: 14893,27933,40766,54427,67053,80300,94167,107414,120247,133919,147166,160424,173673,187336,200172 +DistanceSpacing: 0.5 +BeatDivisor: 4 +GridSize: 8 + +[Metadata] +Title:Rengetsu Ouka +Artist:Kozato snow +Creator:_Kiva +Version:Yuki YukI +Source: +Tags:Kiva Snowy Dream Yumeko Yuki HakuNoKaemi wmfchris aabc271 + +[Difficulty] +HPDrainRate:8 +CircleSize:4 +OverallDifficulty:7 +ApproachRate:8 +SliderMultiplier:1.8 +SliderTickRate:0.5 + +[Events] +//Background and Video events +0,0,"BG_example.JPG" +//Break Periods +2,54644,66322 +2,67893,79572 +2,107641,119526 +2,160627,172513 +//Storyboard Layer 0 (Background) +Sprite,Background,Centre,"SB\bg2.png",320,240 + S,0,26288,26495,1,1.04096 + F,0,26288,27530,1,0 + S,0,26495,27530,1.04096,1.26624 +Sprite,Background,Centre,"SB\C32.png",320,240 + M,0,41193,54436,259,283,320,240 + F,0,41193,54436,1 + S,0,41193,54436,1.2048,1.13312 + R,0,41193,54436,0,0.1023999 + F,0,54436,55264,1,0 + S,0,54436,55264,1.13312,1.29696 +Sprite,Background,Centre,"SB\bg1.png",320,240 + F,0,27944,,1 + S,0,27944,41193,1,1.327681 + S,0,41193,,1.327681 +Sprite,Background,Centre,"SB\bg3.png",320,240 + F,0,160427,162083,0,1 + S,0,160427,162083,1 + S,0,162083,166829,1,1.035869 + F,0,162083,173677,1,0.9987923 + S,0,166829,173677,1.035869,1.11264 + F,0,173677,173780,0.9987923,0.8605523 +//Storyboard Layer 1 (Fail) +//Storyboard Layer 2 (Pass) +//Storyboard Layer 3 (Foreground) +Sprite,Foreground,Centre,"SB\bg2.png",320,240 + F,0,1445,2687,0.8,0 + S,0,1445,2687,1,1.16 +Sprite,Foreground,Centre,"SB\Mini Light.png",320,240 + M,0,24631,,140,147 + S,0,24631,24838,0.19104,0.488 + F,0,24631,25045,1,0 + S,0,24838,25045,0.488,0.5903998 +Sprite,Foreground,Centre,"SB\MINI SNOW.png",320,240 + M,0,25045,,472,224 + S,0,25045,25252,0.32416,0.5392001 + F,0,25045,25459,1,0 + S,0,25252,25459,0.5392001,0.6518402 +Sprite,Foreground,Centre,"SB\black.png",320,240 + F,0,26702,27944,0,1 + F,0,27944,28358,1,0.55296 + F,0,28358,28772,0.55296,0.005119934 +Sprite,Foreground,Centre,"SB\OP effect.png",320,240 + M,0,25459,,193,293 + F,0,25459,25666,1,0 + S,0,25459,25666,0.61088,1.24576 +Sprite,Foreground,Centre,"SB\OP effect.png",320,240 + M,0,25666,,387,373 + P,0,25666,,H + V,0,25666,,1.06144,1 + V,0,25666,,1.06144,1 + F,0,25666,25873,1,0 + S,0,25666,25873,0.6313599,1.4096 +Sprite,Foreground,Centre,"SB\OP effect.png",320,240 + M,0,25873,,417,134 + M,0,25873,,417,134 + P,0,25873,,V + F,0,25873,26080,1,0 + S,0,25873,26080,1,1.52224 +Sprite,Foreground,Centre,"SB\OP effect.png",320,240 + F,0,26080,26288,1,0 + S,0,26080,26288,1,1.54272 +Sprite,Foreground,Centre,"SB\sakura_b.png",320,240 + S,0,26288,26391,0.3,0.7 + F,0,26288,27116,1 + S,0,26391,27530,0.7,0.9 + F,0,27116,27530,1,0 +Sprite,Foreground,Centre,"SB\sakura_b.png",320,240 + M,0,26288,,529,377 + P,0,26288,,H + S,0,26288,26391,0.4,0.55 + F,0,26288,26702,1,0 + S,0,26391,26702,0.55,0.9 +Sprite,Foreground,Centre,"SB\sakura_b.png",320,240 + M,0,26288,,202,210 + P,0,26288,,H + P,0,26288,,V + S,0,26288,26391,0.4,0.64 + F,0,26288,26702,1,0 + S,0,26391,26702,0.64,0.7 +Sprite,Foreground,Centre,"SB\azure.png",320,240 + F,0,40779,41193,0,1 + F,0,41193,41814,1,0 +Sprite,Foreground,Centre,"SB\sakura_b",320,240 + F,0,54436,55264,0,1 + R,0,54436,61060,0.2252804,0 + S,0,54443,,1.5625 + M,0,54443,61060,378,177,304,342 + F,0,55264,59404,1 + F,0,59404,61060,1,0 +Sprite,Foreground,Centre,"SB\bg2.png",320,240 + F,0,61060,61267,0,0.7122133 + S,0,61060,62302,1,1.1024 + F,0,61267,62302,0.7122133,0 +Sprite,Foreground,Centre,"SB\bg2.png",320,240 + F,0,67685,67892,0,0.8333333 + S,0,67685,68927,1,1.13312 + F,0,67892,68927,0.8333333,0 +Sprite,Foreground,Centre,"SB\wakka.png",320,240 + M,0,80935,,305,116 + F,0,80935,81038,1,0.9206253 + S,0,80935,81038,0.3548797,0.7181275 + S,0,81038,,0.7181275 + F,0,81038,81349,0.9206253,0.6809599 + S,0,81038,81556,0.7181275,0.8000475 + F,0,81349,81556,0.6809599,0 +Sprite,Foreground,Centre,"SB\wakka.png",320,240 + F,0,14694,14901,0,0.8333333 + S,0,14694,14901,0.7337599,1.41984 + S,0,14901,15108,1.41984,1.6144 + F,0,14901,15936,0.8333333,0 + S,0,15108,15522,1.6144,1.80896 + S,0,15522,15936,1.80896,1.94208 +Animation,Foreground,Centre,"SB\am2\am2.png",320,240,5,500,LoopForever + S,0,67685,,1 + R,0,67685,,0 + F,0,67685,68513,0,0.7696 + M,0,67685,74310,102,25,93,434 + F,0,68513,69341,0.7696,1 + F,0,69341,70169,1,0.7696 + F,0,70169,70998,0.7696,1 + F,0,70998,71826,1,0.8771199 + F,0,71826,72654,0.8771199,1 + F,0,72654,73482,1,0.73888 + F,0,73482,74310,0.73888,0 +Animation,Foreground,Centre,"SB\am2\am2.png",320,240,5,500,LoopForever + S,0,67685,,1 + R,0,67685,,0 + F,0,67685,68513,0,0.7696 + M,0,67685,74310,411,130,387,308 + F,0,68513,69341,0.7696,1 + F,0,69341,70169,1,0.7696 + F,0,70169,70998,0.7696,1 + F,0,70998,71826,1,0.8771199 + F,0,71826,72654,0.8771199,1 + F,0,72654,73482,1,0.73888 + F,0,73482,74310,0.73888,0 +Animation,Foreground,Centre,"SB\am2\am2.png",320,240,5,500,LoopForever + S,0,67685,,1 + R,0,67685,,0 + F,0,67685,68513,0,0.7696 + M,0,67685,74310,102,25,93,434 + F,0,68513,69341,0.7696,1 + F,0,69341,70169,1,0.7696 + F,0,70169,70998,0.7696,1 + F,0,70998,71826,1,0.8771199 + F,0,71826,72654,0.8771199,1 + F,0,72654,73482,1,0.73888 + F,0,73482,74310,0.73888,0 +Animation,Foreground,Centre,"SB\am2\am2.png",320,240,5,500,LoopForever + S,0,67685,,1 + R,0,67685,,0 + F,0,67685,68513,0,0.7696 + M,0,67685,74310,179,179,203,467 + F,0,68513,69341,0.7696,1 + F,0,69341,70169,1,0.7696 + F,0,70169,70998,0.7696,1 + F,0,70998,71826,1,0.8771199 + F,0,71826,72654,0.8771199,1 + F,0,72654,73482,1,0.73888 + F,0,73482,74310,0.73888,0 +Animation,Foreground,Centre,"SB\am2\am2.png",320,240,5,500,LoopForever + S,0,67685,,1 + R,0,67685,,0 + F,0,67685,68513,0,0.7696 + M,0,67685,74310,237,361,274,534 + F,0,68513,69341,0.7696,1 + F,0,69341,70169,1,0.7696 + F,0,70169,70998,0.7696,1 + F,0,70998,71826,1,0.8771199 + F,0,71826,72654,0.8771199,1 + F,0,72654,73482,1,0.73888 + F,0,73482,74310,0.73888,0 +Animation,Foreground,Centre,"SB\am2\am2.png",320,240,5,500,LoopForever + S,0,67685,,0.63136 + R,0,67685,,0 + F,0,67685,68513,0,0.7696 + M,0,67685,74310,227,175,267,525 + F,0,68513,69341,0.7696,1 + F,0,69341,70169,1,0.7696 + F,0,70169,70998,0.7696,1 + F,0,70998,71826,1,0.8771199 + F,0,71826,72654,0.8771199,1 + F,0,72654,73482,1,0.73888 + F,0,73482,74310,0.73888,0 +Animation,Foreground,Centre,"SB\am2\am2.png",320,240,5,500,LoopForever + S,0,67685,,0.41632 + R,0,67685,,0 + F,0,67685,68513,0,0.7696 + M,0,67685,74310,564,-67,619,531 + F,0,68513,69341,0.7696,1 + F,0,69341,70169,1,0.7696 + F,0,70169,70998,0.7696,1 + F,0,70998,71826,1,0.8771199 + F,0,71826,72654,0.8771199,1 + F,0,72654,73482,1,0.73888 + F,0,73482,74310,0.73888,0 +Sprite,Foreground,Centre,"SB\SNOW.png",320,240 + S,0,67685,,2.35168 + F,0,67685,70998,0,1 + M,0,67685,80314,320,-211,317,693 + F,0,68513,80314,1,0 + F,0,70998,79279,1 + F,0,79279,80314,1,0 +Animation,Foreground,Centre,"SB\am2\am2.png",320,240,5,500,LoopForever + F,0,70998,71826,0,1 + M,0,70998,74299,257,66,263,208 + F,0,71826,72654,1,0.7132799 + F,0,72654,73689,0.7132799,1 + F,0,73689,74310,1,0 +Animation,Foreground,Centre,"SB\am2\am2.png",320,240,5,500,LoopForever + S,0,70998,,0.7030401 + F,0,70998,71826,0,1 + M,0,70998,74310,431,109,422,223 + F,0,71826,72654,1,0.7132799 + F,0,72654,73689,0.7132799,1 + F,0,73689,74310,1,0 +Animation,Foreground,Centre,"SB\am2\am2.png",320,240,5,500,LoopForever + F,0,70998,71826,0,1 + M,0,70998,74299,73,-34,66,270 + F,0,71826,72654,1,0.7132799 + F,0,72654,73689,0.7132799,1 + F,0,73689,74310,1,0 +Animation,Foreground,Centre,"SB\am2\am2.png",320,240,5,500,LoopForever + S,0,70998,,0.6825599 + F,0,70998,71826,0,1 + M,0,70998,74299,390,75,370,115 + F,0,71826,72654,1,0.7132799 + F,0,72654,73689,0.7132799,1 + F,0,73689,74310,1,0 +Sprite,Foreground,Centre,"SB\wakka.png",320,240 + M,0,81763,,249,251 + S,0,81763,81866,0.39584,0.6620799 + F,0,81763,82384,1,0 + S,0,81866,82384,0.6620799,0.8975999 +Sprite,Foreground,Centre,"SB\wakka.png",320,240 + M,0,82591,,152,394 + S,0,82591,82694,0.3651201,0.7952 + F,0,82591,83212,1,0 + S,0,82694,83212,0.7952,1.01024 +Sprite,Foreground,Centre,"SB\wakka.png",320,240 + M,0,83419,,456,324 + S,0,83419,83523,0.3856,0.744 + F,0,83419,84040,1,0 + S,0,83523,84040,0.744,1.02048 +Sprite,Foreground,Centre,"SB\wakka.png",320,240 + M,0,85075,,321,197 + S,0,85075,85179,0.37536,0.80544 + F,0,85075,85696,0.9948799,0 + S,0,85179,85696,0.80544,1.12288 +Sprite,Foreground,Centre,"SB\wakka.png",320,240 + M,0,85903,,248,284 + S,0,85903,86007,0.3344,0.8464 + F,0,85903,86524,1,0 + S,0,86007,86524,0.8464,1.2048 +Sprite,Foreground,Centre,"SB\wakka.png",320,240 + M,0,86731,,207,101 + S,0,86731,86835,0.37536,0.8 + F,0,86731,87352,1,0 + S,0,86835,87352,0.8463999,1.22528 +Sprite,Foreground,Centre,"SB\wakka.png",320,240 + M,0,87560,,472,229 + S,0,87560,87663,0.3,0.8 + F,0,87560,88180,1,0 + S,0,87663,88180,0.8,1.12 +Sprite,Foreground,Centre,"SB\wakka.png",320,240 + M,0,88388,,408,373 + S,0,88388,88491,0.3,0.8 + F,0,88388,88905,1,0 + S,0,88491,88905,0.8,1.12 +Sprite,Foreground,Centre,"SB\wakka.png",320,240 + M,0,89216,,321,136 + S,0,89216,89319,0.3,0.8 + F,0,89216,89733,1,0 + S,0,89319,89733,0.8,1.12 +Sprite,Foreground,Centre,"SB\wakka.png",320,240 + M,0,90044,,257,252 + S,0,90044,90147,0.3,0.8 + F,0,90044,90561,1,0 + S,0,90147,90561,0.8,1.12 +Sprite,Foreground,Centre,"SB\wakka.png",320,240 + M,0,90872,,265,292 + S,0,90872,90975,0.3,0.8 + F,0,90872,91389,1,0 + S,0,90975,91389,0.8,1.12 +Sprite,Foreground,Centre,"SB\wakka.png",320,240 + M,0,91700,,265,132 + S,0,91700,91804,0.3,0.8 + F,0,91700,92217,1,0 + S,0,91804,92217,0.8,1.12 +Sprite,Foreground,Centre,"SB\wakka.png",320,240 + M,0,92528,,521,252 + S,0,92528,92632,0.3,0.8 + F,0,92528,93045,1,0 + S,0,92632,93045,0.8,1.12 +Sprite,Foreground,Centre,"SB\wakka.png",320,240 + M,0,93356,,304,309 + S,0,93356,93460,0.3,0.8 + F,0,93356,93873,1,0 + S,0,93460,93873,0.8,1.12 +Sprite,Foreground,Centre,"SB\wakka.png",320,240 + M,0,84247,,495,122 + S,0,84247,84351,0.3855998,0.7849598 + F,0,84247,84868,1,0 + S,0,84351,84868,0.7849598,1.13312 +Sprite,Foreground,Centre,"SB\bg2.png",320,240 + M,0,94184,,320,240 + S,0,94184,94391,1,1.05632 + F,0,94184,95012,1,0 + S,0,94391,95012,1.05632,1.19456 +Sprite,Foreground,Centre,"SB\azure.png",320,240 + F,0,100809,102051,0.38048,0 +Sprite,Foreground,Centre,"SB\azure.png",320,240 + R,0,120276,,0 + F,0,120276,120690,0,1 + F,0,120690,121518,1,0 +Sprite,Foreground,Centre,"SB\bg4.png",320,240 + F,0,107441,133112,1 + S,0,107441,133112,1.3,1 + R,0,107441,133112,0.2,0 +Sprite,Foreground,Centre,"SB\azure.png",320,240 + F,0,107020,107434,0,1 + F,0,107434,108269,1,0 +Sprite,Foreground,Centre,"SB\C32.png",320,240 + F,0,173682,190322,1 + M,0,173682,200181,228,268,320,240 + S,0,173682,200181,1.70656,1 + R,0,173682,200181,0.3072,0 + F,0,190322,192412,1 + F,0,192412,200181,1 + F,0,200181,201009,1,0 +Sprite,Foreground,Centre,"SB\sakura_b.png",320,240 + F,0,173677,173682,0.69792,0.3702399 + S,0,173682,180306,1,1.43008 + R,0,173682,180306,0.04096008,2.7648 + F,0,173682,186103,0.3702399 + S,0,180306,186931,1.43008,1.64512 + R,0,180306,186931,2.7648,4.68992 + F,0,186103,186931,0.3702399,0 +Sprite,Foreground,Centre,"SB\MINI SNOW.png",320,240 + F,0,186931,187759,0,1 + S,0,186931,200181,1,1.53248 + R,0,186931,200181,1.92512,0 + F,0,187759,199353,1 + F,0,199353,200181,1,0 +Sprite,Foreground,Centre,"SB\sakura_b.png",320,240 + F,0,186931,188173,0,0.3503307 + S,0,186931,199353,1,1.28672 + R,0,186931,199353,-3.23584,-1.76128 + F,0,188173,198110,0.3503307,0.19104 + F,0,198110,199353,0.19104,0.005120086 + F,0,199353,200724,0.005120086,0 +Animation,Foreground,Centre,"SB\am1\am1.jpg",320,240,5,500,LoopForever + M,0,74310,,313,234 + F,0,74310,74724,0.05792008,1 + F,0,74724,75345,1,0.8813094 + F,0,75345,75966,0.8813094,0.9981386 + F,0,75966,76794,0.9981386,0.8279376 + F,0,76794,77622,0.8279376,0.9956568 + F,0,77622,78450,0.9956568,0.7588959 + F,0,78450,79279,0.7588959,0.9931734 + F,0,79279,80107,0.9931734,0.01013343 +Sprite,Foreground,Centre,"SB\wakka.png",320,240 + M,0,74310,,313,232 + S,0,74310,74413,0.3139198,0.6415999 + F,0,74310,75138,1,0 + S,0,74413,75138,0.6415999,0.7961942 +Sprite,Foreground,Centre,"SB\bg2.png",320,240 + F,0,133112,133940,0,1 + F,0,133940,147178,1 + S,0,133940,147178,1,1.16384 + F,0,147178,147592,1,0 + S,0,147178,147592,1.16384,1.33792 +Sprite,Foreground,Centre,"SB\sakura_b.png",320,240 + M,0,120690,,320,240 + S,0,120690,120794,1,1.29696 + F,0,120690,121104,1 + S,0,120794,121932,1.29696,1.44032 + F,0,121104,121932,1,0.002415478 +Sprite,Foreground,Centre,"SB\wakka.png",320,240 + S,0,160427,160531,0.7337601,1.4608 + F,0,160427,162083,1,0 + S,0,160531,161255,1.4608,1.77824 + S,0,161255,162083,1.77824,2.03615 +Sprite,Foreground,Centre,"SB\azure.png",320,240 + R,0,132284,,0 + F,0,132284,133112,0,1 + F,0,133112,133940,1,0 +Sprite,Foreground,Centre,"SB\wakka.png",320,240 + S,0,133940,134043,1,1.38912 + F,0,133940,134457,1,0.80544 + S,0,134043,134975,1.38912,1.89088 + F,0,134457,134975,0.80544,0 +Sprite,Foreground,Centre,"SB\SNOW.png",320,240 + S,0,108269,,2.37216 + F,0,108269,109097,0,1 + M,0,108269,120173,314,-250,315,229 + F,0,109097,112409,1 + F,0,112409,112823,1,0.80032 + F,0,112823,113237,0.80032,1 + F,0,113237,119344,1 + F,0,119344,120173,1,0 +Sprite,Foreground,Centre,"SB\black.png",320,240 + S,0,173263,,1 + F,0,173263,173682,0,1 + F,0,173682,174510,1,0 + F,0,173682,174510,1,0.004830897 +Sprite,Foreground,Centre,"SB\White Effect.png",320,240 + M,0,173677,,217,128 + F,0,173677,174510,1,0 + S,0,173677,174510,0.2115199,1.09216 +//Storyboard Sound Samples +//Background Colour Transformations +3,100,163,162,255 + +[TimingPoints] +1445,414.050100062108,4,2,1,70,1,0 +13659,-100,4,2,1,40,0,0 +13762,-100,4,2,1,45,0,0 +13866,-100,4,2,1,50,0,0 +13970,-100,4,2,1,55,0,0 +14073,-100,4,2,1,50,0,0 +14177,-100,4,2,1,55,0,0 +14280,-100,4,2,1,60,0,0 +14384,-100,4,2,1,75,0,0 +14487,-100,4,2,1,80,0,0 +14591,-100,4,2,1,85,0,0 +14694,-100,4,2,1,60,0,0 +14901,-100,4,2,0,45,0,0 +15005,-100,4,2,1,60,0,0 +15315,-100,4,2,0,45,0,0 +15419,-100,4,2,1,60,0,0 +15626,-100,4,2,0,45,0,0 +15833,-100,4,2,1,60,0,0 +16040,-100,4,2,0,45,0,0 +16247,-100,4,2,1,60,0,0 +16454,-100,4,2,0,45,0,0 +16764,-100,4,2,1,60,0,0 +16868,-100,4,2,0,45,0,0 +17178,-100,4,2,1,60,0,0 +17282,-100,4,2,0,45,0,0 +17489,-100,4,2,1,60,0,0 +17696,-100,4,2,0,45,0,0 +17903,-100,4,2,1,60,0,0 +18110,-100,4,2,0,45,0,0 +18317,-100,4,2,1,60,0,0 +18628,-100,4,2,0,45,0,0 +18731,-100,4,2,1,60,0,0 +18938,-100,4,2,0,45,0,0 +19145,-100,4,2,1,60,0,0 +19352,-100,4,2,0,45,0,0 +19559,-100,4,2,1,60,0,0 +19766,-100,4,2,0,45,0,0 +19973,-100,4,2,1,60,0,0 +20180,-100,4,2,0,45,0,0 +20387,-100,4,2,1,60,0,0 +20594,-100,4,2,0,45,0,0 +20801,-100,4,2,1,60,0,0 +21112,-100,4,2,0,45,0,0 +21215,-100,4,2,1,60,0,0 +21422,-100,4,2,0,45,0,0 +21629,-100,4,2,1,60,0,0 +21836,-100,4,2,0,45,0,0 +22043,-100,4,2,1,60,0,0 +22354,-100,4,2,0,45,0,0 +22458,-100,4,2,1,60,0,0 +22768,-100,4,2,0,45,0,0 +22872,-100,4,2,1,60,0,0 +23079,-100,4,2,0,45,0,0 +23286,-100,4,2,1,60,0,0 +23596,-100,4,2,0,45,0,0 +23700,-100,4,2,1,60,0,0 +23907,-100,4,2,0,45,0,0 +24114,-100,4,2,1,60,0,0 +24321,-100,4,2,0,45,0,0 +24528,-100,4,1,1,60,0,0 +27323,-100,4,2,1,60,0,0 +27530,-100,4,2,1,60,0,0 +27944,-100,4,2,1,60,0,0 +29082,-100,4,2,1,65,0,0 +39951,-100,4,2,1,80,0,0 +40158,-100,4,2,1,85,0,0 +40766,-100,4,2,1,30,0,0 +41193,-100,4,2,1,85,0,0 +41814,-100,4,2,1,85,0,0 +43471,-100,4,2,1,75,0,0 +44092,-100,4,2,1,65,0,0 +44299,-100,4,2,1,55,0,0 +44506,-100,4,2,1,45,0,0 +44920,-100,4,2,1,50,0,0 +45437,-100,4,2,1,55,0,0 +46162,-100,4,2,1,60,0,0 +47094,-100,4,2,1,65,0,0 +47818,-100,4,2,1,55,0,0 +48750,-100,4,2,1,60,0,0 +50095,-100,4,2,1,65,0,0 +54444,414.050100062108,4,2,1,70,1,0 +67383,-100,4,2,1,50,0,0 +67590,-100,4,2,1,70,0,0 +102680,-200,4,2,1,70,0,0 +105993,-100,4,2,1,70,0,0 +107441,414.050100062108,4,2,1,70,1,0 +107648,-100,4,2,1,70,0,0 +120380,-100,4,2,1,75,0,0 +132905,-100,4,2,1,35,0,0 +133008,-100,4,2,1,40,0,0 +133112,-100,4,2,1,45,0,0 +133215,-100,4,2,1,45,0,0 +133319,-100,4,2,1,50,0,0 +133422,-100,4,2,1,55,0,0 +133526,-100,4,2,1,60,0,0 +133629,-100,4,2,1,65,0,0 +133733,-100,4,2,1,70,0,0 +133836,-100,4,2,1,75,0,0 +133940,-100,4,2,1,80,0,1 +136217,-100,4,2,1,60,0,1 +137045,-100,4,2,1,80,0,1 +147174,-100,4,2,1,80,0,0 +147178,414.050100062108,4,2,1,70,1,0 +173263,-100,4,2,1,60,0,0 +173682,414.050100062108,4,2,1,70,1,0 +174303,-100,4,2,1,40,0,0 +174406,-100,4,2,1,45,0,0 +174510,-100,4,2,1,50,0,0 +174613,-100,4,2,1,55,0,0 +174717,-100,4,2,1,60,0,0 +174820,-100,4,2,1,65,0,0 +174924,-100,4,2,1,70,0,0 +175027,-100,4,2,1,75,0,0 +175131,-100,4,2,1,80,0,0 +186517,-100,4,2,1,30,0,0 +186931,-100,4,2,1,80,0,1 +187035,-100,4,2,1,80,0,1 +196247,-100,4,2,1,70,0,1 +196454,-100,4,2,1,60,0,1 +196661,-100,4,2,1,50,0,1 +196868,-100,4,2,1,80,0,1 +200181,-100,4,2,1,80,0,0 + +[Colours] +Combo1 : 152,48,207 +Combo2 : 254,75,169 +Combo3 : 226,5,221 +SliderBorder : 224,224,224 + +[HitObjects] +112,96,1030,1,0 +144,108,1134,1,0 +176,92,1237,1,0 +208,108,1341,1,0 +240,96,1445,1,0 +408,272,2894,5,0 +408,272,2997,1,0 +408,272,3101,2,0,B|360:280|312:272,1,90 +104,276,3515,2,0,B|152:268|200:276,1,90 +216,184,3929,1,0 +168,88,4136,1,0 +256,144,4343,1,0 +208,48,4550,1,0 +312,64,4757,5,0 +416,64,4964,1,0 +416,64,5067,2,0,B|448:104|464:144|464:200,1,135 +463,187,5481,1,0 +463,187,5585,1,0 +437,289,5792,1,0 +337,262,5999,1,0 +364,162,6206,1,0 +464,188,6413,1,0 +464,88,6620,6,0,B|424:64|368:56,1,90 +280,56,7034,2,0,B|184:56,1,90 +190,56,7448,1,0 +128,136,7655,1,0 +120,168,7759,1,0 +128,200,7862,1,0 +136,232,7966,1,0 +128,264,8069,1,0 +192,336,8276,5,0 +192,336,8380,2,0,B|240:336|288:328|336:312,1,135 +324,315,8794,1,0 +324,315,8897,1,0 +336,216,9104,1,0 +440,200,9311,1,0 +480,104,9518,1,0 +392,40,9726,6,0,B|288:40,1,90 +224,88,10140,1,0 +216,104,10243,1,0 +208,120,10347,1,0 +200,136,10450,1,0 +192,152,10554,1,0 +256,296,10761,1,0 +256,152,10968,1,0 +256,296,11175,1,0 +168,344,11382,5,0 +168,248,11589,1,0 +168,248,11692,1,0 +128,112,12003,1,0 +128,112,12106,1,0 +128,112,12210,2,0,B|144:160|128:208,1,90 +48,248,12624,2,0,B|32:200|48:152,1,90 +48,64,13038,5,0 +48,64,13245,2,0,B|96:64,2,45 +208,64,13659,1,0 +240,64,13762,1,0 +272,72,13866,1,0 +304,88,13970,1,0 +328,112,14073,1,8 +344,144,14177,1,8 +352,176,14280,1,8 +352,208,14384,5,0 +344,240,14487,1,0 +328,272,14591,1,0 +304,296,14694,2,0,B|264:320|216:328,1,90,0|2 +104,280,15108,2,0,B|144:256|192:248,1,90,0|2 +280,224,15522,1,0 +296,120,15729,1,2 +192,96,15936,1,0 +168,192,16143,5,2 +168,192,16247,1,0 +168,192,16350,1,0 +144,288,16557,2,0,B|208:288|208:288|232:264,1,90,2|0 +168,192,16971,2,0,B|104:192|104:192|80:216,1,90,2|0 +144,288,17385,1,2 +256,352,17592,1,0 +368,288,17799,1,2 +256,104,18007,5,0 +256,104,18214,1,2 +256,104,18317,2,0,B|256:240,1,135,0|2 +256,239,18731,1,0 +256,239,18835,1,0 +168,296,19042,1,2 +256,352,19249,1,0 +168,296,19456,1,2 +256,239,19663,1,0 +344,296,19870,1,2 +256,239,20077,1,0 +136,152,20284,5,2 +256,96,20491,1,0 +376,152,20698,1,2 +424,264,20905,1,0 +416,264,21008,1,0 +408,264,21112,1,2 +400,264,21215,1,0 +392,264,21319,1,0 +288,264,21526,1,2 +288,264,21629,1,0 +136,208,21940,5,2 +136,208,22043,1,0 +136,208,22147,2,0,B|136:144|136:144|160:128,1,90,0|2 +248,104,22561,2,0,B|248:168|248:168|224:184,1,90,0|2 +136,104,22975,1,0 +248,56,23182,1,2 +360,104,23389,1,0 +376,120,23493,1,0 +392,136,23596,1,2 +408,152,23700,1,0 +424,168,23803,1,0 +432,280,24010,5,2 +256,328,24217,1,0 +80,280,24424,1,2 +256,192,24631,12,0,27116 +256,192,27323,5,0 +256,192,27426,1,0 +256,192,27530,1,4 +72,136,27944,5,0 +161,84,28151,1,0 +158,182,28358,1,0 +96,80,28565,1,0 +192,32,28772,5,0 +224,32,28875,1,0 +256,32,28979,1,0 +288,32,29082,1,0 +320,32,29186,2,0,B|368:32,4,45 +272,112,29807,6,0,B|248:160|272:200,1,90 +360,160,30221,1,0 +368,168,30324,1,0 +376,176,30428,1,0 +384,184,30532,1,0 +392,192,30635,2,0,B|448:192,4,45 +328,280,31256,5,0 +224,296,31463,1,0 +128,248,31670,2,0,B|96:216|104:160,1,90 +176,88,32084,2,0,B|208:120|200:176,1,90 +128,248,32498,2,0,B|96:280,2,45 +216,192,32912,2,0,B|256:168|304:192,1,90 +264,288,33326,2,0,B|304:312|352:288,1,90 +408,208,33740,1,0 +424,104,33947,1,0 +336,40,34154,6,0,B|288:40,4,45,0|0|0|0|8 +336,136,34776,1,0 +176,136,34983,1,0 +256,72,35190,1,0 +256,112,35293,1,0 +256,160,35397,1,0 +88,264,35604,2,0,B|128:240|176:240,1,90 +424,264,36018,2,0,B|384:240|336:240,1,90 +208,320,36432,6,0,B|208:232,1,90 +304,320,36846,2,0,B|304:232,1,90 +256,144,37260,1,0 +256,144,37467,1,0 +256,144,37570,1,0 +256,144,37674,1,0 +336,80,37881,1,0 +424,136,38088,1,0 +424,136,38191,1,0 +424,136,38295,2,0,B|424:232,1,90 +344,272,38709,5,0 +344,176,38916,1,0 +256,328,39123,1,0 +256,120,39330,1,0 +176,224,39537,5,0 +176,224,39744,1,0 +176,224,39848,1,0 +176,224,39951,1,0 +120,128,40158,1,0 +120,128,40262,1,0 +120,128,40365,1,0 +224,128,40572,1,0 +224,128,40676,1,0 +224,128,40779,6,0,B|224:96,7,22.5 +224,105,41193,6,0,B|312:104,1,90,4|0 +400,152,41607,1,0 +400,256,41814,2,0,B|432:288,4,45 +304,312,42435,1,0 +208,256,42642,1,0 +208,256,42746,1,0 +208,256,42850,2,0,B|208:168,1,90 +168,80,43264,6,0,B|208:56|256:80,1,90 +272,112,43574,1,0 +288,144,43678,2,0,B|312:184|368:192,1,90 +368,96,44092,1,0 +368,288,44299,1,0 +280,336,44506,6,0,B|240:368,4,45 +232,248,45127,1,0 +232,248,45230,1,0 +128,248,45437,1,0 +120,248,45541,1,0 +112,248,45644,1,0 +104,248,45748,1,0 +48,168,45955,1,0 +104,80,46162,5,0 +120,80,46265,1,0 +136,80,46369,1,0 +152,80,46472,1,0 +168,80,46576,1,0 +272,80,46783,1,0 +272,80,46886,1,0 +376,80,47094,1,0 +400,80,47197,1,0 +424,80,47301,1,0 +448,80,47404,1,0 +456,176,47611,5,0 +400,256,47818,1,8 +368,256,47922,1,0 +336,256,48025,1,0 +304,256,48129,1,0 +272,256,48232,1,0 +176,256,48439,1,0 +176,256,48543,1,0 +80,256,48750,5,0 +80,256,48853,1,0 +80,256,48957,1,0 +80,256,49060,1,0 +128,168,49267,1,0 +32,168,49474,1,0 +32,168,49578,1,0 +32,168,49681,1,0 +32,168,49785,1,0 +32,168,49888,1,0 +80,80,50095,5,0 +96,72,50199,1,0 +200,40,50406,1,0 +224,40,50509,1,0 +248,40,50613,1,0 +272,40,50716,1,0 +360,96,50923,1,0 +415,175,51131,5,0 +336,230,51338,1,0 +281,151,51545,1,0 +360,96,51752,1,0 +360,96,51855,1,0 +360,96,51959,1,0 +442,214,52166,1,0 +323,297,52373,1,0 +241,178,52580,1,0 +241,178,52683,1,0 +241,178,52787,1,0 +256,192,52890,12,4,54444 +168,112,67072,5,0 +168,112,67176,1,0 +168,112,67279,1,0 +168,112,67486,1,8 +168,112,67693,1,4 +144,96,80322,5,0 +144,96,80425,1,0 +144,96,80529,1,0 +144,96,80736,1,0 +240,56,80943,1,12 +280,152,81150,1,0 +280,152,81253,1,0 +280,152,81357,1,0 +184,192,81564,1,0 +184,192,81771,1,4 +88,232,81978,5,0 +88,232,82185,1,0 +88,232,82392,1,0 +88,336,82599,2,8,B|184:336,1,90,8|0 +208,336,82909,1,0 +240,336,83013,2,0,B|328:336,1,90 +392,264,83427,1,4 +464,168,83634,1,0 +392,264,83841,1,0 +464,168,84048,1,0 +432,64,84255,6,8,B|336:64,1,90,8|0 +80,64,84669,2,8,B|176:64,1,90,0|0 +256,136,85083,1,4 +256,304,85290,1,0 +256,136,85497,1,0 +256,304,85704,1,0 +184,224,85911,5,8 +88,224,86118,1,0 +80,216,86222,1,0 +72,208,86325,1,0 +72,112,86532,1,0 +144,40,86739,2,0,B|240:40,1,90,4|0 +224,128,87153,2,0,B|312:128,1,90 +408,168,87568,6,0,B|432:208|416:256,1,90,8|0 +416,254,87878,1,0 +416,254,87982,1,0 +344,312,88189,1,0 +344,312,88396,1,4 +168,256,88603,1,0 +344,200,88810,1,0 +168,144,89017,1,0 +256,76,89224,5,8 +256,160,89431,1,0 +256,192,89534,1,0 +256,224,89638,1,0 +256,307,89845,1,0 +192,192,90052,1,4 +256,76,90259,1,0 +320,192,90466,1,0 +256,307,90673,1,0 +200,232,90880,5,8 +312,232,91087,1,0 +152,152,91294,1,0 +360,152,91501,1,0 +200,72,91708,5,4 +312,72,91915,1,0 +152,152,92122,1,0 +360,152,92329,1,0 +456,192,92536,5,8 +416,288,92743,1,0 +384,288,92847,1,0 +352,288,92950,1,0 +264,336,93157,2,0,B|240:296|240:240,1,90,0|4 +240,160,93571,1,0 +208,64,93778,1,0 +176,72,93882,1,0 +152,96,93985,1,0 +136,128,94089,1,0 +136,160,94192,5,8 +72,240,94399,2,0,B|16:256,2,45 +136,312,94813,1,0 +192,232,95020,2,0,B|240:152,1,90 +376,112,95434,2,0,B|328:192,1,90 +464,112,96056,5,0 +496,192,96263,1,0 +464,272,96470,1,0 +48,272,96884,1,0 +16,192,97091,1,0 +48,112,97298,1,0 +152,64,97505,5,0 +224,136,97712,1,0 +152,64,97919,1,0 +248,40,98126,1,0 +344,72,98333,2,0,B|392:88|416:144,1,90 +392,224,98747,2,0,B|344:208|320:152,1,90 +224,136,99161,5,0 +152,208,99368,1,0 +144,240,99471,1,0 +152,272,99575,1,0 +248,222,99782,1,0 +248,312,99989,2,0,B|248:216,1,90 +328,112,100403,2,0,B|328:216,1,90 +360,288,100817,5,2 +432,216,101024,1,0 +432,184,101128,1,0 +432,152,101231,1,0 +400,64,101438,1,0 +304,40,101645,2,0,B|256:40|216:72,1,90 +200,168,102059,2,0,B|248:168|288:136,1,90 +176,280,102680,6,0,B|176:336,2,45 +336,104,103508,2,0,B|336:48,2,45 +336,104,104130,5,0 +416,192,104337,1,0 +336,280,104544,1,0 +256,192,104751,1,0 +176,280,104958,1,0 +96,192,105165,1,0 +176,104,105372,1,0 +256,192,105579,1,0 +256,192,105786,5,0 +256,192,105993,2,0,B|256:136,2,45 +256,192,106407,1,0 +256,288,106614,1,0 +256,288,106821,2,0,B|160:288,1,90 +144,288,107131,1,0 +128,288,107235,1,0 +112,288,107338,1,0 +96,288,107441,1,4 +256,56,120276,5,0 +248,88,120380,1,0 +256,120,120483,1,0 +264,152,120587,1,0 +256,184,120690,5,4 +160,208,120897,2,0,B|176:256|224:280,1,90 +296,208,121311,1,0 +312,192,121415,1,0 +336,184,121518,5,0 +360,184,121622,1,0 +376,192,121725,1,0 +392,208,121829,1,0 +400,232,121932,1,0 +376,336,122139,1,0 +376,336,122243,1,0 +376,336,122346,6,0,B|336:360|288:360,1,90 +192,336,122760,2,0,B|168:296|168:248,1,90 +272,208,123174,1,0 +216,104,123381,1,0 +336,88,123588,2,0,B|304:120|304:176,2,90 +416,168,124210,1,0 +416,168,124313,2,0,B|472:192|472:256|424:280,1,135 +432,275,124727,1,0 +432,275,124831,1,0 +344,224,125038,1,0 +240,208,125245,2,0,B|248:160|304:136,1,90 +360,80,125659,6,0,B|328:40|272:56,1,90 +216,144,126073,1,0 +104,136,126280,1,0 +104,136,126383,1,0 +104,136,126487,2,0,B|64:168|64:224,1,90 +136,296,126901,5,0 +160,320,127004,1,0 +192,328,127108,1,0 +224,320,127211,1,0 +248,296,127315,2,0,B|280:264|296:216,1,90 +294,219,127625,1,0 +408,80,127936,5,0 +368,80,128039,1,0 +328,80,128143,1,0 +224,80,128350,1,0 +72,40,128557,1,0 +104,192,128764,1,0 +272,144,128971,5,0 +120,104,129178,1,0 +152,256,129385,1,0 +152,256,129489,1,0 +152,256,129592,1,0 +152,256,129696,1,0 +152,256,129799,2,0,B|200:280|240:256,1,90 +328,128,130213,2,0,B|280:104|240:128,1,90 +240,224,130627,5,0 +336,256,130834,1,0 +320,288,130938,1,0 +296,312,131041,2,0,B|256:344|208:352,1,90 +184,352,131352,1,0 +152,352,131455,1,0 +64,264,131662,1,0 +160,264,131869,1,0 +32,248,132076,1,0 +192,248,132284,1,0 +96,160,132491,1,0 +120,136,132594,1,0 +152,128,132698,1,0 +248,128,132905,5,0 +280,120,133008,1,0 +312,120,133112,1,0 +344,128,133215,1,0 +372,144,133319,1,0 +392,176,133422,1,0 +400,208,133526,1,0 +400,240,133629,1,0 +392,272,133733,1,0 +376,304,133836,1,0 +344,320,133940,6,0,B|304:344|256:344,1,90,4|0 +192,280,134354,1,0 +92,264,134561,1,0 +80,232,134664,1,0 +76,196,134768,1,0 +80,160,134871,1,0 +88,128,134975,2,0,B|104:88|144:56,1,90 +232,104,135389,6,0,B|256:152,2,45,0|0|8 +232,104,135803,1,0 +380,49,136010,1,0 +289,185,136217,1,0 +283,14,136424,1,0 +389,149,136631,1,0 +232,104,136838,1,0 +380,49,137045,1,0 +289,185,137252,5,4 +289,185,137459,1,0 +289,185,137563,1,0 +112,256,137873,1,0 +112,256,137977,1,0 +112,256,138080,2,0,B|160:272|208:256,1,90 +400,256,138494,2,0,B|352:240|304:256,1,90 +256,184,138908,5,8 +288,72,139115,1,0 +232,152,139322,1,0 +264,40,139529,1,0 +168,72,139736,1,0 +168,72,139943,1,0 +100,160,140150,1,0 +88,192,140254,1,0 +84,224,140357,1,0 +88,256,140461,1,0 +96,288,140565,6,0,B|128:328|184:336,1,90,4|0 +208,336,140875,1,0 +248,336,140979,2,0,B|336:336,1,90 +376,336,141289,1,0 +408,336,141393,1,0 +455,255,141600,1,0 +460,82,141807,1,0 +351,217,142014,1,0 +512,172,142221,5,8 +361,117,142428,1,0 +256,116,142635,2,0,B|208:116,3,45 +184,132,143049,2,0,B|144:160|144:216,1,90 +256,280,143463,2,0,B|296:252|296:196,1,90 +256,192,143877,12,4,147178 +152,120,148627,6,0,B|184:88,2,45 +152,232,149041,1,0 +264,232,149248,2,0,B|264:280|224:320,1,90 +152,232,149662,2,0,B|152:184|192:144,1,90 +288,128,150076,5,0 +416,64,150283,1,0 +288,128,150490,1,8 +392,184,150697,1,0 +392,184,150800,2,0,B|408:232|408:280|352:320,1,135 +367,307,151214,1,0 +367,307,151318,5,0 +256,344,151525,1,0 +98,316,151732,1,0 +126,158,151939,1,0 +283,186,152146,1,0 +194,290,152353,1,0 +36,262,152560,1,0 +64,104,152767,1,0 +221,132,152974,5,0 +194,290,153181,1,0 +128,192,153388,1,0 +144,192,153492,1,0 +160,192,153595,1,0 +176,192,153699,1,0 +192,192,153802,2,0,B|320:192,1,90,4|0 +280,192,154113,1,0 +472,152,154423,5,0 +480,192,154527,1,0 +472,232,154630,1,0 +336,192,154837,1,0 +456,112,155044,1,0 +456,272,155251,1,0 +360,328,155459,5,0 +152,328,155666,1,0 +256,272,155873,1,0 +256,240,155976,1,0 +256,208,156080,1,0 +256,176,156183,1,0 +256,144,156287,1,0 +320,64,156494,2,0,B|376:64|392:112,2,90,0|0|0 +216,64,157115,5,8 +216,64,157322,1,0 +216,64,157425,1,0 +88,104,157736,1,0 +88,104,157839,1,0 +88,104,157943,2,0,B|88:200,1,90 +184,256,158357,2,0,B|184:160,1,90 +88,228,158771,2,0,B|88:324,1,90 +88,318,159081,1,0 +88,318,159185,1,0 +192,320,159392,5,0 +208,320,159495,1,0 +224,320,159599,1,0 +240,320,159703,1,0 +256,320,159806,1,0 +272,320,159910,1,0 +288,320,160013,1,0 +304,320,160117,1,0 +320,320,160220,1,0 +336,320,160324,1,0 +352,320,160427,1,4 +152,72,173263,6,0,B|152:128,4,45,0|0|0|0|8 +248,48,173889,2,0,B|336:48,1,90,0|0 +408,120,174303,2,0,B|456:120,2,45,0|0|0 +376,152,174613,2,0,B|328:152,2,45 +408,184,174924,2,0,B|464:184,2,45 +376,216,175234,1,0 +344,240,175338,6,0,B|240:240,1,90,0|0 +184,184,175752,1,0 +144,296,175959,1,0 +152,160,176166,1,0 +112,272,176373,1,0 +32,216,176580,1,0 +32,112,176787,2,0,B|48:72|96:48,1,90,0|0 +200,48,177201,5,0 +200,48,177304,2,0,B|344:48,1,135 +368,48,177718,1,0 +400,48,177822,1,0 +448,144,178029,1,0 +424,256,178236,2,0,B|376:240|352:192,1,90,0|0 +344,160,178547,1,0 +336,120,178650,2,0,B|288:128|248:168,1,90,0|0 +160,224,179064,6,0,B|256:248,1,90 +352,160,179478,2,0,B|256:136,1,90 +176,88,179892,1,0 +144,72,179996,1,0 +112,88,180099,1,0 +80,72,180203,1,0 +56,88,180306,5,0 +56,176,180513,1,0 +56,176,180617,2,0,B|56:312,1,135 +56,311,181031,1,0 +56,311,181134,1,0 +168,312,181341,1,0 +256,256,181548,1,0 +344,312,181755,1,0 +440,280,181963,2,0,B|472:240|464:192,1,90,0|0 +440,96,182377,5,0 +432,80,182480,1,0 +424,64,182584,1,0 +416,48,182687,1,0 +408,32,182791,2,0,B|344:32|344:32|328:56,1,90 +288,136,183205,2,0,B|200:136,1,90 +128,64,183619,2,0,B|120:32|120:32|56:32,1,90 +32,32,183929,2,0,B|32:168,1,135 +32,200,184343,1,0 +32,232,184447,5,0 +128,272,184654,2,0,B|216:320,1,90 +328,272,185068,2,0,B|240:224,1,90 +168,160,185482,1,0 +176,120,185585,1,0 +208,96,185689,1,0 +320,80,185896,5,0 +352,88,185999,1,0 +376,112,186103,1,0 +384,152,186207,1,0 +376,184,186310,1,0 +344,208,186414,1,0 +312,208,186517,2,0,B|280:192,8,22.5,0|0|0|0|0|0|0|0|4 +256,192,187035,12,0,188173 +256,96,188380,5,0 +256,96,188484,1,0 +256,96,188587,1,8 +376,96,188794,1,0 +448,184,189001,2,0,B|360:216,1,90 +424,304,189415,2,0,B|336:336,1,90 +216,336,189829,1,0 +144,232,190036,1,0 +216,336,190244,1,4 +280,232,190451,5,0 +280,232,190554,2,0,B|280:96,1,135 +280,64,190968,1,0 +280,32,191072,1,0 +176,64,191279,1,0 +121,179,191486,1,0 +237,233,191693,1,0 +291,117,191900,2,0,B|360:184,1,90,8|0 +400,264,192314,6,0,B|352:256|304:264,1,90 +112,264,192728,2,0,B|160:256|208:264,1,90 +256,168,193142,2,0,B|280:128,4,45,0|0|0|0|4 +160,112,193763,1,0 +160,112,193866,2,0,B|104:112|64:144|64:208,1,135 +64,224,194280,1,0 +64,256,194384,1,0 +128,352,194591,5,0 +192,256,194798,1,0 +256,352,195005,1,0 +368,352,195212,2,0,B|416:340|420:280,1,90,8|0 +416,184,195626,1,0 +408,168,195730,1,0 +400,152,195833,1,0 +392,136,195937,1,0 +384,120,196040,5,0 +184,64,196247,1,0 +128,264,196454,1,0 +328,320,196661,1,0 +256,192,196868,12,8,199767 +256,192,200181,5,4 diff --git a/osu.Game.Tests/osu.Game.Tests.csproj b/osu.Game.Tests/osu.Game.Tests.csproj index 3a15b5e6b1..df22aede95 100644 --- a/osu.Game.Tests/osu.Game.Tests.csproj +++ b/osu.Game.Tests/osu.Game.Tests.csproj @@ -151,6 +151,7 @@ + \ No newline at end of file From fcfdbc8e07cf19ee234e2bff03eb0105272c9410 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 7 Dec 2017 12:02:48 +0900 Subject: [PATCH 023/122] Don't show the migrate button on deployed builds for now --- .../Sections/Maintenance/GeneralSettings.cs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs index f0f5b434cd..2b40ade895 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs @@ -20,7 +20,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance protected override string Header => "General"; [BackgroundDependencyLoader] - private void load(BeatmapManager beatmaps) + private void load(OsuGameBase osuGame, BeatmapManager beatmaps) { Children = new Drawable[] { @@ -55,8 +55,12 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance beatmaps.Restore(b); }).ContinueWith(t => Schedule(() => restoreButton.Enabled.Value = true)); } - }, - migrateButton = new SettingsButton + } + }; + + if (!osuGame.IsDeployedBuild) + { + Add(migrateButton = new SettingsButton { Text = "Migrate all beatmaps to the new format", Action = () => @@ -64,8 +68,8 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance migrateButton.Enabled.Value = false; Task.Factory.StartNew(beatmaps.MigrateAllToNewFormat).ContinueWith(t => Schedule(() => migrateButton.Enabled.Value = true), TaskContinuationOptions.LongRunning); } - } - }; + }); + } } } } From feef4b1890daa1bb609c995d3bd6a90d8c84b580 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 7 Dec 2017 12:18:00 +0900 Subject: [PATCH 024/122] Add license header --- osu.Game/IO/Serialization/Converters/TypedListConverter.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/IO/Serialization/Converters/TypedListConverter.cs b/osu.Game/IO/Serialization/Converters/TypedListConverter.cs index f8897a4e9d..36b53e1137 100644 --- a/osu.Game/IO/Serialization/Converters/TypedListConverter.cs +++ b/osu.Game/IO/Serialization/Converters/TypedListConverter.cs @@ -1,3 +1,6 @@ +// 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 Newtonsoft.Json; From f1dbcc4f1aab9d0b5540a9dfabeabea29858bc00 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 7 Dec 2017 12:23:53 +0900 Subject: [PATCH 025/122] Remove misleading comments --- osu.Game/Beatmaps/BeatmapManager.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 6b547afe5d..8d20a3dcfb 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -548,12 +548,10 @@ namespace osu.Game.Beatmaps public void UpdateContent(BeatmapInfo beatmapInfo, Stream newData) { - // let's only allow one concurrent update at a time for now. var context = createContext(); using (var transaction = context.BeginTransaction()) { - // create local stores so we can isolate and thread safely, and share a context/transaction. var setInfo = beatmapInfo.BeatmapSet; var existingSetFileInfo = setInfo.Files.First(f => f.FileInfo.Hash == beatmapInfo.Hash); var existingFileInfo = existingSetFileInfo.FileInfo; From 9e51480aa392935b9d06b29869cd9b24439d9d6a Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 7 Dec 2017 12:27:30 +0900 Subject: [PATCH 026/122] Cleanup TypedListConverter a bit --- osu.Game/IO/Serialization/Converters/TypedListConverter.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/osu.Game/IO/Serialization/Converters/TypedListConverter.cs b/osu.Game/IO/Serialization/Converters/TypedListConverter.cs index 36b53e1137..c3d5869035 100644 --- a/osu.Game/IO/Serialization/Converters/TypedListConverter.cs +++ b/osu.Game/IO/Serialization/Converters/TypedListConverter.cs @@ -69,10 +69,7 @@ namespace osu.Game.IO.Serialization.Converters serializer.Serialize(writer, lookupTable); writer.WritePropertyName("Items"); - writer.WriteStartArray(); - foreach (var item in objects) - item.WriteTo(writer); - writer.WriteEndArray(); + serializer.Serialize(writer, objects); writer.WriteEndObject(); } From d026587a915ad17d1ab9b3871fa0144ef1b6e095 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 7 Dec 2017 12:49:16 +0900 Subject: [PATCH 027/122] Add flag to explicitly serialize the type version --- .../Converters/TypedListConverter.cs | 31 +++++++++++++++++-- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/osu.Game/IO/Serialization/Converters/TypedListConverter.cs b/osu.Game/IO/Serialization/Converters/TypedListConverter.cs index c3d5869035..32b7772092 100644 --- a/osu.Game/IO/Serialization/Converters/TypedListConverter.cs +++ b/osu.Game/IO/Serialization/Converters/TypedListConverter.cs @@ -16,6 +16,26 @@ namespace osu.Game.IO.Serialization.Converters /// The type of objects contained in the this attribute is attached to. public class TypedListConverter : JsonConverter { + private readonly bool requiresTypeVersion; + + /// + /// Constructs a new . + /// + // ReSharper disable once UnusedMember.Global + public TypedListConverter() + { + } + + /// + /// Constructs a new . + /// + /// Whether the version of the type should be serialized. + // ReSharper disable once UnusedMember.Global (Used in Beatmap) + public TypedListConverter(bool requiresTypeVersion) + { + this.requiresTypeVersion = requiresTypeVersion; + } + public override bool CanConvert(Type objectType) => objectType == typeof(List); public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) @@ -49,12 +69,17 @@ namespace osu.Game.IO.Serialization.Converters var objects = new List(); foreach (var item in list) { - var type = item.GetType().AssemblyQualifiedName; + var type = item.GetType(); + var assemblyName = type.Assembly.GetName(); - int typeId = lookupTable.IndexOf(type); + var typeString = $"{type.FullName}, {assemblyName.Name}"; + if (requiresTypeVersion) + typeString += $", {assemblyName.Version}"; + + int typeId = lookupTable.IndexOf(typeString); if (typeId == -1) { - lookupTable.Add(type); + lookupTable.Add(typeString); typeId = lookupTable.Count - 1; } From 245b5f759ff4a2cc00e4ca89a5b553bccbca0ade Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 7 Dec 2017 14:36:32 +0900 Subject: [PATCH 028/122] Underscore + lowercase all keys --- .../Converters/TypedListConverter.cs | 12 ++++++------ .../Serialization/Converters/Vector2Converter.cs | 6 +++--- osu.Game/IO/Serialization/IJsonSerializable.cs | 3 ++- osu.Game/IO/Serialization/KeyContractResolver.cs | 16 ++++++++++++++++ osu.Game/osu.Game.csproj | 1 + 5 files changed, 28 insertions(+), 10 deletions(-) create mode 100644 osu.Game/IO/Serialization/KeyContractResolver.cs diff --git a/osu.Game/IO/Serialization/Converters/TypedListConverter.cs b/osu.Game/IO/Serialization/Converters/TypedListConverter.cs index 32b7772092..7147f9110e 100644 --- a/osu.Game/IO/Serialization/Converters/TypedListConverter.cs +++ b/osu.Game/IO/Serialization/Converters/TypedListConverter.cs @@ -45,13 +45,13 @@ namespace osu.Game.IO.Serialization.Converters var obj = JObject.Load(reader); var lookupTable = new List(); - serializer.Populate(obj["LookupTable"].CreateReader(), lookupTable); + serializer.Populate(obj["lookup_table"].CreateReader(), lookupTable); - foreach (var tok in obj["Items"]) + foreach (var tok in obj["items"]) { var itemReader = tok.CreateReader(); - var typeName = lookupTable[(int)tok["Type"]]; + var typeName = lookupTable[(int)tok["type"]]; var instance = (T)Activator.CreateInstance(Type.GetType(typeName)); serializer.Populate(itemReader, instance); @@ -84,16 +84,16 @@ namespace osu.Game.IO.Serialization.Converters } var itemObject = JObject.FromObject(item, serializer); - itemObject.AddFirst(new JProperty("Type", typeId)); + itemObject.AddFirst(new JProperty("type", typeId)); objects.Add(itemObject); } writer.WriteStartObject(); - writer.WritePropertyName("LookupTable"); + writer.WritePropertyName("lookup_table"); serializer.Serialize(writer, lookupTable); - writer.WritePropertyName("Items"); + writer.WritePropertyName("items"); serializer.Serialize(writer, objects); writer.WriteEndObject(); diff --git a/osu.Game/IO/Serialization/Converters/Vector2Converter.cs b/osu.Game/IO/Serialization/Converters/Vector2Converter.cs index 5f21018fd5..87fbd31d21 100644 --- a/osu.Game/IO/Serialization/Converters/Vector2Converter.cs +++ b/osu.Game/IO/Serialization/Converters/Vector2Converter.cs @@ -18,7 +18,7 @@ namespace osu.Game.IO.Serialization.Converters public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { var obj = JObject.Load(reader); - return new Vector2((float)obj["X"], (float)obj["Y"]); + return new Vector2((float)obj["x"], (float)obj["y"]); } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) @@ -27,9 +27,9 @@ namespace osu.Game.IO.Serialization.Converters writer.WriteStartObject(); - writer.WritePropertyName("X"); + writer.WritePropertyName("x"); writer.WriteValue(vector.X); - writer.WritePropertyName("Y"); + writer.WritePropertyName("y"); writer.WriteValue(vector.Y); writer.WriteEndObject(); diff --git a/osu.Game/IO/Serialization/IJsonSerializable.cs b/osu.Game/IO/Serialization/IJsonSerializable.cs index 38e7f47656..892c266fe3 100644 --- a/osu.Game/IO/Serialization/IJsonSerializable.cs +++ b/osu.Game/IO/Serialization/IJsonSerializable.cs @@ -30,7 +30,8 @@ namespace osu.Game.IO.Serialization Formatting = Formatting.Indented, ObjectCreationHandling = ObjectCreationHandling.Replace, DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate, - Converters = new JsonConverter[] { new Vector2Converter() } + Converters = new JsonConverter[] { new Vector2Converter() }, + ContractResolver = new KeyContractResolver() }; } } diff --git a/osu.Game/IO/Serialization/KeyContractResolver.cs b/osu.Game/IO/Serialization/KeyContractResolver.cs new file mode 100644 index 0000000000..10375646ce --- /dev/null +++ b/osu.Game/IO/Serialization/KeyContractResolver.cs @@ -0,0 +1,16 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using Humanizer; +using Newtonsoft.Json.Serialization; + +namespace osu.Game.IO.Serialization +{ + public class KeyContractResolver : DefaultContractResolver + { + protected override string ResolvePropertyName(string propertyName) + { + return propertyName.Underscore(); + } + } +} diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 9e5d4291ce..a2d4a00110 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -272,6 +272,7 @@ + 20171019041408_InitialCreate.cs From f5f7658e906125fca54bc57532971d8d3cb74b36 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 7 Dec 2017 14:40:28 +0900 Subject: [PATCH 029/122] Don't serialize TotalBreakTime --- osu.Game/Beatmaps/Beatmap.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/Beatmap.cs b/osu.Game/Beatmaps/Beatmap.cs index c331872dda..e9342584cc 100644 --- a/osu.Game/Beatmaps/Beatmap.cs +++ b/osu.Game/Beatmaps/Beatmap.cs @@ -34,15 +34,16 @@ namespace osu.Game.Beatmaps [JsonIgnore] public BeatmapMetadata Metadata => BeatmapInfo?.Metadata ?? BeatmapInfo?.BeatmapSet?.Metadata; - [JsonConverter(typeof(TypedListConverter))] /// /// The HitObjects this Beatmap contains. /// + [JsonConverter(typeof(TypedListConverter))] public List HitObjects = new List(); /// /// Total amount of break time in the beatmap. /// + [JsonIgnore] public double TotalBreakTime => Breaks.Sum(b => b.Duration); /// From e573db04d43361caf21e14b5c7a601ec0df4ebd5 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 7 Dec 2017 14:42:36 +0900 Subject: [PATCH 030/122] Don't serialize HitObject.Kiai --- osu.Game/Rulesets/Objects/HitObject.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Objects/HitObject.cs b/osu.Game/Rulesets/Objects/HitObject.cs index 92220ff8bd..0772e7707e 100644 --- a/osu.Game/Rulesets/Objects/HitObject.cs +++ b/osu.Game/Rulesets/Objects/HitObject.cs @@ -1,6 +1,7 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using Newtonsoft.Json; using osu.Game.Audio; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; @@ -33,6 +34,7 @@ namespace osu.Game.Rulesets.Objects /// /// Whether this is in Kiai time. /// + [JsonIgnore] public bool Kiai { get; private set; } /// @@ -45,7 +47,7 @@ namespace osu.Game.Rulesets.Objects SoundControlPoint soundPoint = controlPointInfo.SoundPointAt(StartTime); EffectControlPoint effectPoint = controlPointInfo.EffectPointAt(StartTime); - Kiai |= effectPoint.KiaiMode; + Kiai = effectPoint.KiaiMode; // Initialize first sample Samples.ForEach(s => s.ControlPoint = soundPoint); From 0ba8988580a266343c1ab9ad42f0f5a85a7662d1 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 7 Dec 2017 15:32:39 +0900 Subject: [PATCH 031/122] Don't serialize Author + add SerializableAttributes --- osu.Game/Beatmaps/BeatmapInfo.cs | 1 + osu.Game/Beatmaps/BeatmapMetadata.cs | 3 +++ 2 files changed, 4 insertions(+) diff --git a/osu.Game/Beatmaps/BeatmapInfo.cs b/osu.Game/Beatmaps/BeatmapInfo.cs index 9450022a01..dd66812ea5 100644 --- a/osu.Game/Beatmaps/BeatmapInfo.cs +++ b/osu.Game/Beatmaps/BeatmapInfo.cs @@ -12,6 +12,7 @@ using osu.Game.Rulesets; namespace osu.Game.Beatmaps { + [Serializable] public class BeatmapInfo : IEquatable, IJsonSerializable, IHasPrimaryKey { [DatabaseGenerated(DatabaseGeneratedOption.Identity)] diff --git a/osu.Game/Beatmaps/BeatmapMetadata.cs b/osu.Game/Beatmaps/BeatmapMetadata.cs index 2efbcd4f15..67d6de49cd 100644 --- a/osu.Game/Beatmaps/BeatmapMetadata.cs +++ b/osu.Game/Beatmaps/BeatmapMetadata.cs @@ -1,6 +1,7 @@ // 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.ComponentModel.DataAnnotations.Schema; using System.Linq; @@ -9,6 +10,7 @@ using osu.Game.Users; namespace osu.Game.Beatmaps { + [Serializable] public class BeatmapMetadata { [DatabaseGenerated(DatabaseGeneratedOption.Identity)] @@ -51,6 +53,7 @@ namespace osu.Game.Beatmaps /// The author of the beatmaps in this set. /// public User Author; + public bool ShouldSerializeAuthor() => false; public string Source { get; set; } From 09f54b06ace0c82a3e500d18acd81e3737b475ff Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 7 Dec 2017 15:55:22 +0900 Subject: [PATCH 032/122] Just don't serialize Author altogether for now --- osu.Game/Beatmaps/BeatmapMetadata.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/BeatmapMetadata.cs b/osu.Game/Beatmaps/BeatmapMetadata.cs index 67d6de49cd..a9488ce0e2 100644 --- a/osu.Game/Beatmaps/BeatmapMetadata.cs +++ b/osu.Game/Beatmaps/BeatmapMetadata.cs @@ -52,8 +52,8 @@ namespace osu.Game.Beatmaps /// /// The author of the beatmaps in this set. /// + [JsonIgnore] public User Author; - public bool ShouldSerializeAuthor() => false; public string Source { get; set; } From bdf283a4e1b3d3a913beb6dfeb54e78d050d13de Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 7 Dec 2017 15:55:38 +0900 Subject: [PATCH 033/122] A bit more cleanup --- osu.Game/IO/Serialization/Converters/TypedListConverter.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/osu.Game/IO/Serialization/Converters/TypedListConverter.cs b/osu.Game/IO/Serialization/Converters/TypedListConverter.cs index 7147f9110e..b218f76b53 100644 --- a/osu.Game/IO/Serialization/Converters/TypedListConverter.cs +++ b/osu.Game/IO/Serialization/Converters/TypedListConverter.cs @@ -43,9 +43,7 @@ namespace osu.Game.IO.Serialization.Converters var list = new List(); var obj = JObject.Load(reader); - - var lookupTable = new List(); - serializer.Populate(obj["lookup_table"].CreateReader(), lookupTable); + var lookupTable = serializer.Deserialize>(obj["lookup_table"].CreateReader()); foreach (var tok in obj["items"]) { From 43c270ea49559e2a8515d91dfbccddcf5d3f6a18 Mon Sep 17 00:00:00 2001 From: FreezyLemon Date: Thu, 7 Dec 2017 21:18:51 +0100 Subject: [PATCH 034/122] Rolled back the bad earlier implementation --- .../Objects/Drawables/DrawableHitStrong.cs | 11 ----- .../Drawables/DrawableTaikoHitObject.cs | 2 - .../UI/TaikoRulesetContainer.cs | 48 +------------------ .../Objects/Drawables/DrawableHitObject.cs | 4 +- 4 files changed, 2 insertions(+), 63 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHitStrong.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHitStrong.cs index eced24a8da..c07eaf4d8b 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHitStrong.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHitStrong.cs @@ -16,8 +16,6 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables /// private const double second_hit_window = 30; - protected override bool PlaysSamples => true; - private double firstHitTime; private bool firstKeyHeld; private TaikoAction firstHitAction; @@ -55,15 +53,6 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables return base.OnReleased(action); } - protected override void LoadComplete() - { - base.LoadComplete(); - - if (Samples.Count > 1) - // Removes the "normal" hitsound, leaving only the hitfinish one - Samples.RemoveAt(0); - } - public override bool OnPressed(TaikoAction action) { if (AllJudged) diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs index 8ebfaaea38..7976cbbbc1 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs @@ -14,8 +14,6 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables { public override Vector2 OriginPosition => new Vector2(DrawHeight / 2); - protected override bool PlaysSamples => false; - protected readonly Vector2 BaseSize; protected readonly TaikoPiece MainPiece; diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs b/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs index f72d253a73..48ee0a5b42 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs @@ -2,11 +2,8 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using osu.Framework.Allocation; -using osu.Framework.Audio; using osu.Framework.Graphics; -using osu.Framework.Input.Bindings; using osu.Game.Beatmaps; -using osu.Game.Input; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Replays; @@ -18,45 +15,21 @@ using osu.Game.Rulesets.Taiko.Scoring; using osu.Game.Rulesets.UI; using osu.Game.Rulesets.Taiko.Replays; using OpenTK; -using OpenTK.Input; using System.Linq; using osu.Framework.Input; -using System.Collections.Generic; namespace osu.Game.Rulesets.Taiko.UI { public class TaikoRulesetContainer : ScrollingRulesetContainer { - private readonly HashSet centreKeys = new HashSet(); - private readonly HashSet rimKeys = new HashSet(); - private AudioManager audio; - private IEnumerable keyBindings; - public TaikoRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap, bool isForCurrentRuleset) : base(ruleset, beatmap, isForCurrentRuleset) { } [BackgroundDependencyLoader] - private void load(AudioManager audio, KeyBindingStore store) + private void load() { - keyBindings = store.Query(Ruleset.RulesetInfo.ID, Ruleset.AvailableVariants?.First() ?? 0).Cast(); - if (keyBindings.Count() == 0) - keyBindings = Ruleset.GetDefaultKeyBindings(); - - foreach (var kb in keyBindings) - { - var key = (Key)(kb.KeyCombination.Keys as InputKey[]).First(); - var action = kb.GetAction(); - - if (action == TaikoAction.LeftCentre || action == TaikoAction.RightCentre) - centreKeys.Add(key); - - if (action == TaikoAction.LeftRim || action == TaikoAction.RightRim) - rimKeys.Add(key); - } - - this.audio = audio; loadBarLines(); } @@ -104,25 +77,6 @@ namespace osu.Game.Rulesets.Taiko.UI } } - protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) - { - if (!args.Repeat) - { - var sampleBank = Beatmap.ControlPointInfo.SoundPointAt(WorkingBeatmap.Track.CurrentTime).SampleBank ?? "normal"; - string sampleName = ""; - - if (centreKeys.Contains(args.Key)) - sampleName = "hitnormal"; - - else if (rimKeys.Contains(args.Key)) - sampleName = "hitclap"; - - audio.Sample.Get($"Gameplay/{sampleBank}-{sampleName}")?.Play(); - } - - return base.OnKeyDown(state, args); - } - protected override Vector2 GetPlayfieldAspectAdjust() { const float default_relative_height = TaikoPlayfield.DEFAULT_HEIGHT / 768; diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index 12f4fc4f31..0a9de15586 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -59,8 +59,6 @@ namespace osu.Game.Rulesets.Objects.Drawables private readonly List judgements = new List(); public IReadOnlyList Judgements => judgements; - // Override in inheriting classes to prevent from playing samples on hit - protected virtual bool PlaysSamples => true; protected List Samples = new List(); @@ -95,7 +93,7 @@ namespace osu.Game.Rulesets.Objects.Drawables { UpdateState(state); - if (State == ArmedState.Hit && PlaysSamples) + if (State == ArmedState.Hit) PlaySamples(); }; From d2f3d5a80769eeae5932b2c4e42039430253e468 Mon Sep 17 00:00:00 2001 From: FreezyLemon Date: Thu, 7 Dec 2017 23:09:51 +0100 Subject: [PATCH 035/122] Added basic SampleInfo.FromSoundPoint and GetChannel methods --- osu.Game/Audio/SampleInfo.cs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/osu.Game/Audio/SampleInfo.cs b/osu.Game/Audio/SampleInfo.cs index 171a1bdf75..4a5d836c53 100644 --- a/osu.Game/Audio/SampleInfo.cs +++ b/osu.Game/Audio/SampleInfo.cs @@ -1,6 +1,11 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using osu.Framework.Audio; +using osu.Framework.Audio.Sample; +using osu.Framework.Configuration; +using osu.Game.Beatmaps.ControlPoints; + namespace osu.Game.Audio { public class SampleInfo @@ -10,6 +15,24 @@ namespace osu.Game.Audio public const string HIT_NORMAL = @"hitnormal"; public const string HIT_CLAP = @"hitclap"; + public static SampleInfo FromSoundPoint(SoundControlPoint soundPoint, string sampleName = SampleInfo.HIT_NORMAL) + { + return new SampleInfo() + { + Bank = soundPoint.SampleBank, + Name = sampleName, + Volume = soundPoint.SampleVolume, + }; + } + + public SampleChannel GetChannel(SampleManager manager) + { + var channel = manager.Get($"{Bank}-{Name}"); + + channel.AddAdjustment(AdjustableProperty.Volume, new BindableDouble(Volume / 100.0)); + return channel; + } + /// /// The bank to load the sample from. /// From 229c9b5b4ea4a2524b1fc4285bf86ce5d78ef2c5 Mon Sep 17 00:00:00 2001 From: FreezyLemon Date: Thu, 7 Dec 2017 23:11:34 +0100 Subject: [PATCH 036/122] First basic implementation of IKeyBindingHandler for the playfield so it can handle taiko hitsounds --- osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs | 33 +++++++++++++++++-- .../UI/TaikoRulesetContainer.cs | 2 +- 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs index ac3796f5b8..c4210dd261 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs @@ -16,10 +16,16 @@ using osu.Framework.Extensions.Color4Extensions; using System.Linq; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Taiko.Objects.Drawables; +using osu.Framework.Input.Bindings; +using osu.Game.Beatmaps.ControlPoints; +using osu.Framework.Audio; +using osu.Framework.Audio.Sample; +using System.Collections.Generic; +using osu.Game.Audio; namespace osu.Game.Rulesets.Taiko.UI { - public class TaikoPlayfield : ScrollingPlayfield + public class TaikoPlayfield : ScrollingPlayfield, IKeyBindingHandler { /// /// Default height of a when inside a . @@ -54,9 +60,14 @@ namespace osu.Game.Rulesets.Taiko.UI private readonly Box overlayBackground; private readonly Box background; - public TaikoPlayfield() + private ControlPointInfo controlPointInfo; + private IEnumerable allSamples; + private AudioManager audio; + + public TaikoPlayfield(ControlPointInfo controlPointInfo) : base(Axes.X) { + this.controlPointInfo = controlPointInfo; AddRangeInternal(new Drawable[] { backgroundContainer = new Container @@ -194,8 +205,15 @@ namespace osu.Game.Rulesets.Taiko.UI } [BackgroundDependencyLoader] - private void load(OsuColour colours) + private void load(OsuColour colours, AudioManager audio) { + this.audio = audio; + + foreach (var soundPoint in controlPointInfo.SoundPoints) + { + SampleInfo.FromSoundPoint(soundPoint).GetChannel(audio.Sample); + } + overlayBackgroundContainer.BorderColour = colours.Gray0; overlayBackground.Colour = colours.Gray1; @@ -258,5 +276,14 @@ namespace osu.Game.Rulesets.Taiko.UI kiaiExplosionContainer.Add(new KiaiHitExplosion(judgedObject, isRim)); } } + + public bool OnPressed(TaikoAction action) + { + var soundPoint = controlPointInfo.SoundPointAt(Time.Current); + + return true; + } + + public bool OnReleased(TaikoAction action) => false; } } diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs b/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs index 48ee0a5b42..614b446181 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs @@ -93,7 +93,7 @@ namespace osu.Game.Rulesets.Taiko.UI public override PassThroughInputManager CreateInputManager() => new TaikoInputManager(Ruleset.RulesetInfo); - protected override Playfield CreatePlayfield() => new TaikoPlayfield + protected override Playfield CreatePlayfield() => new TaikoPlayfield(Beatmap.ControlPointInfo) { Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft From 40e750f309eb8d9f61d4ee16d44c8d5fa5131931 Mon Sep 17 00:00:00 2001 From: FreezyLemon Date: Fri, 8 Dec 2017 08:32:16 +0100 Subject: [PATCH 037/122] Added sample preloading and playing --- osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs index c4210dd261..eda5c75906 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs @@ -22,6 +22,7 @@ using osu.Framework.Audio; using osu.Framework.Audio.Sample; using System.Collections.Generic; using osu.Game.Audio; +using System; namespace osu.Game.Rulesets.Taiko.UI { @@ -61,7 +62,7 @@ namespace osu.Game.Rulesets.Taiko.UI private readonly Box background; private ControlPointInfo controlPointInfo; - private IEnumerable allSamples; + private SortedDictionary> allSamples; private AudioManager audio; public TaikoPlayfield(ControlPointInfo controlPointInfo) @@ -211,7 +212,9 @@ namespace osu.Game.Rulesets.Taiko.UI foreach (var soundPoint in controlPointInfo.SoundPoints) { - SampleInfo.FromSoundPoint(soundPoint).GetChannel(audio.Sample); + var normalSample = SampleInfo.FromSoundPoint(soundPoint).GetChannel(audio.Sample); + var clapSample = SampleInfo.FromSoundPoint(soundPoint, SampleInfo.HIT_CLAP).GetChannel(audio.Sample); + allSamples.Add(soundPoint.Time, new Tuple(normalSample, clapSample)); } overlayBackgroundContainer.BorderColour = colours.Gray0; @@ -279,7 +282,13 @@ namespace osu.Game.Rulesets.Taiko.UI public bool OnPressed(TaikoAction action) { - var soundPoint = controlPointInfo.SoundPointAt(Time.Current); + if (!allSamples.TryGetValue(controlPointInfo.SoundPointAt(Clock.CurrentTime).Time, out Tuple samples)) + throw new InvalidOperationException("Current sample set not found."); + + if (action == TaikoAction.LeftCentre || action == TaikoAction.RightCentre) + samples.Item1.Play(); + else + samples.Item2.Play(); return true; } From 61a6a2919ef47d50ee0087d92618cd9da27c3a35 Mon Sep 17 00:00:00 2001 From: FreezyLemon Date: Fri, 8 Dec 2017 09:41:13 +0100 Subject: [PATCH 038/122] Fixed multiple critical bugs and changed allSamples to a normal Dictionary for faster access --- osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs | 8 ++++++-- osu.Game/Audio/SampleInfo.cs | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs index eda5c75906..394b683531 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs @@ -62,7 +62,7 @@ namespace osu.Game.Rulesets.Taiko.UI private readonly Box background; private ControlPointInfo controlPointInfo; - private SortedDictionary> allSamples; + private Dictionary> allSamples; private AudioManager audio; public TaikoPlayfield(ControlPointInfo controlPointInfo) @@ -210,6 +210,7 @@ namespace osu.Game.Rulesets.Taiko.UI { this.audio = audio; + allSamples = new Dictionary>(); foreach (var soundPoint in controlPointInfo.SoundPoints) { var normalSample = SampleInfo.FromSoundPoint(soundPoint).GetChannel(audio.Sample); @@ -282,7 +283,10 @@ namespace osu.Game.Rulesets.Taiko.UI public bool OnPressed(TaikoAction action) { - if (!allSamples.TryGetValue(controlPointInfo.SoundPointAt(Clock.CurrentTime).Time, out Tuple samples)) + var currentTime = Clock.CurrentTime; + var soundPoint = currentTime < controlPointInfo.SoundPoints[0].Time ? controlPointInfo.SoundPoints[0] : controlPointInfo.SoundPointAt(currentTime); + + if (!allSamples.TryGetValue(soundPoint.Time, out Tuple samples)) throw new InvalidOperationException("Current sample set not found."); if (action == TaikoAction.LeftCentre || action == TaikoAction.RightCentre) diff --git a/osu.Game/Audio/SampleInfo.cs b/osu.Game/Audio/SampleInfo.cs index 4a5d836c53..6ee8a7f296 100644 --- a/osu.Game/Audio/SampleInfo.cs +++ b/osu.Game/Audio/SampleInfo.cs @@ -27,7 +27,7 @@ namespace osu.Game.Audio public SampleChannel GetChannel(SampleManager manager) { - var channel = manager.Get($"{Bank}-{Name}"); + var channel = manager.Get($"Gameplay/{Bank}-{Name}"); channel.AddAdjustment(AdjustableProperty.Volume, new BindableDouble(Volume / 100.0)); return channel; From 9d3d9bcdc8efab16d62946dbb658416b555f3b02 Mon Sep 17 00:00:00 2001 From: FreezyLemon Date: Fri, 8 Dec 2017 09:42:10 +0100 Subject: [PATCH 039/122] Corrected the return values for taiko DrawableHit and DrawableHitStrong (OnPressed == true if new Judgement occurs and is a hit) --- osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs | 3 ++- osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHitStrong.cs | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs index 489eacf386..9d797b77b5 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs @@ -67,7 +67,8 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables { validKeyPressed = HitActions.Contains(action); - return UpdateJudgement(true); + // Only count this as handled if the new judgement is a hit + return UpdateJudgement(true) && Judgements.Last().IsHit; } protected override void Update() diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHitStrong.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHitStrong.cs index c07eaf4d8b..a6575df6d7 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHitStrong.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHitStrong.cs @@ -83,7 +83,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables return false; // Assume the intention was to hit the strong hit with both keys only if the first key is still being held down - return firstKeyHeld && UpdateJudgement(true); + return firstKeyHeld && Judgements.Last().IsHit; } } } From 4b3cf0773d0bffcc503755bccbca1a652491c8e1 Mon Sep 17 00:00:00 2001 From: FreezyLemon Date: Fri, 8 Dec 2017 09:52:58 +0100 Subject: [PATCH 040/122] Various CI adjustments --- osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs | 5 +---- osu.Game/Audio/SampleInfo.cs | 4 ++-- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs index 394b683531..549c59cba1 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs @@ -61,9 +61,8 @@ namespace osu.Game.Rulesets.Taiko.UI private readonly Box overlayBackground; private readonly Box background; - private ControlPointInfo controlPointInfo; + private readonly ControlPointInfo controlPointInfo; private Dictionary> allSamples; - private AudioManager audio; public TaikoPlayfield(ControlPointInfo controlPointInfo) : base(Axes.X) @@ -208,8 +207,6 @@ namespace osu.Game.Rulesets.Taiko.UI [BackgroundDependencyLoader] private void load(OsuColour colours, AudioManager audio) { - this.audio = audio; - allSamples = new Dictionary>(); foreach (var soundPoint in controlPointInfo.SoundPoints) { diff --git a/osu.Game/Audio/SampleInfo.cs b/osu.Game/Audio/SampleInfo.cs index 6ee8a7f296..d3fc1d4932 100644 --- a/osu.Game/Audio/SampleInfo.cs +++ b/osu.Game/Audio/SampleInfo.cs @@ -15,9 +15,9 @@ namespace osu.Game.Audio public const string HIT_NORMAL = @"hitnormal"; public const string HIT_CLAP = @"hitclap"; - public static SampleInfo FromSoundPoint(SoundControlPoint soundPoint, string sampleName = SampleInfo.HIT_NORMAL) + public static SampleInfo FromSoundPoint(SoundControlPoint soundPoint, string sampleName = HIT_NORMAL) { - return new SampleInfo() + return new SampleInfo { Bank = soundPoint.SampleBank, Name = sampleName, From f6552da406e7f0c56d2e84fcf7e310ee33e62853 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 21 Dec 2017 13:44:18 +0900 Subject: [PATCH 041/122] Update framework --- osu-framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu-framework b/osu-framework index 9cd6968a8c..28fbd0711c 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 9cd6968a8c4d27415808f5e770d24fec5a44485f +Subproject commit 28fbd0711c09d3b06b51fc728b025f83ded2f0f8 From bfa4f1a2c3ad203ef377d165091ce73bced1de68 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 21 Dec 2017 13:59:03 +0900 Subject: [PATCH 042/122] Apply changes in line with master changes --- .../Beatmaps/Formats/OsuJsonDecoderTest.cs | 4 ++-- osu.Game/Beatmaps/Formats/OsuJsonDecoder.cs | 23 +++++++++---------- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs index 5a66a7047d..7886383725 100644 --- a/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs @@ -158,8 +158,8 @@ namespace osu.Game.Tests.Beatmaps.Formats using (var stream = Resource.OpenResource(filename)) using (var sr = new StreamReader(stream)) { - var legacyDecoded = new OsuLegacyDecoder().Decode(sr); + var legacyDecoded = new LegacyBeatmapDecoder().DecodeBeatmap(sr); using (var ms = new MemoryStream()) using (var sw = new StreamWriter(ms)) using (var sr2 = new StreamReader(ms)) @@ -168,7 +168,7 @@ namespace osu.Game.Tests.Beatmaps.Formats sw.Flush(); ms.Position = 0; - return (legacyDecoded, new OsuJsonDecoder().Decode(sr2)); + return (legacyDecoded, new OsuJsonDecoder().DecodeBeatmap(sr2)); } } } diff --git a/osu.Game/Beatmaps/Formats/OsuJsonDecoder.cs b/osu.Game/Beatmaps/Formats/OsuJsonDecoder.cs index d00cbbb8fb..e2d7414013 100644 --- a/osu.Game/Beatmaps/Formats/OsuJsonDecoder.cs +++ b/osu.Game/Beatmaps/Formats/OsuJsonDecoder.cs @@ -3,34 +3,33 @@ using System.IO; using osu.Game.IO.Serialization; +using osu.Game.Storyboards; namespace osu.Game.Beatmaps.Formats { - public class OsuJsonDecoder : BeatmapDecoder + public class OsuJsonDecoder : Decoder { public static void Register() { AddDecoder("{"); } - protected override void ParseFile(StreamReader stream, Beatmap beatmap) + public override Decoder GetStoryboardDecoder() => this; + + protected override void ParseBeatmap(StreamReader stream, Beatmap beatmap) { stream.BaseStream.Position = 0; stream.DiscardBufferedData(); - try - { - string fullText = stream.ReadToEnd(); - fullText.DeserializeInto(beatmap); - } - catch - { - // Temporary because storyboards are deserialized into beatmaps at the moment - // This try-catch shouldn't exist in the future - } + stream.ReadToEnd().DeserializeInto(beatmap); foreach (var hitObject in beatmap.HitObjects) hitObject.ApplyDefaults(beatmap.ControlPointInfo, beatmap.BeatmapInfo.BaseDifficulty); } + + protected override void ParseStoryboard(StreamReader stream, Storyboard storyboard) + { + // throw new System.NotImplementedException(); + } } } From e8e5e8270bbf244719866f0af6bd26862344eb78 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 21 Dec 2017 14:19:25 +0900 Subject: [PATCH 043/122] Rename decoder --- osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs | 6 +++--- .../Formats/{OsuJsonDecoder.cs => JsonBeatmapDecoder.cs} | 4 ++-- osu.Game/osu.Game.csproj | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) rename osu.Game/Beatmaps/Formats/{OsuJsonDecoder.cs => JsonBeatmapDecoder.cs} (88%) diff --git a/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs index 7886383725..8fd7645287 100644 --- a/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs @@ -141,7 +141,7 @@ namespace osu.Game.Tests.Beatmaps.Formats /// /// Reads a .osu file first with a , serializes the resulting to JSON - /// and then deserializes the result back into a through an . + /// and then deserializes the result back into a through an . /// /// The .osu file to decode. /// The after being decoded by an . @@ -149,7 +149,7 @@ namespace osu.Game.Tests.Beatmaps.Formats /// /// Reads a .osu file first with a , serializes the resulting to JSON - /// and then deserializes the result back into a through an . + /// and then deserializes the result back into a through an . /// /// The .osu file to decode. /// The after being decoded by an . @@ -168,7 +168,7 @@ namespace osu.Game.Tests.Beatmaps.Formats sw.Flush(); ms.Position = 0; - return (legacyDecoded, new OsuJsonDecoder().DecodeBeatmap(sr2)); + return (legacyDecoded, new JsonBeatmapDecoder().DecodeBeatmap(sr2)); } } } diff --git a/osu.Game/Beatmaps/Formats/OsuJsonDecoder.cs b/osu.Game/Beatmaps/Formats/JsonBeatmapDecoder.cs similarity index 88% rename from osu.Game/Beatmaps/Formats/OsuJsonDecoder.cs rename to osu.Game/Beatmaps/Formats/JsonBeatmapDecoder.cs index e2d7414013..ce6037b43e 100644 --- a/osu.Game/Beatmaps/Formats/OsuJsonDecoder.cs +++ b/osu.Game/Beatmaps/Formats/JsonBeatmapDecoder.cs @@ -7,11 +7,11 @@ using osu.Game.Storyboards; namespace osu.Game.Beatmaps.Formats { - public class OsuJsonDecoder : Decoder + public class JsonBeatmapDecoder : Decoder { public static void Register() { - AddDecoder("{"); + AddDecoder("{"); } public override Decoder GetStoryboardDecoder() => this; diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 5440cdc8f4..223dd77b04 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -263,7 +263,7 @@ - + From 22f8853f49de80e604e25c3684061a23cbe68e1b Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 21 Dec 2017 14:44:51 +0900 Subject: [PATCH 044/122] Serialize star difficulty for now --- osu.Game/Beatmaps/BeatmapInfo.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Beatmaps/BeatmapInfo.cs b/osu.Game/Beatmaps/BeatmapInfo.cs index 8139aff6ef..1da3dc8a54 100644 --- a/osu.Game/Beatmaps/BeatmapInfo.cs +++ b/osu.Game/Beatmaps/BeatmapInfo.cs @@ -123,7 +123,6 @@ namespace osu.Game.Beatmaps [JsonProperty("difficulty_rating")] public double StarDifficulty { get; set; } - public bool ShouldSerializeStarDifficulty() => false; public override string ToString() => $"{Metadata} [{Version}]"; From 58859f2ffb12b62396a7e909f2c22ed457fa994f Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 21 Dec 2017 15:34:00 +0900 Subject: [PATCH 045/122] Rework registration/instantiation of decoders to not rely on reflection --- osu.Game/Beatmaps/Formats/Decoder.cs | 16 +++++++------ .../Beatmaps/Formats/JsonBeatmapDecoder.cs | 2 +- osu.Game/Beatmaps/Formats/LegacyDecoder.cs | 24 +++++++++---------- 3 files changed, 22 insertions(+), 20 deletions(-) diff --git a/osu.Game/Beatmaps/Formats/Decoder.cs b/osu.Game/Beatmaps/Formats/Decoder.cs index e157150651..a6e2699262 100644 --- a/osu.Game/Beatmaps/Formats/Decoder.cs +++ b/osu.Game/Beatmaps/Formats/Decoder.cs @@ -10,11 +10,12 @@ namespace osu.Game.Beatmaps.Formats { public abstract class Decoder { - private static readonly Dictionary decoders = new Dictionary(); + private static readonly Dictionary> decoders = new Dictionary>(); static Decoder() { LegacyDecoder.Register(); + JsonBeatmapDecoder.Register(); } /// @@ -33,17 +34,18 @@ namespace osu.Game.Beatmaps.Formats if (line == null || !decoders.ContainsKey(line)) throw new IOException(@"Unknown file format"); - return (Decoder)Activator.CreateInstance(decoders[line], line); + + return decoders[line](line); } /// - /// Adds the to the list of and decoder. + /// Registers an instantiation function for a . /// - /// Type to decode a with. - /// A string representation of the version. - protected static void AddDecoder(string version) where T : Decoder + /// A string in the file which triggers this decoder to be used. + /// A function which constructs the given . + protected static void AddDecoder(string magic, Func constructor) { - decoders[version] = typeof(T); + decoders[magic] = constructor; } /// diff --git a/osu.Game/Beatmaps/Formats/JsonBeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/JsonBeatmapDecoder.cs index ce6037b43e..29e7cee336 100644 --- a/osu.Game/Beatmaps/Formats/JsonBeatmapDecoder.cs +++ b/osu.Game/Beatmaps/Formats/JsonBeatmapDecoder.cs @@ -11,7 +11,7 @@ namespace osu.Game.Beatmaps.Formats { public static void Register() { - AddDecoder("{"); + AddDecoder("{", m => new JsonBeatmapDecoder()); } public override Decoder GetStoryboardDecoder() => this; diff --git a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs index 96747a870d..e5ced5f772 100644 --- a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs @@ -13,18 +13,18 @@ namespace osu.Game.Beatmaps.Formats { public static void Register() { - AddDecoder(@"osu file format v14"); - AddDecoder(@"osu file format v13"); - AddDecoder(@"osu file format v12"); - AddDecoder(@"osu file format v11"); - AddDecoder(@"osu file format v10"); - AddDecoder(@"osu file format v9"); - AddDecoder(@"osu file format v8"); - AddDecoder(@"osu file format v7"); - AddDecoder(@"osu file format v6"); - AddDecoder(@"osu file format v5"); - AddDecoder(@"osu file format v4"); - AddDecoder(@"osu file format v3"); + AddDecoder(@"osu file format v14", m => new LegacyBeatmapDecoder(m)); + AddDecoder(@"osu file format v13", m => new LegacyBeatmapDecoder(m)); + AddDecoder(@"osu file format v12", m => new LegacyBeatmapDecoder(m)); + AddDecoder(@"osu file format v11", m => new LegacyBeatmapDecoder(m)); + AddDecoder(@"osu file format v10", m => new LegacyBeatmapDecoder(m)); + AddDecoder(@"osu file format v9", m => new LegacyBeatmapDecoder(m)); + AddDecoder(@"osu file format v8", m => new LegacyBeatmapDecoder(m)); + AddDecoder(@"osu file format v7", m => new LegacyBeatmapDecoder(m)); + AddDecoder(@"osu file format v6", m => new LegacyBeatmapDecoder(m)); + AddDecoder(@"osu file format v5", m => new LegacyBeatmapDecoder(m)); + AddDecoder(@"osu file format v4", m => new LegacyBeatmapDecoder(m)); + AddDecoder(@"osu file format v3", m => new LegacyBeatmapDecoder(m)); // TODO: differences between versions } From cb7e192aff65d73fba3f8c762f1a3df4b14fbed0 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 21 Dec 2017 16:02:33 +0900 Subject: [PATCH 046/122] Determine SampleInfo defaults in DrawableHitObject --- .../Objects/JuiceStream.cs | 8 ++++++ osu.Game.Rulesets.Mania/Objects/HoldNote.cs | 14 ++++++++-- .../Objects/Drawables/DrawableSlider.cs | 1 + osu.Game.Rulesets.Osu/Objects/Slider.cs | 19 +++++++++++-- osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs | 14 +++++++--- osu.Game/Audio/SampleInfo.cs | 27 +++---------------- .../ControlPoints/SoundControlPoint.cs | 6 +++-- .../Objects/Drawables/DrawableHitObject.cs | 15 +++++++++-- osu.Game/Rulesets/Objects/HitObject.cs | 11 +++----- 9 files changed, 73 insertions(+), 42 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs index bf9f0bd44b..4de8cd897f 100644 --- a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs +++ b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs @@ -12,6 +12,7 @@ using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Types; using OpenTK; using osu.Framework.Lists; +using osu.Framework.Extensions.IEnumerableExtensions; namespace osu.Game.Rulesets.Catch.Objects { @@ -29,9 +30,14 @@ namespace osu.Game.Rulesets.Catch.Objects public double Velocity; public double TickDistance; + private ControlPointInfo controlPointInfo; + private BeatmapDifficulty difficulty; + public override void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) { base.ApplyDefaults(controlPointInfo, difficulty); + this.controlPointInfo = controlPointInfo; + this.difficulty = difficulty; TimingControlPoint timingPoint = controlPointInfo.TimingPointAt(StartTime); DifficultyControlPoint difficultyPoint = controlPointInfo.DifficultyPointAt(StartTime); @@ -124,6 +130,8 @@ namespace osu.Game.Rulesets.Catch.Objects }); } + ticks.ForEach(t => t.ApplyDefaults(controlPointInfo, difficulty)); + return ticks; } } diff --git a/osu.Game.Rulesets.Mania/Objects/HoldNote.cs b/osu.Game.Rulesets.Mania/Objects/HoldNote.cs index fc1331551e..2b68dcf62c 100644 --- a/osu.Game.Rulesets.Mania/Objects/HoldNote.cs +++ b/osu.Game.Rulesets.Mania/Objects/HoldNote.cs @@ -63,10 +63,16 @@ namespace osu.Game.Rulesets.Mania.Objects /// private double tickSpacing = 50; + private ControlPointInfo controlPointInfo; + private BeatmapDifficulty difficulty; + public override void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) { base.ApplyDefaults(controlPointInfo, difficulty); + this.controlPointInfo = controlPointInfo; + this.difficulty = difficulty; + TimingControlPoint timingPoint = controlPointInfo.TimingPointAt(StartTime); tickSpacing = timingPoint.BeatLength / difficulty.SliderTickRate; @@ -89,11 +95,15 @@ namespace osu.Game.Rulesets.Mania.Objects for (double t = StartTime + tickSpacing; t <= EndTime - tickSpacing; t += tickSpacing) { - ret.Add(new HoldNoteTick + var tick = new HoldNoteTick { StartTime = t, Column = Column - }); + }; + + tick.ApplyDefaults(controlPointInfo, difficulty); + + ret.Add(tick); } return ret; diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs index 42f54af801..a91d846aa7 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs @@ -57,6 +57,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables Scale = s.Scale, ComboColour = s.ComboColour, Samples = s.Samples, + SoundControlPoint = s.SoundControlPoint }) }; diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs index 39ec753fe1..ec1b146328 100644 --- a/osu.Game.Rulesets.Osu/Objects/Slider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs @@ -10,6 +10,7 @@ using System.Linq; using osu.Game.Audio; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; +using osu.Framework.Extensions.IEnumerableExtensions; namespace osu.Game.Rulesets.Osu.Objects { @@ -74,10 +75,16 @@ namespace osu.Game.Rulesets.Osu.Objects public double Velocity; public double TickDistance; + private ControlPointInfo controlPointInfo; + private BeatmapDifficulty difficulty; + public override void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) { base.ApplyDefaults(controlPointInfo, difficulty); + this.controlPointInfo = controlPointInfo; + this.difficulty = difficulty; + TimingControlPoint timingPoint = controlPointInfo.TimingPointAt(StartTime); DifficultyControlPoint difficultyPoint = controlPointInfo.DifficultyPointAt(StartTime); @@ -124,7 +131,7 @@ namespace osu.Game.Rulesets.Osu.Objects var distanceProgress = d / length; var timeProgress = reversed ? 1 - distanceProgress : distanceProgress; - yield return new SliderTick + var ret = new SliderTick { RepeatIndex = repeat, StartTime = repeatStartTime + timeProgress * repeatDuration, @@ -139,6 +146,10 @@ namespace osu.Game.Rulesets.Osu.Objects Volume = s.Volume })) }; + + ret.ApplyDefaults(controlPointInfo, difficulty); + + yield return ret; } } } @@ -158,7 +169,7 @@ namespace osu.Game.Rulesets.Osu.Objects var repeatStartTime = StartTime + repeat * repeatDuration; var distanceProgress = d / length; - yield return new RepeatPoint + var ret = new RepeatPoint { RepeatIndex = repeat, StartTime = repeatStartTime, @@ -167,6 +178,10 @@ namespace osu.Game.Rulesets.Osu.Objects Scale = Scale, ComboColour = ComboColour, }; + + ret.ApplyDefaults(controlPointInfo, difficulty); + + yield return ret; } } } diff --git a/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs b/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs index 526d23f51a..a2503b8060 100644 --- a/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs +++ b/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs @@ -55,9 +55,14 @@ namespace osu.Game.Rulesets.Taiko.Objects /// private double tickSpacing = 100; + private ControlPointInfo controlPointInfo; + private BeatmapDifficulty difficulty; + public override void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) { base.ApplyDefaults(controlPointInfo, difficulty); + this.controlPointInfo = controlPointInfo; + this.difficulty = difficulty; TimingControlPoint timingPoint = controlPointInfo.TimingPointAt(StartTime); @@ -77,7 +82,7 @@ namespace osu.Game.Rulesets.Taiko.Objects bool first = true; for (double t = StartTime; t < EndTime + tickSpacing / 2; t += tickSpacing) { - ret.Add(new DrumRollTick + var tick = new DrumRollTick { FirstTick = first, TickSpacing = tickSpacing, @@ -89,12 +94,15 @@ namespace osu.Game.Rulesets.Taiko.Objects Name = @"slidertick", Volume = s.Volume })) - }); + }; + tick.ApplyDefaults(controlPointInfo, difficulty); + + ret.Add(tick); first = false; } return ret; } } -} \ No newline at end of file +} diff --git a/osu.Game/Audio/SampleInfo.cs b/osu.Game/Audio/SampleInfo.cs index 3c3a64dbb2..2cde4e01ad 100644 --- a/osu.Game/Audio/SampleInfo.cs +++ b/osu.Game/Audio/SampleInfo.cs @@ -15,40 +15,19 @@ namespace osu.Game.Audio public const string HIT_NORMAL = @"hitnormal"; public const string HIT_CLAP = @"hitclap"; - /// - /// The that is used for and - /// if the values have not already been provided by the hitobject. - /// - [JsonIgnore] - public SoundControlPoint ControlPoint; - - private string bank; /// /// The bank to load the sample from. /// - public string Bank - { - get { return string.IsNullOrEmpty(bank) ? (ControlPoint?.SampleBank ?? "normal") : bank; } - set { bank = value; } - } - - public bool ShouldSerializeBank() => Bank != ControlPoint.SampleBank; + public string Bank; /// /// The name of the sample to load. /// - public string Name { get; set; } + public string Name; - private int volume; /// /// The sample volume. /// - public int Volume - { - get { return volume == 0 ? (ControlPoint?.SampleVolume ?? 0) : volume; } - set { volume = value; } - } - - public bool ShouldSerializeVolume() => Volume != ControlPoint.SampleVolume; + public int Volume; } } diff --git a/osu.Game/Beatmaps/ControlPoints/SoundControlPoint.cs b/osu.Game/Beatmaps/ControlPoints/SoundControlPoint.cs index 8084229382..b73a03b95a 100644 --- a/osu.Game/Beatmaps/ControlPoints/SoundControlPoint.cs +++ b/osu.Game/Beatmaps/ControlPoints/SoundControlPoint.cs @@ -5,14 +5,16 @@ namespace osu.Game.Beatmaps.ControlPoints { public class SoundControlPoint : ControlPoint { + public const string DEFAULT_BANK = "normal"; + /// /// The default sample bank at this control point. /// - public string SampleBank; + public string SampleBank = DEFAULT_BANK; /// /// The default sample volume at this control point. /// public int SampleVolume; } -} \ No newline at end of file +} diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index 57db36fda5..4f5f8898f8 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -86,12 +86,23 @@ namespace osu.Game.Rulesets.Objects.Drawables { foreach (SampleInfo sample in HitObject.Samples) { - SampleChannel channel = audio.Sample.Get($@"Gameplay/{sample.Bank}-{sample.Name}"); + if (HitObject.SoundControlPoint == null) + throw new ArgumentNullException(nameof(HitObject.SoundControlPoint), $"{nameof(HitObject)} must always have an attached {nameof(HitObject.SoundControlPoint)}."); + + var bank = sample.Bank; + if (string.IsNullOrEmpty(bank)) + bank = HitObject.SoundControlPoint.SampleBank; + + int volume = sample.Volume; + if (volume == 0) + volume = HitObject.SoundControlPoint.SampleVolume; + + SampleChannel channel = audio.Sample.Get($@"Gameplay/{bank}-{sample.Name}"); if (channel == null) continue; - channel.Volume.Value = sample.Volume; + channel.Volume.Value = volume; Samples.Add(channel); } } diff --git a/osu.Game/Rulesets/Objects/HitObject.cs b/osu.Game/Rulesets/Objects/HitObject.cs index 0772e7707e..66e34eac32 100644 --- a/osu.Game/Rulesets/Objects/HitObject.cs +++ b/osu.Game/Rulesets/Objects/HitObject.cs @@ -31,6 +31,9 @@ namespace osu.Game.Rulesets.Objects /// public SampleInfoList Samples = new SampleInfoList(); + [JsonIgnore] + public SoundControlPoint SoundControlPoint; + /// /// Whether this is in Kiai time. /// @@ -48,13 +51,7 @@ namespace osu.Game.Rulesets.Objects EffectControlPoint effectPoint = controlPointInfo.EffectPointAt(StartTime); Kiai = effectPoint.KiaiMode; - - // Initialize first sample - Samples.ForEach(s => s.ControlPoint = soundPoint); - - // Initialize any repeat samples - var repeatData = this as IHasRepeats; - repeatData?.RepeatSamples?.ForEach(r => r.ForEach(s => s.ControlPoint = soundPoint)); + SoundControlPoint = soundPoint; } } } From a3fcc0b60cb4c7113b0195c846a2008165836651 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 21 Dec 2017 19:40:41 +0900 Subject: [PATCH 047/122] Back to using SortedLists --- osu-framework | 2 +- .../UI/ManiaRulesetContainer.cs | 2 +- osu.Game.Rulesets.Osu/Objects/Slider.cs | 1 - .../Beatmaps/Formats/OsuJsonDecoderTest.cs | 8 ++++---- .../Visual/TestCaseBeatSyncedContainer.cs | 4 ++-- osu.Game/Audio/SampleInfo.cs | 2 -- .../ControlPoints/ControlPointInfo.cs | 19 ++++++++++--------- 7 files changed, 18 insertions(+), 20 deletions(-) diff --git a/osu-framework b/osu-framework index 28fbd0711c..d997b34da4 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 28fbd0711c09d3b06b51fc728b025f83ded2f0f8 +Subproject commit d997b34da4556e4fcfc2de5413ded92c6ee9bec1 diff --git a/osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs b/osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs index 83306187bd..61446a31b6 100644 --- a/osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs +++ b/osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs @@ -43,7 +43,7 @@ namespace osu.Game.Rulesets.Mania.UI // Generate the bar lines double lastObjectTime = (Objects.LastOrDefault() as IHasEndTime)?.EndTime ?? Objects.LastOrDefault()?.StartTime ?? double.MaxValue; - List timingPoints = Beatmap.ControlPointInfo.TimingPoints; + var timingPoints = Beatmap.ControlPointInfo.TimingPoints; var barLines = new List(); for (int i = 0; i < timingPoints.Count; i++) diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs index ec1b146328..5449466f2e 100644 --- a/osu.Game.Rulesets.Osu/Objects/Slider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs @@ -10,7 +10,6 @@ using System.Linq; using osu.Game.Audio; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; -using osu.Framework.Extensions.IEnumerableExtensions; namespace osu.Game.Rulesets.Osu.Objects { diff --git a/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs index 8fd7645287..7143550ee2 100644 --- a/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs @@ -140,19 +140,19 @@ namespace osu.Game.Tests.Beatmaps.Formats } /// - /// Reads a .osu file first with a , serializes the resulting to JSON + /// Reads a .osu file first with a , serializes the resulting to JSON /// and then deserializes the result back into a through an . /// /// The .osu file to decode. - /// The after being decoded by an . + /// The after being decoded by an . private Beatmap decodeAsJson(string filename) => decode(filename).jsonDecoded; /// - /// Reads a .osu file first with a , serializes the resulting to JSON + /// Reads a .osu file first with a , serializes the resulting to JSON /// and then deserializes the result back into a through an . /// /// The .osu file to decode. - /// The after being decoded by an . + /// The after being decoded by an . private (Beatmap legacyDecoded, Beatmap jsonDecoded) decode(string filename) { using (var stream = Resource.OpenResource(filename)) diff --git a/osu.Game.Tests/Visual/TestCaseBeatSyncedContainer.cs b/osu.Game.Tests/Visual/TestCaseBeatSyncedContainer.cs index d99485f3a2..771148827d 100644 --- a/osu.Game.Tests/Visual/TestCaseBeatSyncedContainer.cs +++ b/osu.Game.Tests/Visual/TestCaseBeatSyncedContainer.cs @@ -2,7 +2,6 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; -using System.Collections.Generic; using osu.Framework.Audio.Track; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; @@ -14,6 +13,7 @@ using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Overlays; using OpenTK.Graphics; +using osu.Framework.Lists; namespace osu.Game.Tests.Visual { @@ -137,7 +137,7 @@ namespace osu.Game.Tests.Visual }; } - private List timingPoints => Beatmap.Value.Beatmap.ControlPointInfo.TimingPoints; + private SortedList timingPoints => Beatmap.Value.Beatmap.ControlPointInfo.TimingPoints; private TimingControlPoint getNextTimingPoint(TimingControlPoint current) { if (timingPoints[timingPoints.Count - 1] == current) diff --git a/osu.Game/Audio/SampleInfo.cs b/osu.Game/Audio/SampleInfo.cs index 2cde4e01ad..8242ee14df 100644 --- a/osu.Game/Audio/SampleInfo.cs +++ b/osu.Game/Audio/SampleInfo.cs @@ -2,8 +2,6 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; -using Newtonsoft.Json; -using osu.Game.Beatmaps.ControlPoints; namespace osu.Game.Audio { diff --git a/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs b/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs index 652ae42979..64b9b837b6 100644 --- a/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs +++ b/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs @@ -5,35 +5,36 @@ using System; using System.Collections.Generic; using System.Linq; using Newtonsoft.Json; +using osu.Framework.Lists; namespace osu.Game.Beatmaps.ControlPoints { [Serializable] public class ControlPointInfo { - [JsonProperty] /// /// All timing points. /// - public List TimingPoints { get; private set; } = new List(); - [JsonProperty] + public SortedList TimingPoints { get; private set; } = new SortedList(Comparer.Default); + /// /// All difficulty points. /// - public List DifficultyPoints { get; private set; } = new List(); - [JsonProperty] + public SortedList DifficultyPoints { get; private set; } = new SortedList(Comparer.Default); + /// /// All sound points. /// - public List SoundPoints { get; private set; } = new List(); - [JsonProperty] + public SortedList SoundPoints { get; private set; } = new SortedList(Comparer.Default); + /// /// All effect points. /// - public List EffectPoints { get; private set; } = new List(); + [JsonProperty] + public SortedList EffectPoints { get; private set; } = new SortedList(Comparer.Default); /// /// Finds the difficulty control point that is active at . @@ -91,7 +92,7 @@ namespace osu.Game.Beatmaps.ControlPoints /// The time to find the control point at. /// The control point to use when is before any control points. If null, a new control point will be constructed. /// The active control point at . - private T binarySearch(List list, double time, T prePoint = null) + private T binarySearch(SortedList list, double time, T prePoint = null) where T : ControlPoint, new() { if (list == null) From b2c0b013aa06b4d9bc0bf4c9f088764fc9f7f1f2 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 21 Dec 2017 19:56:12 +0900 Subject: [PATCH 048/122] Remove migration setting in favour of export option in the editor --- osu.Game/Beatmaps/BeatmapManager.cs | 70 ------------------- osu.Game/Beatmaps/WorkingBeatmap.cs | 15 ++++ .../Sections/Maintenance/GeneralSettings.cs | 12 ---- osu.Game/Screens/Edit/Editor.cs | 6 ++ 4 files changed, 21 insertions(+), 82 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 40f1545b77..ca1a056992 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -553,76 +553,6 @@ namespace osu.Game.Beatmaps return beatmapSet; } - public void UpdateContent(BeatmapInfo beatmapInfo, Stream newData) - { - var context = createContext(); - - using (var transaction = context.BeginTransaction()) - { - var setInfo = beatmapInfo.BeatmapSet; - var existingSetFileInfo = setInfo.Files.First(f => f.FileInfo.Hash == beatmapInfo.Hash); - var existingFileInfo = existingSetFileInfo.FileInfo; - - existingSetFileInfo.FileInfo = files.Add(newData); - files.Dereference(existingFileInfo); - - beatmapInfo.Hash = newData.ComputeSHA2Hash(); - beatmapInfo.MD5Hash = newData.ComputeMD5Hash(); - - context.Update(existingSetFileInfo); - context.Update(beatmapInfo); - - context.SaveChanges(transaction); - } - } - - public void MigrateAllToNewFormat() - { - var usableSets = GetAllUsableBeatmapSets(); - - if (usableSets.Count == 0) - return; - - var notification = new ProgressNotification - { - Progress = 0, - State = ProgressNotificationState.Active, - }; - - PostNotification?.Invoke(notification); - - int i = 1; - foreach (var set in usableSets) - { - if (notification.State == ProgressNotificationState.Cancelled) - // user requested abort - return; - - notification.Text = $"Migrating ({i} of {usableSets.Count})"; - notification.Progress = (float)i++ / usableSets.Count; - - foreach (var beatmap in set.Beatmaps) - { - if (notification.State == ProgressNotificationState.Cancelled) - // user requested abort - return; - - var working = GetWorkingBeatmap(beatmap); - using (var ms = new MemoryStream()) - using (var sw = new StreamWriter(ms)) - { - sw.Write(working.Beatmap.Serialize()); - sw.Flush(); - - ms.Position = 0; - UpdateContent(beatmap, ms); - } - } - } - - notification.State = ProgressNotificationState.Completed; - } - /// /// Returns a list of all usable s. /// diff --git a/osu.Game/Beatmaps/WorkingBeatmap.cs b/osu.Game/Beatmaps/WorkingBeatmap.cs index 736cc2a0b0..8c8cf212c1 100644 --- a/osu.Game/Beatmaps/WorkingBeatmap.cs +++ b/osu.Game/Beatmaps/WorkingBeatmap.cs @@ -10,6 +10,10 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using osu.Game.Storyboards; +using osu.Framework.IO.File; +using System.IO; +using osu.Game.IO.Serialization; +using System.Diagnostics; namespace osu.Game.Beatmaps { @@ -38,6 +42,17 @@ namespace osu.Game.Beatmaps storyboard = new AsyncLazy(populateStoryboard); } + /// + /// Saves the . + /// + public void Save() + { + var path = FileSafety.GetTempPath(Guid.NewGuid().ToString().Replace("-", string.Empty) + ".json"); + using (var sw = new StreamWriter(path)) + sw.WriteLine(Beatmap.Serialize()); + Process.Start(path); + } + protected abstract Beatmap GetBeatmap(); protected abstract Texture GetBackground(); protected abstract Track GetTrack(); diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs index 2b40ade895..a648ebd64c 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs @@ -58,18 +58,6 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance } }; - if (!osuGame.IsDeployedBuild) - { - Add(migrateButton = new SettingsButton - { - Text = "Migrate all beatmaps to the new format", - Action = () => - { - migrateButton.Enabled.Value = false; - Task.Factory.StartNew(beatmaps.MigrateAllToNewFormat).ContinueWith(t => Schedule(() => migrateButton.Enabled.Value = true), TaskContinuationOptions.LongRunning); - } - }); - } } } } diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 607ff792d8..5ff48f1adf 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -67,6 +67,7 @@ namespace osu.Game.Screens.Edit { Items = new[] { + new EditorMenuItem("Export", MenuItemType.Standard, exportBeatmap), new EditorMenuItem("Exit", MenuItemType.Standard, Exit) } } @@ -136,6 +137,11 @@ namespace osu.Game.Screens.Edit bottomBackground.Colour = colours.Gray2; } + private void exportBeatmap() + { + Beatmap.Value.Save(); + } + private void onModeChanged(EditorScreenMode mode) { currentScreen?.Exit(); From 2fb8895e663ac6adba47bdb0de38b2ab48fb1353 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 21 Dec 2017 19:57:09 +0900 Subject: [PATCH 049/122] Add spacer to menu --- osu.Game/Screens/Edit/Editor.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 5ff48f1adf..19d00f3477 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -68,6 +68,7 @@ namespace osu.Game.Screens.Edit Items = new[] { new EditorMenuItem("Export", MenuItemType.Standard, exportBeatmap), + new EditorMenuItemSpacer(), new EditorMenuItem("Exit", MenuItemType.Standard, Exit) } } From eb382dc23f0ce817782931a2c43e5bdb272beab8 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 21 Dec 2017 19:58:41 +0900 Subject: [PATCH 050/122] Update framework --- osu-framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu-framework b/osu-framework index d997b34da4..e41fa9e90a 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit d997b34da4556e4fcfc2de5413ded92c6ee9bec1 +Subproject commit e41fa9e90ae8261afa2962ee9fddb5b68491212c From 866d1c6e0f584829072211705a4d31b62fca5ee0 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 21 Dec 2017 22:13:18 +0900 Subject: [PATCH 051/122] Remove now unused references --- osu.Game/Beatmaps/BeatmapManager.cs | 1 - .../Overlays/Settings/Sections/Maintenance/GeneralSettings.cs | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index ca1a056992..a1ad708304 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -20,7 +20,6 @@ using osu.Game.Beatmaps.IO; using osu.Game.Database; using osu.Game.Graphics; using osu.Game.IO; -using osu.Game.IO.Serialization; using osu.Game.IPC; using osu.Game.Online.API; using osu.Game.Online.API.Requests; diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs index a648ebd64c..953e9a54ae 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs @@ -20,7 +20,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance protected override string Header => "General"; [BackgroundDependencyLoader] - private void load(OsuGameBase osuGame, BeatmapManager beatmaps) + private void load(BeatmapManager beatmaps) { Children = new Drawable[] { @@ -57,7 +57,6 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance } } }; - } } } From 790aa8be2a51b0d6a07f3750e0beb085c7f8da7a Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 21 Dec 2017 22:13:53 +0900 Subject: [PATCH 052/122] Merge master into beatmap-serialization --- osu-framework | 2 +- .../Bindings/GlobalKeyBindingInputManager.cs | 3 +- osu.Game/Screens/Play/GameplayMenuOverlay.cs | 108 ++++++++++-------- osu.Game/Screens/Play/Player.cs | 2 +- 4 files changed, 64 insertions(+), 51 deletions(-) diff --git a/osu-framework b/osu-framework index e41fa9e90a..f4fde31f8c 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit e41fa9e90ae8261afa2962ee9fddb5b68491212c +Subproject commit f4fde31f8c09305d2130064da2f7bae995be8286 diff --git a/osu.Game/Input/Bindings/GlobalKeyBindingInputManager.cs b/osu.Game/Input/Bindings/GlobalKeyBindingInputManager.cs index 759396e195..745508ec9e 100644 --- a/osu.Game/Input/Bindings/GlobalKeyBindingInputManager.cs +++ b/osu.Game/Input/Bindings/GlobalKeyBindingInputManager.cs @@ -5,11 +5,12 @@ using System.Collections.Generic; using System.ComponentModel; using System.Linq; using osu.Framework.Graphics; +using osu.Framework.Input; using osu.Framework.Input.Bindings; namespace osu.Game.Input.Bindings { - public class GlobalKeyBindingInputManager : DatabasedKeyBindingInputManager + public class GlobalKeyBindingInputManager : DatabasedKeyBindingInputManager, IHandleGlobalInput { private readonly Drawable handler; diff --git a/osu.Game/Screens/Play/GameplayMenuOverlay.cs b/osu.Game/Screens/Play/GameplayMenuOverlay.cs index 182c4efe89..6969cd915b 100644 --- a/osu.Game/Screens/Play/GameplayMenuOverlay.cs +++ b/osu.Game/Screens/Play/GameplayMenuOverlay.cs @@ -26,6 +26,8 @@ namespace osu.Game.Screens.Play protected override bool BlockPassThroughKeyboard => true; + public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => true; + public Action OnRetry; public Action OnQuit; @@ -122,44 +124,21 @@ namespace osu.Game.Screens.Play }, }; - Retries = 0; + updateRetryCount(); } + private int retries; + public int Retries { set { - if (retryCounterContainer != null) - { - // "You've retried 1,065 times in this session" - // "You've retried 1 time in this session" + if (value == retries) + return; - retryCounterContainer.Children = new Drawable[] - { - new OsuSpriteText - { - Text = "You've retried ", - Shadow = true, - ShadowColour = new Color4(0, 0, 0, 0.25f), - TextSize = 18 - }, - new OsuSpriteText - { - Text = $"{value:n0}", - Font = @"Exo2.0-Bold", - Shadow = true, - ShadowColour = new Color4(0, 0, 0, 0.25f), - TextSize = 18 - }, - new OsuSpriteText - { - Text = $" time{(value == 1 ? "" : "s")} in this session", - Shadow = true, - ShadowColour = new Color4(0, 0, 0, 0.25f), - TextSize = 18 - } - }; - } + retries = value; + if (retryCounterContainer != null) + updateRetryCount(); } } @@ -197,6 +176,7 @@ namespace osu.Game.Screens.Play } private int _selectionIndex = -1; + private int selectionIndex { get { return _selectionIndex; } @@ -219,26 +199,26 @@ namespace osu.Game.Screens.Play protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) { - if (args.Repeat) - return false; - - switch (args.Key) + if (!args.Repeat) { - case Key.Up: - if (selectionIndex == -1 || selectionIndex == 0) - selectionIndex = InternalButtons.Count - 1; - else - selectionIndex--; - return true; - case Key.Down: - if (selectionIndex == -1 || selectionIndex == InternalButtons.Count - 1) - selectionIndex = 0; - else - selectionIndex++; - return true; + switch (args.Key) + { + case Key.Up: + if (selectionIndex == -1 || selectionIndex == 0) + selectionIndex = InternalButtons.Count - 1; + else + selectionIndex--; + return true; + case Key.Down: + if (selectionIndex == -1 || selectionIndex == InternalButtons.Count - 1) + selectionIndex = 0; + else + selectionIndex++; + return true; + } } - return false; + return base.OnKeyDown(state, args); } private void buttonSelectionChanged(DialogButton button, bool isSelected) @@ -249,6 +229,38 @@ namespace osu.Game.Screens.Play selectionIndex = InternalButtons.IndexOf(button); } + private void updateRetryCount() + { + // "You've retried 1,065 times in this session" + // "You've retried 1 time in this session" + + retryCounterContainer.Children = new Drawable[] + { + new OsuSpriteText + { + Text = "You've retried ", + Shadow = true, + ShadowColour = new Color4(0, 0, 0, 0.25f), + TextSize = 18 + }, + new OsuSpriteText + { + Text = $"{retries:n0}", + Font = @"Exo2.0-Bold", + Shadow = true, + ShadowColour = new Color4(0, 0, 0, 0.25f), + TextSize = 18 + }, + new OsuSpriteText + { + Text = $" time{(retries == 1 ? "" : "s")} in this session", + Shadow = true, + ShadowColour = new Color4(0, 0, 0, 0.25f), + TextSize = 18 + } + }; + } + private class Button : DialogButton { protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index b5b09504da..e9992f2df7 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -161,8 +161,8 @@ namespace osu.Game.Screens.Play OnRetry = Restart, OnQuit = Exit, CheckCanPause = () => AllowPause && ValidForResume && !HasFailed && !RulesetContainer.HasReplayLoaded, - Retries = RestartCount, OnPause = () => { + pauseContainer.Retries = RestartCount; hudOverlay.KeyCounter.IsCounting = pauseContainer.IsPaused; }, OnResume = () => { From ac1d27e925e80f95d939bf30d72faa563afe5a29 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 21 Dec 2017 23:02:46 +0900 Subject: [PATCH 053/122] Fix possible nullref exceptions --- osu.Game.Rulesets.Catch/Objects/JuiceStream.cs | 3 ++- osu.Game.Rulesets.Mania/Objects/HoldNote.cs | 3 ++- osu.Game.Rulesets.Osu/Objects/Slider.cs | 6 ++++-- osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs | 3 ++- 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs index 4de8cd897f..b0540b2a4d 100644 --- a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs +++ b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs @@ -130,7 +130,8 @@ namespace osu.Game.Rulesets.Catch.Objects }); } - ticks.ForEach(t => t.ApplyDefaults(controlPointInfo, difficulty)); + if (controlPointInfo != null && difficulty != null) + ticks.ForEach(t => t.ApplyDefaults(controlPointInfo, difficulty)); return ticks; } diff --git a/osu.Game.Rulesets.Mania/Objects/HoldNote.cs b/osu.Game.Rulesets.Mania/Objects/HoldNote.cs index 2b68dcf62c..2a62eaa2ef 100644 --- a/osu.Game.Rulesets.Mania/Objects/HoldNote.cs +++ b/osu.Game.Rulesets.Mania/Objects/HoldNote.cs @@ -101,7 +101,8 @@ namespace osu.Game.Rulesets.Mania.Objects Column = Column }; - tick.ApplyDefaults(controlPointInfo, difficulty); + if (controlPointInfo != null && difficulty != null) + tick.ApplyDefaults(controlPointInfo, difficulty); ret.Add(tick); } diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs index 5449466f2e..af50667d42 100644 --- a/osu.Game.Rulesets.Osu/Objects/Slider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs @@ -146,7 +146,8 @@ namespace osu.Game.Rulesets.Osu.Objects })) }; - ret.ApplyDefaults(controlPointInfo, difficulty); + if (controlPointInfo != null && difficulty != null) + ret.ApplyDefaults(controlPointInfo, difficulty); yield return ret; } @@ -178,7 +179,8 @@ namespace osu.Game.Rulesets.Osu.Objects ComboColour = ComboColour, }; - ret.ApplyDefaults(controlPointInfo, difficulty); + if (controlPointInfo != null && difficulty != null) + ret.ApplyDefaults(controlPointInfo, difficulty); yield return ret; } diff --git a/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs b/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs index a2503b8060..ff20a16c7b 100644 --- a/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs +++ b/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs @@ -96,7 +96,8 @@ namespace osu.Game.Rulesets.Taiko.Objects })) }; - tick.ApplyDefaults(controlPointInfo, difficulty); + if (controlPointInfo != null && difficulty != null) + tick.ApplyDefaults(controlPointInfo, difficulty); ret.Add(tick); first = false; From 6ef575c005c6aa889ffda6606c382f7d41909fed Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 22 Dec 2017 15:46:45 +0900 Subject: [PATCH 054/122] Update framework --- osu-framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu-framework b/osu-framework index f4fde31f8c..675745afa1 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit f4fde31f8c09305d2130064da2f7bae995be8286 +Subproject commit 675745afa19c0ceaa96a43edf76ee295ba394c61 From f3c93c894b273d1373e5e44c302522b46e41becb Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Tue, 21 Nov 2017 10:15:16 +0300 Subject: [PATCH 055/122] Rank graph improvements --- osu.Game/Overlays/Profile/ProfileHeader.cs | 13 ++- osu.Game/Overlays/Profile/RankChart.cs | 125 +++++++++++++-------- 2 files changed, 88 insertions(+), 50 deletions(-) diff --git a/osu.Game/Overlays/Profile/ProfileHeader.cs b/osu.Game/Overlays/Profile/ProfileHeader.cs index 4ddd6c498e..f0b441affb 100644 --- a/osu.Game/Overlays/Profile/ProfileHeader.cs +++ b/osu.Game/Overlays/Profile/ProfileHeader.cs @@ -27,6 +27,7 @@ namespace osu.Game.Overlays.Profile private readonly OsuTextFlowContainer infoTextLeft; private readonly LinkFlowContainer infoTextRight; private readonly FillFlowContainer scoreText, scoreNumberText; + protected readonly RankChart rankGraph; private readonly Container coverContainer, chartContainer, supporterTag; private readonly Sprite levelBadge; @@ -285,6 +286,10 @@ namespace osu.Game.Overlays.Profile { Colour = Color4.Black.Opacity(0.25f), RelativeSizeAxes = Axes.Both + }, + rankGraph = new RankChart + { + RelativeSizeAxes = Axes.Both } } } @@ -303,11 +308,7 @@ namespace osu.Game.Overlays.Profile public User User { - get - { - return user; - } - + get { return user; } set { user = value; @@ -420,7 +421,7 @@ namespace osu.Game.Overlays.Profile gradeSPlus.DisplayCount = 0; gradeSSPlus.DisplayCount = 0; - chartContainer.Add(new RankChart(user) { RelativeSizeAxes = Axes.Both }); + rankGraph.Redraw(user); } } diff --git a/osu.Game/Overlays/Profile/RankChart.cs b/osu.Game/Overlays/Profile/RankChart.cs index 8190ef3c62..3981939bf8 100644 --- a/osu.Game/Overlays/Profile/RankChart.cs +++ b/osu.Game/Overlays/Profile/RankChart.cs @@ -14,30 +14,40 @@ using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using osu.Game.Users; +using System.Collections.Generic; namespace osu.Game.Overlays.Profile { public class RankChart : Container { + private const float primary_textsize = 25; + private const float secondary_textsize = 13; + private const float padding = 10; + private const float fade_duration = 150; + private const int rankedDays = 88; + private readonly SpriteText rankText, performanceText, relativeText; private readonly RankChartLineGraph graph; + private readonly OsuSpriteText placeholder; - private readonly int[] ranks; + private KeyValuePair[] ranks; + private User user; - private const float primary_textsize = 25, secondary_textsize = 13, padding = 10; - - private readonly User user; - - public RankChart(User user) + public RankChart() { - this.user = user; - - int[] userRanks = user.RankHistory?.Data ?? new[] { user.Statistics.Rank }; - ranks = userRanks.SkipWhile(x => x == 0).ToArray(); - Padding = new MarginPadding { Vertical = padding }; Children = new Drawable[] { + placeholder = new OsuSpriteText + { + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + Text = "No recent plays", + TextSize = 14, + Font = @"Exo2.0-RegularItalic", + Alpha = 0, + Padding = new MarginPadding { Bottom = padding } + }, rankText = new OsuSpriteText { Anchor = Anchor.TopCentre, @@ -60,50 +70,73 @@ namespace osu.Game.Overlays.Profile Font = @"Exo2.0-RegularItalic", TextSize = secondary_textsize }, - }; - - if (ranks.Length > 0) - { - Add(graph = new RankChartLineGraph + graph = new RankChartLineGraph { Anchor = Anchor.BottomCentre, Origin = Anchor.BottomCentre, RelativeSizeAxes = Axes.X, Y = -secondary_textsize, - DefaultValueCount = ranks.Length, - }); + Alpha = 0, + } + }; - graph.OnBallMove += showHistoryRankTexts; + graph.OnBallMove += showHistoryRankTexts; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + graph.Colour = colours.Yellow; + } + + public void Redraw(User user) + { + if (this.user == null && user != null) + placeholder.FadeOut(fade_duration, Easing.Out); + + this.user = user; + + if (user == null) + { + rankText.Text = string.Empty; + performanceText.Text = string.Empty; + relativeText.Text = string.Empty; + graph.FadeOut(fade_duration, Easing.Out); + placeholder.FadeIn(fade_duration, Easing.Out); + ranks = null; + return; } + + int[] userRanks = user.RankHistory?.Data ?? new[] { user.Statistics.Rank }; + var tempRanks = userRanks.Select((x, index) => new KeyValuePair(index, x)).SkipWhile(x => x.Value == 0).ToArray(); + ranks = tempRanks.Where(x => x.Value != 0).ToArray(); + + if (ranks.Length > 1) + { + graph.DefaultValueCount = ranks.Length; + graph.Values = ranks.Select(x => -(float)Math.Log(x.Value)); + graph.SetStaticBallPosition(); + graph.FadeIn(fade_duration, Easing.Out); + } + else + { + graph.FadeOut(fade_duration, Easing.Out); + } + + updateRankTexts(); } private void updateRankTexts() { rankText.Text = user.Statistics.Rank > 0 ? $"#{user.Statistics.Rank:#,0}" : "no rank"; performanceText.Text = user.Statistics.PP != null ? $"{user.Statistics.PP:#,0}pp" : string.Empty; - relativeText.Text = user.CountryRank > 0 ? $"{user.Country?.FullName} #{user.CountryRank:#,0}" : $"{user.Country?.FullName}"; + relativeText.Text = $"{user.Country?.FullName} #{user.CountryRank:#,0}"; } private void showHistoryRankTexts(int dayIndex) { - rankText.Text = ranks[dayIndex] > 0 ? $"#{ranks[dayIndex]:#,0}" : "no rank"; - dayIndex++; - relativeText.Text = dayIndex == ranks.Length ? "Now" : $"{ranks.Length - dayIndex} days ago"; - //plural should be handled in a general way - } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - if (graph != null) - { - graph.Colour = colours.Yellow; - // use logarithmic coordinates - graph.Values = ranks.Select(x => x == 0 ? float.MinValue : -(float)Math.Log(x)); - graph.SetStaticBallPosition(); - } - - updateRankTexts(); + rankText.Text = $"#{ranks[dayIndex].Value:#,0}"; + relativeText.Text = dayIndex + 1 == ranks.Length ? "Now" : $"{rankedDays - ranks[dayIndex].Key} days ago"; } public override bool Invalidate(Invalidation invalidation = Invalidation.All, Drawable source = null, bool shallPropagate = true) @@ -118,31 +151,35 @@ namespace osu.Game.Overlays.Profile protected override bool OnHover(InputState state) { - graph?.UpdateBallPosition(state.Mouse.Position.X); - graph?.ShowBall(); + if (ranks != null && ranks.Length > 1) + { + graph.UpdateBallPosition(state.Mouse.Position.X); + graph.ShowBall(); + } return base.OnHover(state); } protected override bool OnMouseMove(InputState state) { - graph?.UpdateBallPosition(state.Mouse.Position.X); + if (ranks != null && ranks.Length > 1) + graph.UpdateBallPosition(state.Mouse.Position.X); + return base.OnMouseMove(state); } protected override void OnHoverLost(InputState state) { - if (graph != null) + if (ranks != null && ranks.Length > 1) { graph.HideBall(); updateRankTexts(); } + base.OnHoverLost(state); } private class RankChartLineGraph : LineGraph { - private const double fade_duration = 200; - private readonly CircularContainer staticBall; private readonly CircularContainer movingBall; From 5ffdaf711e59f1dd909f4ed1cf758fa54e4877ce Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Tue, 21 Nov 2017 10:30:12 +0300 Subject: [PATCH 056/122] Remove useless array --- osu.Game/Overlays/Profile/RankChart.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Profile/RankChart.cs b/osu.Game/Overlays/Profile/RankChart.cs index 3981939bf8..6547b0aa07 100644 --- a/osu.Game/Overlays/Profile/RankChart.cs +++ b/osu.Game/Overlays/Profile/RankChart.cs @@ -108,8 +108,7 @@ namespace osu.Game.Overlays.Profile } int[] userRanks = user.RankHistory?.Data ?? new[] { user.Statistics.Rank }; - var tempRanks = userRanks.Select((x, index) => new KeyValuePair(index, x)).SkipWhile(x => x.Value == 0).ToArray(); - ranks = tempRanks.Where(x => x.Value != 0).ToArray(); + ranks = userRanks.Select((x, index) => new KeyValuePair(index, x)).Where(x => x.Value != 0).ToArray(); if (ranks.Length > 1) { From e48c515d5291ac8d045fa8433834a8731fee63aa Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Tue, 21 Nov 2017 10:36:53 +0300 Subject: [PATCH 057/122] CI fixes --- osu.Game/Overlays/Profile/ProfileHeader.cs | 6 +++--- osu.Game/Overlays/Profile/RankChart.cs | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game/Overlays/Profile/ProfileHeader.cs b/osu.Game/Overlays/Profile/ProfileHeader.cs index f0b441affb..40843e5b98 100644 --- a/osu.Game/Overlays/Profile/ProfileHeader.cs +++ b/osu.Game/Overlays/Profile/ProfileHeader.cs @@ -27,9 +27,9 @@ namespace osu.Game.Overlays.Profile private readonly OsuTextFlowContainer infoTextLeft; private readonly LinkFlowContainer infoTextRight; private readonly FillFlowContainer scoreText, scoreNumberText; - protected readonly RankChart rankGraph; + private readonly RankChart rankGraph; - private readonly Container coverContainer, chartContainer, supporterTag; + private readonly Container coverContainer, supporterTag; private readonly Sprite levelBadge; private readonly SpriteText levelText; private readonly GradeBadge gradeSSPlus, gradeSS, gradeSPlus, gradeS, gradeA; @@ -274,7 +274,7 @@ namespace osu.Game.Overlays.Profile } } }, - chartContainer = new Container + new Container { RelativeSizeAxes = Axes.X, Anchor = Anchor.BottomCentre, diff --git a/osu.Game/Overlays/Profile/RankChart.cs b/osu.Game/Overlays/Profile/RankChart.cs index 6547b0aa07..c7a1c88818 100644 --- a/osu.Game/Overlays/Profile/RankChart.cs +++ b/osu.Game/Overlays/Profile/RankChart.cs @@ -24,7 +24,7 @@ namespace osu.Game.Overlays.Profile private const float secondary_textsize = 13; private const float padding = 10; private const float fade_duration = 150; - private const int rankedDays = 88; + private const int ranked_days = 88; private readonly SpriteText rankText, performanceText, relativeText; private readonly RankChartLineGraph graph; @@ -135,7 +135,7 @@ namespace osu.Game.Overlays.Profile private void showHistoryRankTexts(int dayIndex) { rankText.Text = $"#{ranks[dayIndex].Value:#,0}"; - relativeText.Text = dayIndex + 1 == ranks.Length ? "Now" : $"{rankedDays - ranks[dayIndex].Key} days ago"; + relativeText.Text = dayIndex + 1 == ranks.Length ? "Now" : $"{ranked_days - ranks[dayIndex].Key} days ago"; } public override bool Invalidate(Invalidation invalidation = Invalidation.All, Drawable source = null, bool shallPropagate = true) From 94a974a397973d26569372aaa7be95f0f4eb760d Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Tue, 21 Nov 2017 13:33:34 +0300 Subject: [PATCH 058/122] Use bindable for a user --- osu.Game/Overlays/Profile/ProfileHeader.cs | 2 +- osu.Game/Overlays/Profile/RankChart.cs | 30 ++++++++++------------ 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/osu.Game/Overlays/Profile/ProfileHeader.cs b/osu.Game/Overlays/Profile/ProfileHeader.cs index 40843e5b98..509e05329b 100644 --- a/osu.Game/Overlays/Profile/ProfileHeader.cs +++ b/osu.Game/Overlays/Profile/ProfileHeader.cs @@ -421,7 +421,7 @@ namespace osu.Game.Overlays.Profile gradeSPlus.DisplayCount = 0; gradeSSPlus.DisplayCount = 0; - rankGraph.Redraw(user); + rankGraph.User.Value = user; } } diff --git a/osu.Game/Overlays/Profile/RankChart.cs b/osu.Game/Overlays/Profile/RankChart.cs index c7a1c88818..0ff7914fa9 100644 --- a/osu.Game/Overlays/Profile/RankChart.cs +++ b/osu.Game/Overlays/Profile/RankChart.cs @@ -15,6 +15,7 @@ using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using osu.Game.Users; using System.Collections.Generic; +using osu.Framework.Configuration; namespace osu.Game.Overlays.Profile { @@ -31,7 +32,7 @@ namespace osu.Game.Overlays.Profile private readonly OsuSpriteText placeholder; private KeyValuePair[] ranks; - private User user; + public Bindable User = new Bindable(); public RankChart() { @@ -81,6 +82,8 @@ namespace osu.Game.Overlays.Profile }; graph.OnBallMove += showHistoryRankTexts; + + User.ValueChanged += userChanged; } [BackgroundDependencyLoader] @@ -89,25 +92,21 @@ namespace osu.Game.Overlays.Profile graph.Colour = colours.Yellow; } - public void Redraw(User user) + private void userChanged(User newUser) { - if (this.user == null && user != null) - placeholder.FadeOut(fade_duration, Easing.Out); + placeholder.FadeTo(newUser == null ? 1 : 0, fade_duration, Easing.Out); - this.user = user; - - if (user == null) + if (newUser == null) { rankText.Text = string.Empty; performanceText.Text = string.Empty; relativeText.Text = string.Empty; graph.FadeOut(fade_duration, Easing.Out); - placeholder.FadeIn(fade_duration, Easing.Out); ranks = null; return; } - int[] userRanks = user.RankHistory?.Data ?? new[] { user.Statistics.Rank }; + int[] userRanks = newUser.RankHistory?.Data ?? new[] { newUser.Statistics.Rank }; ranks = userRanks.Select((x, index) => new KeyValuePair(index, x)).Where(x => x.Value != 0).ToArray(); if (ranks.Length > 1) @@ -115,21 +114,18 @@ namespace osu.Game.Overlays.Profile graph.DefaultValueCount = ranks.Length; graph.Values = ranks.Select(x => -(float)Math.Log(x.Value)); graph.SetStaticBallPosition(); - graph.FadeIn(fade_duration, Easing.Out); - } - else - { - graph.FadeOut(fade_duration, Easing.Out); } + graph.FadeTo(ranks.Length > 1 ? 1 : 0, fade_duration, Easing.Out); + updateRankTexts(); } private void updateRankTexts() { - rankText.Text = user.Statistics.Rank > 0 ? $"#{user.Statistics.Rank:#,0}" : "no rank"; - performanceText.Text = user.Statistics.PP != null ? $"{user.Statistics.PP:#,0}pp" : string.Empty; - relativeText.Text = $"{user.Country?.FullName} #{user.CountryRank:#,0}"; + rankText.Text = User.Value.Statistics.Rank > 0 ? $"#{User.Value.Statistics.Rank:#,0}" : "no rank"; + performanceText.Text = User.Value.Statistics.PP != null ? $"{User.Value.Statistics.PP:#,0}pp" : string.Empty; + relativeText.Text = $"{User.Value.Country?.FullName} #{User.Value.CountryRank:#,0}"; } private void showHistoryRankTexts(int dayIndex) From 938c5feea4fddc4eae862cb3d9171b1fabdbe1d8 Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Tue, 21 Nov 2017 13:42:42 +0300 Subject: [PATCH 059/122] Simplify interaction condition --- osu.Game/Overlays/Profile/RankChart.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Profile/RankChart.cs b/osu.Game/Overlays/Profile/RankChart.cs index 0ff7914fa9..92655f2993 100644 --- a/osu.Game/Overlays/Profile/RankChart.cs +++ b/osu.Game/Overlays/Profile/RankChart.cs @@ -146,7 +146,7 @@ namespace osu.Game.Overlays.Profile protected override bool OnHover(InputState state) { - if (ranks != null && ranks.Length > 1) + if (ranks?.Length > 1) { graph.UpdateBallPosition(state.Mouse.Position.X); graph.ShowBall(); @@ -156,7 +156,7 @@ namespace osu.Game.Overlays.Profile protected override bool OnMouseMove(InputState state) { - if (ranks != null && ranks.Length > 1) + if (ranks?.Length > 1) graph.UpdateBallPosition(state.Mouse.Position.X); return base.OnMouseMove(state); @@ -164,7 +164,7 @@ namespace osu.Game.Overlays.Profile protected override void OnHoverLost(InputState state) { - if (ranks != null && ranks.Length > 1) + if (ranks?.Length > 1) { graph.HideBall(); updateRankTexts(); From 8c50fa0b84d31ac19f05a90e6c1a71a3a7e13047 Mon Sep 17 00:00:00 2001 From: EVAST9919 Date: Wed, 22 Nov 2017 07:04:54 +0300 Subject: [PATCH 060/122] Add testcase --- osu.Game.Tests/Visual/TestCaseRankGraph.cs | 118 +++++++++++++++++++++ osu.Game.Tests/osu.Game.Tests.csproj | 1 + osu.Game/Overlays/Profile/RankChart.cs | 1 - 3 files changed, 119 insertions(+), 1 deletion(-) create mode 100644 osu.Game.Tests/Visual/TestCaseRankGraph.cs diff --git a/osu.Game.Tests/Visual/TestCaseRankGraph.cs b/osu.Game.Tests/Visual/TestCaseRankGraph.cs new file mode 100644 index 0000000000..5cdb6269f7 --- /dev/null +++ b/osu.Game.Tests/Visual/TestCaseRankGraph.cs @@ -0,0 +1,118 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Game.Overlays.Profile; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using OpenTK; +using osu.Framework.Graphics.Shapes; +using osu.Game.Graphics; +using System.Collections.Generic; +using System; +using osu.Game.Users; + +namespace osu.Game.Tests.Visual +{ + public class TestCaseRankGraph : OsuTestCase + { + public override IReadOnlyList RequiredTypes => new[] { typeof(RankChart) }; + + public TestCaseRankGraph() + { + RankChart graph; + + var data = new int[89]; + var dataWithZeros = new int[89]; + var smallData = new int[89]; + + for(int i = 0; i < 89; i++) + data[i] = dataWithZeros[i] = (i + 1) * 1000; + + for (int i = 20; i < 60; i++) + dataWithZeros[i] = 0; + + for (int i = 79; i < 89; i++) + smallData[i] = 100000 - i * 1000; + + Add(new Container + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(300, 150), + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = OsuColour.Gray(0.2f) + }, + graph = new RankChart + { + RelativeSizeAxes = Axes.Both, + } + } + }); + + AddStep("null user", () => graph.User.Value = null); + AddStep("rank only", () => + { + graph.User.Value = new User + { + Statistics = new UserStatistics + { + Rank = 123456, + PP = 12345, + } + }; + }); + + AddStep("with rank history", () => + { + graph.User.Value = new User + { + Statistics = new UserStatistics + { + Rank = 89000, + PP = 12345, + }, + RankHistory = new User.RankHistoryData + { + Data = data, + } + }; + }); + + AddStep("with zero values", () => + { + graph.User.Value = new User + { + Statistics = new UserStatistics + { + Rank = 89000, + PP = 12345, + }, + RankHistory = new User.RankHistoryData + { + Data = dataWithZeros, + } + }; + }); + + AddStep("small amount of data", () => + { + graph.User.Value = new User + { + Statistics = new UserStatistics + { + Rank = 12000, + PP = 12345, + }, + RankHistory = new User.RankHistoryData + { + Data = smallData, + } + }; + }); + } + } +} diff --git a/osu.Game.Tests/osu.Game.Tests.csproj b/osu.Game.Tests/osu.Game.Tests.csproj index e78b9d5c0e..31915b44cc 100644 --- a/osu.Game.Tests/osu.Game.Tests.csproj +++ b/osu.Game.Tests/osu.Game.Tests.csproj @@ -130,6 +130,7 @@ + diff --git a/osu.Game/Overlays/Profile/RankChart.cs b/osu.Game/Overlays/Profile/RankChart.cs index 92655f2993..73030acadd 100644 --- a/osu.Game/Overlays/Profile/RankChart.cs +++ b/osu.Game/Overlays/Profile/RankChart.cs @@ -46,7 +46,6 @@ namespace osu.Game.Overlays.Profile Text = "No recent plays", TextSize = 14, Font = @"Exo2.0-RegularItalic", - Alpha = 0, Padding = new MarginPadding { Bottom = padding } }, rankText = new OsuSpriteText From 1a318c5c2b87f4fa4161552ac717c5846fe54999 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 22 Dec 2017 18:58:35 +0900 Subject: [PATCH 061/122] Improve LineGraph invalidation logic --- osu.Game.Tests/Visual/TestCaseUserProfile.cs | 11 ++++++ osu.Game/Graphics/UserInterface/LineGraph.cs | 38 ++++++++++++++------ 2 files changed, 39 insertions(+), 10 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseUserProfile.cs b/osu.Game.Tests/Visual/TestCaseUserProfile.cs index 697b84941c..7f2e7779d9 100644 --- a/osu.Game.Tests/Visual/TestCaseUserProfile.cs +++ b/osu.Game.Tests/Visual/TestCaseUserProfile.cs @@ -2,14 +2,25 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; +using System.Collections.Generic; using System.Linq; +using osu.Game.Graphics.UserInterface; using osu.Game.Overlays; +using osu.Game.Overlays.Profile; using osu.Game.Users; namespace osu.Game.Tests.Visual { public class TestCaseUserProfile : OsuTestCase { + public override IReadOnlyList RequiredTypes => new[] + { + typeof(ProfileHeader), + typeof(UserProfileOverlay), + typeof(RankChart), + typeof(LineGraph), + }; + public TestCaseUserProfile() { var profile = new UserProfileOverlay(); diff --git a/osu.Game/Graphics/UserInterface/LineGraph.cs b/osu.Game/Graphics/UserInterface/LineGraph.cs index aa9256e576..ea74c67f6c 100644 --- a/osu.Game/Graphics/UserInterface/LineGraph.cs +++ b/osu.Game/Graphics/UserInterface/LineGraph.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Linq; +using osu.Framework.Caching; using OpenTK; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -47,7 +48,16 @@ namespace osu.Game.Graphics.UserInterface set { values = value.ToArray(); - applyPath(); + + float max = values.Max(), min = values.Min(); + if (MaxValue > max) max = MaxValue.Value; + if (MinValue < min) min = MinValue.Value; + + ActualMaxValue = max; + ActualMinValue = min; + + pathCached.Invalidate(); + maskingContainer.Width = 0; maskingContainer.ResizeWidthTo(1, transform_duration, Easing.OutQuint); } @@ -63,13 +73,28 @@ namespace osu.Game.Graphics.UserInterface }); } + private bool pending; + public override bool Invalidate(Invalidation invalidation = Invalidation.All, Drawable source = null, bool shallPropagate = true) { - if ((invalidation & Invalidation.DrawSize) != 0) - applyPath(); + if ((invalidation & Invalidation.DrawSize) > 0) + pathCached.Invalidate(); + return base.Invalidate(invalidation, source, shallPropagate); } + private Cached pathCached = new Cached(); + + protected override void Update() + { + base.Update(); + if (!pathCached.IsValid) + { + applyPath(); + pathCached.Validate(); + } + } + private void applyPath() { path.ClearVertices(); @@ -77,13 +102,6 @@ namespace osu.Game.Graphics.UserInterface int count = Math.Max(values.Length, DefaultValueCount); - float max = values.Max(), min = values.Min(); - if (MaxValue > max) max = MaxValue.Value; - if (MinValue < min) min = MinValue.Value; - - ActualMaxValue = max; - ActualMinValue = min; - for (int i = 0; i < values.Length; i++) { float x = (i + count - values.Length) / (float)(count - 1) * DrawWidth - 1; From 728d1cb7f65110cb3f49459e776eff311f647dfd Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 22 Dec 2017 19:24:54 +0900 Subject: [PATCH 062/122] Formatting and more dynamically testable references --- osu.Game.Tests/Visual/TestCaseRankGraph.cs | 13 +++++++++---- osu.Game.Tests/Visual/TestCaseUserProfile.cs | 2 +- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseRankGraph.cs b/osu.Game.Tests/Visual/TestCaseRankGraph.cs index 5cdb6269f7..489fba6501 100644 --- a/osu.Game.Tests/Visual/TestCaseRankGraph.cs +++ b/osu.Game.Tests/Visual/TestCaseRankGraph.cs @@ -9,23 +9,28 @@ using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; using System.Collections.Generic; using System; +using osu.Game.Graphics.UserInterface; using osu.Game.Users; namespace osu.Game.Tests.Visual { public class TestCaseRankGraph : OsuTestCase { - public override IReadOnlyList RequiredTypes => new[] { typeof(RankChart) }; + public override IReadOnlyList RequiredTypes => new[] + { + typeof(RankGraph), + typeof(LineGraph) + }; public TestCaseRankGraph() { - RankChart graph; + RankGraph graph; var data = new int[89]; var dataWithZeros = new int[89]; var smallData = new int[89]; - for(int i = 0; i < 89; i++) + for (int i = 0; i < 89; i++) data[i] = dataWithZeros[i] = (i + 1) * 1000; for (int i = 20; i < 60; i++) @@ -46,7 +51,7 @@ namespace osu.Game.Tests.Visual RelativeSizeAxes = Axes.Both, Colour = OsuColour.Gray(0.2f) }, - graph = new RankChart + graph = new RankGraph { RelativeSizeAxes = Axes.Both, } diff --git a/osu.Game.Tests/Visual/TestCaseUserProfile.cs b/osu.Game.Tests/Visual/TestCaseUserProfile.cs index 7f2e7779d9..38d59f03b5 100644 --- a/osu.Game.Tests/Visual/TestCaseUserProfile.cs +++ b/osu.Game.Tests/Visual/TestCaseUserProfile.cs @@ -17,7 +17,7 @@ namespace osu.Game.Tests.Visual { typeof(ProfileHeader), typeof(UserProfileOverlay), - typeof(RankChart), + typeof(RankGraph), typeof(LineGraph), }; From 82909f6585eb372a91e37d3479d448300e7f217d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 22 Dec 2017 19:25:18 +0900 Subject: [PATCH 063/122] RankChart -> RankGraph --- osu.Game/Overlays/Profile/ProfileHeader.cs | 4 ++-- .../Profile/{RankChart.cs => RankGraph.cs} | 24 +++++++------------ osu.Game/osu.Game.csproj | 2 +- 3 files changed, 11 insertions(+), 19 deletions(-) rename osu.Game/Overlays/Profile/{RankChart.cs => RankGraph.cs} (88%) diff --git a/osu.Game/Overlays/Profile/ProfileHeader.cs b/osu.Game/Overlays/Profile/ProfileHeader.cs index 509e05329b..a706799664 100644 --- a/osu.Game/Overlays/Profile/ProfileHeader.cs +++ b/osu.Game/Overlays/Profile/ProfileHeader.cs @@ -27,7 +27,7 @@ namespace osu.Game.Overlays.Profile private readonly OsuTextFlowContainer infoTextLeft; private readonly LinkFlowContainer infoTextRight; private readonly FillFlowContainer scoreText, scoreNumberText; - private readonly RankChart rankGraph; + private readonly RankGraph rankGraph; private readonly Container coverContainer, supporterTag; private readonly Sprite levelBadge; @@ -287,7 +287,7 @@ namespace osu.Game.Overlays.Profile Colour = Color4.Black.Opacity(0.25f), RelativeSizeAxes = Axes.Both }, - rankGraph = new RankChart + rankGraph = new RankGraph { RelativeSizeAxes = Axes.Both } diff --git a/osu.Game/Overlays/Profile/RankChart.cs b/osu.Game/Overlays/Profile/RankGraph.cs similarity index 88% rename from osu.Game/Overlays/Profile/RankChart.cs rename to osu.Game/Overlays/Profile/RankGraph.cs index 73030acadd..b5933d6fec 100644 --- a/osu.Game/Overlays/Profile/RankChart.cs +++ b/osu.Game/Overlays/Profile/RankGraph.cs @@ -19,7 +19,7 @@ using osu.Framework.Configuration; namespace osu.Game.Overlays.Profile { - public class RankChart : Container + public class RankGraph : Container { private const float primary_textsize = 25; private const float secondary_textsize = 13; @@ -34,19 +34,18 @@ namespace osu.Game.Overlays.Profile private KeyValuePair[] ranks; public Bindable User = new Bindable(); - public RankChart() + public RankGraph() { Padding = new MarginPadding { Vertical = padding }; Children = new Drawable[] { placeholder = new OsuSpriteText { - Anchor = Anchor.BottomCentre, - Origin = Anchor.BottomCentre, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, Text = "No recent plays", TextSize = 14, Font = @"Exo2.0-RegularItalic", - Padding = new MarginPadding { Bottom = padding } }, rankText = new OsuSpriteText { @@ -75,6 +74,7 @@ namespace osu.Game.Overlays.Profile Anchor = Anchor.BottomCentre, Origin = Anchor.BottomCentre, RelativeSizeAxes = Axes.X, + Height = 75, Y = -secondary_textsize, Alpha = 0, } @@ -93,7 +93,7 @@ namespace osu.Game.Overlays.Profile private void userChanged(User newUser) { - placeholder.FadeTo(newUser == null ? 1 : 0, fade_duration, Easing.Out); + placeholder.FadeIn(fade_duration, Easing.Out); if (newUser == null) { @@ -110,6 +110,8 @@ namespace osu.Game.Overlays.Profile if (ranks.Length > 1) { + placeholder.FadeOut(fade_duration, Easing.Out); + graph.DefaultValueCount = ranks.Length; graph.Values = ranks.Select(x => -(float)Math.Log(x.Value)); graph.SetStaticBallPosition(); @@ -133,16 +135,6 @@ namespace osu.Game.Overlays.Profile relativeText.Text = dayIndex + 1 == ranks.Length ? "Now" : $"{ranked_days - ranks[dayIndex].Key} days ago"; } - public override bool Invalidate(Invalidation invalidation = Invalidation.All, Drawable source = null, bool shallPropagate = true) - { - if ((invalidation & Invalidation.DrawSize) != 0) - { - graph.Height = DrawHeight - padding * 2 - primary_textsize - secondary_textsize * 2; - } - - return base.Invalidate(invalidation, source, shallPropagate); - } - protected override bool OnHover(InputState state) { if (ranks?.Length > 1) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 199d51a8c1..1004d9dc95 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -499,7 +499,7 @@ - + From e5faced9bab698b14bcaf91b8eb1e73eb643650b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 22 Dec 2017 19:25:59 +0900 Subject: [PATCH 064/122] Better variable name --- osu.Game/Overlays/Profile/RankGraph.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Profile/RankGraph.cs b/osu.Game/Overlays/Profile/RankGraph.cs index b5933d6fec..d216789b1a 100644 --- a/osu.Game/Overlays/Profile/RankGraph.cs +++ b/osu.Game/Overlays/Profile/RankGraph.cs @@ -91,11 +91,11 @@ namespace osu.Game.Overlays.Profile graph.Colour = colours.Yellow; } - private void userChanged(User newUser) + private void userChanged(User user) { placeholder.FadeIn(fade_duration, Easing.Out); - if (newUser == null) + if (user == null) { rankText.Text = string.Empty; performanceText.Text = string.Empty; @@ -105,7 +105,7 @@ namespace osu.Game.Overlays.Profile return; } - int[] userRanks = newUser.RankHistory?.Data ?? new[] { newUser.Statistics.Rank }; + int[] userRanks = user.RankHistory?.Data ?? new[] { user.Statistics.Rank }; ranks = userRanks.Select((x, index) => new KeyValuePair(index, x)).Where(x => x.Value != 0).ToArray(); if (ranks.Length > 1) From 6a29f6020af7f6bf6397d0bbc3e3ba981ee33acf Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 22 Dec 2017 21:42:54 +0900 Subject: [PATCH 065/122] Make HitObjects construct nested hit objects --- .../Objects/CatchHitObject.cs | 4 +- .../Objects/Drawable/DrawableJuiceStream.cs | 3 +- .../Objects/JuiceStream.cs | 156 +++++++++--------- .../Scoring/CatchScoreProcessor.cs | 3 +- .../Objects/Drawables/DrawableHoldNote.cs | 2 +- osu.Game.Rulesets.Mania/Objects/HoldNote.cs | 42 ++--- osu.Game.Rulesets.Mania/Objects/Note.cs | 4 +- .../Scoring/ManiaScoreProcessor.cs | 2 +- .../Objects/Drawables/DrawableSlider.cs | 4 +- osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs | 4 +- osu.Game.Rulesets.Osu/Objects/Slider.cs | 133 +++++++-------- osu.Game.Rulesets.Osu/Objects/Spinner.cs | 4 +- .../Preprocessing/OsuDifficultyHitObject.cs | 2 +- .../Scoring/OsuPerformanceCalculator.cs | 2 +- .../Scoring/OsuScoreProcessor.cs | 5 +- .../Objects/Drawables/DrawableDrumRoll.cs | 2 +- osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs | 47 ++---- osu.Game.Rulesets.Taiko/Objects/Hit.cs | 4 +- .../Replays/TaikoAutoGenerator.cs | 3 +- .../Scoring/TaikoScoreProcessor.cs | 3 +- osu.Game/Rulesets/Objects/HitObject.cs | 25 ++- .../Rulesets/Objects/Legacy/ConvertSlider.cs | 4 +- 22 files changed, 216 insertions(+), 242 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs b/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs index 38757d4928..9952e85c70 100644 --- a/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs +++ b/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs @@ -37,9 +37,9 @@ namespace osu.Game.Rulesets.Catch.Objects /// public CatchHitObject HyperDashTarget; - public override void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) + protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) { - base.ApplyDefaults(controlPointInfo, difficulty); + base.ApplyDefaultsToSelf(controlPointInfo, difficulty); Scale = 1.0f - 0.7f * (difficulty.CircleSize - 5) / 5; } diff --git a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableJuiceStream.cs b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableJuiceStream.cs index bfb674d1b4..db0632a07d 100644 --- a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableJuiceStream.cs +++ b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableJuiceStream.cs @@ -1,6 +1,7 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System.Linq; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using OpenTK; @@ -25,7 +26,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable RelativeChildSize = new Vector2(1, (float)HitObject.Duration) }; - foreach (CatchHitObject tick in s.Ticks) + foreach (CatchHitObject tick in s.NestedHitObjects.OfType()) { TinyDroplet tiny = tick as TinyDroplet; if (tiny != null) diff --git a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs index b0540b2a4d..8e496c3b0c 100644 --- a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs +++ b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs @@ -11,8 +11,6 @@ using osu.Game.Rulesets.Catch.UI; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Types; using OpenTK; -using osu.Framework.Lists; -using osu.Framework.Extensions.IEnumerableExtensions; namespace osu.Game.Rulesets.Catch.Objects { @@ -30,14 +28,9 @@ namespace osu.Game.Rulesets.Catch.Objects public double Velocity; public double TickDistance; - private ControlPointInfo controlPointInfo; - private BeatmapDifficulty difficulty; - - public override void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) + protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) { - base.ApplyDefaults(controlPointInfo, difficulty); - this.controlPointInfo = controlPointInfo; - this.difficulty = difficulty; + base.ApplyDefaultsToSelf(controlPointInfo, difficulty); TimingControlPoint timingPoint = controlPointInfo.TimingPointAt(StartTime); DifficultyControlPoint difficultyPoint = controlPointInfo.DifficultyPointAt(StartTime); @@ -48,95 +41,94 @@ namespace osu.Game.Rulesets.Catch.Objects TickDistance = scoringDistance / difficulty.SliderTickRate; } - public IEnumerable Ticks + protected override void CreateNestedHitObjects() { - get + base.CreateNestedHitObjects(); + + createTicks(); + } + + private void createTicks() + { + if (TickDistance == 0) + return; + + var length = Curve.Distance; + var tickDistance = Math.Min(TickDistance, length); + var repeatDuration = length / Velocity; + + var minDistanceFromEnd = Velocity * 0.01; + + AddNested(new Fruit { - SortedList ticks = new SortedList((a, b) => a.StartTime.CompareTo(b.StartTime)); + Samples = Samples, + ComboColour = ComboColour, + StartTime = StartTime, + X = X + }); - if (TickDistance == 0) - return ticks; + for (var repeat = 0; repeat < RepeatCount; repeat++) + { + var repeatStartTime = StartTime + repeat * repeatDuration; + var reversed = repeat % 2 == 1; - var length = Curve.Distance; - var tickDistance = Math.Min(TickDistance, length); - var repeatDuration = length / Velocity; - - var minDistanceFromEnd = Velocity * 0.01; - - ticks.Add(new Fruit + for (var d = tickDistance; d <= length; d += tickDistance) { - Samples = Samples, - ComboColour = ComboColour, - StartTime = StartTime, - X = X - }); + if (d > length - minDistanceFromEnd) + break; - for (var repeat = 0; repeat < RepeatCount; repeat++) - { - var repeatStartTime = StartTime + repeat * repeatDuration; - var reversed = repeat % 2 == 1; + var timeProgress = d / length; + var distanceProgress = reversed ? 1 - timeProgress : timeProgress; - for (var d = tickDistance; d <= length; d += tickDistance) + var lastTickTime = repeatStartTime + timeProgress * repeatDuration; + AddNested(new Droplet { - if (d > length - minDistanceFromEnd) - break; - - var timeProgress = d / length; - var distanceProgress = reversed ? 1 - timeProgress : timeProgress; - - var lastTickTime = repeatStartTime + timeProgress * repeatDuration; - ticks.Add(new Droplet - { - StartTime = lastTickTime, - ComboColour = ComboColour, - X = Curve.PositionAt(distanceProgress).X / CatchPlayfield.BASE_WIDTH, - Samples = new SampleInfoList(Samples.Select(s => new SampleInfo - { - Bank = s.Bank, - Name = @"slidertick", - Volume = s.Volume - })) - }); - } - - double tinyTickInterval = tickDistance / length * repeatDuration; - while (tinyTickInterval > 100) - tinyTickInterval /= 2; - - for (double t = 0; t < repeatDuration; t += tinyTickInterval) - { - double progress = reversed ? 1 - t / repeatDuration : t / repeatDuration; - - ticks.Add(new TinyDroplet - { - StartTime = repeatStartTime + t, - ComboColour = ComboColour, - X = Curve.PositionAt(progress).X / CatchPlayfield.BASE_WIDTH, - Samples = new SampleInfoList(Samples.Select(s => new SampleInfo - { - Bank = s.Bank, - Name = @"slidertick", - Volume = s.Volume - })) - }); - } - - ticks.Add(new Fruit - { - Samples = Samples, + StartTime = lastTickTime, ComboColour = ComboColour, - StartTime = repeatStartTime + repeatDuration, - X = Curve.PositionAt(reversed ? 0 : 1).X / CatchPlayfield.BASE_WIDTH + X = Curve.PositionAt(distanceProgress).X / CatchPlayfield.BASE_WIDTH, + Samples = new SampleInfoList(Samples.Select(s => new SampleInfo + { + Bank = s.Bank, + Name = @"slidertick", + Volume = s.Volume + })) }); } - if (controlPointInfo != null && difficulty != null) - ticks.ForEach(t => t.ApplyDefaults(controlPointInfo, difficulty)); + double tinyTickInterval = tickDistance / length * repeatDuration; + while (tinyTickInterval > 100) + tinyTickInterval /= 2; - return ticks; + for (double t = 0; t < repeatDuration; t += tinyTickInterval) + { + double progress = reversed ? 1 - t / repeatDuration : t / repeatDuration; + + AddNested(new TinyDroplet + { + StartTime = repeatStartTime + t, + ComboColour = ComboColour, + X = Curve.PositionAt(progress).X / CatchPlayfield.BASE_WIDTH, + Samples = new SampleInfoList(Samples.Select(s => new SampleInfo + { + Bank = s.Bank, + Name = @"slidertick", + Volume = s.Volume + })) + }); + } + + AddNested(new Fruit + { + Samples = Samples, + ComboColour = ComboColour, + StartTime = repeatStartTime + repeatDuration, + X = Curve.PositionAt(reversed ? 0 : 1).X / CatchPlayfield.BASE_WIDTH + }); } + } + public double EndTime => StartTime + RepeatCount * Curve.Distance / Velocity; public float EndX => Curve.PositionAt(ProgressAt(1)).X / CatchPlayfield.BASE_WIDTH; diff --git a/osu.Game.Rulesets.Catch/Scoring/CatchScoreProcessor.cs b/osu.Game.Rulesets.Catch/Scoring/CatchScoreProcessor.cs index 0806c4b29d..3826fd1129 100644 --- a/osu.Game.Rulesets.Catch/Scoring/CatchScoreProcessor.cs +++ b/osu.Game.Rulesets.Catch/Scoring/CatchScoreProcessor.cs @@ -1,6 +1,7 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System.Linq; using osu.Game.Beatmaps; using osu.Game.Rulesets.Catch.Judgements; using osu.Game.Rulesets.Catch.Objects; @@ -28,7 +29,7 @@ namespace osu.Game.Rulesets.Catch.Scoring AddJudgement(new CatchJudgement { Result = HitResult.Perfect }); AddJudgement(new CatchJudgement { Result = HitResult.Perfect }); - foreach (var unused in stream.Ticks) + foreach (var unused in stream.NestedHitObjects.OfType()) AddJudgement(new CatchJudgement { Result = HitResult.Perfect }); continue; diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs index 237df72480..7b207ca229 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs @@ -77,7 +77,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables } }); - foreach (var tick in HitObject.Ticks) + foreach (var tick in HitObject.NestedHitObjects.OfType()) { var drawableTick = new DrawableHoldNoteTick(tick) { diff --git a/osu.Game.Rulesets.Mania/Objects/HoldNote.cs b/osu.Game.Rulesets.Mania/Objects/HoldNote.cs index 2a62eaa2ef..f72bed3142 100644 --- a/osu.Game.Rulesets.Mania/Objects/HoldNote.cs +++ b/osu.Game.Rulesets.Mania/Objects/HoldNote.cs @@ -1,7 +1,6 @@ // 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.Beatmaps; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Rulesets.Objects.Types; @@ -63,15 +62,9 @@ namespace osu.Game.Rulesets.Mania.Objects /// private double tickSpacing = 50; - private ControlPointInfo controlPointInfo; - private BeatmapDifficulty difficulty; - - public override void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) + protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) { - base.ApplyDefaults(controlPointInfo, difficulty); - - this.controlPointInfo = controlPointInfo; - this.difficulty = difficulty; + base.ApplyDefaultsToSelf(controlPointInfo, difficulty); TimingControlPoint timingPoint = controlPointInfo.TimingPointAt(StartTime); tickSpacing = timingPoint.BeatLength / difficulty.SliderTickRate; @@ -80,34 +73,27 @@ namespace osu.Game.Rulesets.Mania.Objects Tail.ApplyDefaults(controlPointInfo, difficulty); } - /// - /// The scoring scoring ticks of the hold note. - /// - public IEnumerable Ticks => ticks ?? (ticks = createTicks()); - private List ticks; - - private List createTicks() + protected override void CreateNestedHitObjects() { - var ret = new List(); + base.CreateNestedHitObjects(); + createTicks(); + } + + private void createTicks() + { if (tickSpacing == 0) - return ret; + return; for (double t = StartTime + tickSpacing; t <= EndTime - tickSpacing; t += tickSpacing) { - var tick = new HoldNoteTick + AddNested(new HoldNoteTick { StartTime = t, Column = Column - }; - - if (controlPointInfo != null && difficulty != null) - tick.ApplyDefaults(controlPointInfo, difficulty); - - ret.Add(tick); + }); } - return ret; } /// @@ -121,9 +107,9 @@ namespace osu.Game.Rulesets.Mania.Objects /// private const double release_window_lenience = 1.5; - public override void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) + protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) { - base.ApplyDefaults(controlPointInfo, difficulty); + base.ApplyDefaultsToSelf(controlPointInfo, difficulty); HitWindows *= release_window_lenience; } diff --git a/osu.Game.Rulesets.Mania/Objects/Note.cs b/osu.Game.Rulesets.Mania/Objects/Note.cs index c4d5a13352..51a9a18afa 100644 --- a/osu.Game.Rulesets.Mania/Objects/Note.cs +++ b/osu.Game.Rulesets.Mania/Objects/Note.cs @@ -19,9 +19,9 @@ namespace osu.Game.Rulesets.Mania.Objects [JsonIgnore] public HitWindows HitWindows { get; protected set; } = new HitWindows(); - public override void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) + protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) { - base.ApplyDefaults(controlPointInfo, difficulty); + base.ApplyDefaultsToSelf(controlPointInfo, difficulty); HitWindows = new HitWindows(difficulty.OverallDifficulty); } diff --git a/osu.Game.Rulesets.Mania/Scoring/ManiaScoreProcessor.cs b/osu.Game.Rulesets.Mania/Scoring/ManiaScoreProcessor.cs index 9b8ebe0070..012137f555 100644 --- a/osu.Game.Rulesets.Mania/Scoring/ManiaScoreProcessor.cs +++ b/osu.Game.Rulesets.Mania/Scoring/ManiaScoreProcessor.cs @@ -116,7 +116,7 @@ namespace osu.Game.Rulesets.Mania.Scoring AddJudgement(new ManiaJudgement { Result = HitResult.Perfect }); // Ticks - int tickCount = holdNote.Ticks.Count(); + int tickCount = holdNote.NestedHitObjects.OfType().Count(); for (int i = 0; i < tickCount; i++) AddJudgement(new HoldNoteTickJudgement { Result = HitResult.Perfect }); } diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs index a91d846aa7..57c1ffab00 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs @@ -67,7 +67,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables AddNested(initialCircle); var repeatDuration = s.Curve.Distance / s.Velocity; - foreach (var tick in s.Ticks) + foreach (var tick in s.NestedHitObjects.OfType()) { var repeatStartTime = s.StartTime + tick.RepeatIndex * repeatDuration; var fadeInTime = repeatStartTime + (tick.StartTime - repeatStartTime) / 2 - (tick.RepeatIndex == 0 ? TIME_FADEIN : TIME_FADEIN / 2); @@ -84,7 +84,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables AddNested(drawableTick); } - foreach (var repeatPoint in s.RepeatPoints) + foreach (var repeatPoint in s.NestedHitObjects.OfType()) { var repeatStartTime = s.StartTime + repeatPoint.RepeatIndex * repeatDuration; var fadeInTime = repeatStartTime + (repeatPoint.StartTime - repeatStartTime) / 2 - (repeatPoint.RepeatIndex == 0 ? TIME_FADEIN : TIME_FADEIN / 2); diff --git a/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs b/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs index e6bfd8a277..7532387aa2 100644 --- a/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs +++ b/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs @@ -68,9 +68,9 @@ namespace osu.Game.Rulesets.Osu.Objects return HitResult.Miss; } - public override void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) + protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) { - base.ApplyDefaults(controlPointInfo, difficulty); + base.ApplyDefaultsToSelf(controlPointInfo, difficulty); Scale = (1.0f - 0.7f * (difficulty.CircleSize - 5) / 5) / 2; } diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs index af50667d42..24398c2235 100644 --- a/osu.Game.Rulesets.Osu/Objects/Slider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs @@ -74,15 +74,9 @@ namespace osu.Game.Rulesets.Osu.Objects public double Velocity; public double TickDistance; - private ControlPointInfo controlPointInfo; - private BeatmapDifficulty difficulty; - - public override void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) + protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) { - base.ApplyDefaults(controlPointInfo, difficulty); - - this.controlPointInfo = controlPointInfo; - this.difficulty = difficulty; + base.ApplyDefaultsToSelf(controlPointInfo, difficulty); TimingControlPoint timingPoint = controlPointInfo.TimingPointAt(StartTime); DifficultyControlPoint difficultyPoint = controlPointInfo.DifficultyPointAt(StartTime); @@ -105,85 +99,78 @@ namespace osu.Game.Rulesets.Osu.Objects public int RepeatAt(double progress) => (int)(progress * RepeatCount); - public IEnumerable Ticks + protected override void CreateNestedHitObjects() { - get + base.CreateNestedHitObjects(); + + createTicks(); + createRepeatPoints(); + } + + private void createTicks() + { + if (TickDistance == 0) return; + + var length = Curve.Distance; + var tickDistance = Math.Min(TickDistance, length); + var repeatDuration = length / Velocity; + + var minDistanceFromEnd = Velocity * 0.01; + + for (var repeat = 0; repeat < RepeatCount; repeat++) { - if (TickDistance == 0) yield break; + var repeatStartTime = StartTime + repeat * repeatDuration; + var reversed = repeat % 2 == 1; - var length = Curve.Distance; - var tickDistance = Math.Min(TickDistance, length); - var repeatDuration = length / Velocity; - - var minDistanceFromEnd = Velocity * 0.01; - - for (var repeat = 0; repeat < RepeatCount; repeat++) + for (var d = tickDistance; d <= length; d += tickDistance) { - var repeatStartTime = StartTime + repeat * repeatDuration; - var reversed = repeat % 2 == 1; + if (d > length - minDistanceFromEnd) + break; - for (var d = tickDistance; d <= length; d += tickDistance) + var distanceProgress = d / length; + var timeProgress = reversed ? 1 - distanceProgress : distanceProgress; + + AddNested(new SliderTick { - if (d > length - minDistanceFromEnd) - break; - - var distanceProgress = d / length; - var timeProgress = reversed ? 1 - distanceProgress : distanceProgress; - - var ret = new SliderTick + RepeatIndex = repeat, + StartTime = repeatStartTime + timeProgress * repeatDuration, + Position = Curve.PositionAt(distanceProgress), + StackHeight = StackHeight, + Scale = Scale, + ComboColour = ComboColour, + Samples = new SampleInfoList(Samples.Select(s => new SampleInfo { - RepeatIndex = repeat, - StartTime = repeatStartTime + timeProgress * repeatDuration, - Position = Curve.PositionAt(distanceProgress), - StackHeight = StackHeight, - Scale = Scale, - ComboColour = ComboColour, - Samples = new SampleInfoList(Samples.Select(s => new SampleInfo - { - Bank = s.Bank, - Name = @"slidertick", - Volume = s.Volume - })) - }; - - if (controlPointInfo != null && difficulty != null) - ret.ApplyDefaults(controlPointInfo, difficulty); - - yield return ret; - } + Bank = s.Bank, + Name = @"slidertick", + Volume = s.Volume + })) + }); } } } - public IEnumerable RepeatPoints + + private void createRepeatPoints() { - get + var length = Curve.Distance; + var repeatPointDistance = Math.Min(Distance, length); + var repeatDuration = length / Velocity; + + for (var repeat = 1; repeat < RepeatCount; repeat++) { - var length = Curve.Distance; - var repeatPointDistance = Math.Min(Distance, length); - var repeatDuration = length / Velocity; - - for (var repeat = 1; repeat < RepeatCount; repeat++) + for (var d = repeatPointDistance; d <= length; d += repeatPointDistance) { - for (var d = repeatPointDistance; d <= length; d += repeatPointDistance) + var repeatStartTime = StartTime + repeat * repeatDuration; + var distanceProgress = d / length; + + AddNested(new RepeatPoint { - var repeatStartTime = StartTime + repeat * repeatDuration; - var distanceProgress = d / length; - - var ret = new RepeatPoint - { - RepeatIndex = repeat, - StartTime = repeatStartTime, - Position = Curve.PositionAt(distanceProgress), - StackHeight = StackHeight, - Scale = Scale, - ComboColour = ComboColour, - }; - - if (controlPointInfo != null && difficulty != null) - ret.ApplyDefaults(controlPointInfo, difficulty); - - yield return ret; - } + RepeatIndex = repeat, + StartTime = repeatStartTime, + Position = Curve.PositionAt(distanceProgress), + StackHeight = StackHeight, + Scale = Scale, + ComboColour = ComboColour, + }); } } } diff --git a/osu.Game.Rulesets.Osu/Objects/Spinner.cs b/osu.Game.Rulesets.Osu/Objects/Spinner.cs index c4f5dfe97a..7d1bd9239d 100644 --- a/osu.Game.Rulesets.Osu/Objects/Spinner.cs +++ b/osu.Game.Rulesets.Osu/Objects/Spinner.cs @@ -19,9 +19,9 @@ namespace osu.Game.Rulesets.Osu.Objects public override bool NewCombo => true; - public override void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) + protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) { - base.ApplyDefaults(controlPointInfo, difficulty); + base.ApplyDefaultsToSelf(controlPointInfo, difficulty); SpinsRequired = (int)(Duration / 1000 * BeatmapDifficulty.DifficultyRange(difficulty.OverallDifficulty, 3, 5, 7.5)); diff --git a/osu.Game.Rulesets.Osu/OsuDifficulty/Preprocessing/OsuDifficultyHitObject.cs b/osu.Game.Rulesets.Osu/OsuDifficulty/Preprocessing/OsuDifficultyHitObject.cs index 89821a10fb..11c0df0c8c 100644 --- a/osu.Game.Rulesets.Osu/OsuDifficulty/Preprocessing/OsuDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Osu/OsuDifficulty/Preprocessing/OsuDifficultyHitObject.cs @@ -107,7 +107,7 @@ namespace osu.Game.Rulesets.Osu.OsuDifficulty.Preprocessing } }); - var scoringTimes = slider.Ticks.Select(t => t.StartTime).Concat(slider.RepeatPoints.Select(r => r.StartTime)).OrderBy(t => t); + var scoringTimes = slider.NestedHitObjects.Select(t => t.StartTime); foreach (var time in scoringTimes) computeVertex(time); computeVertex(slider.EndTime); diff --git a/osu.Game.Rulesets.Osu/Scoring/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Scoring/OsuPerformanceCalculator.cs index cd6b6c5e27..2cf321da50 100644 --- a/osu.Game.Rulesets.Osu/Scoring/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Scoring/OsuPerformanceCalculator.cs @@ -33,7 +33,7 @@ namespace osu.Game.Rulesets.Osu.Scoring countHitCircles = Beatmap.HitObjects.Count(h => h is HitCircle); beatmapMaxCombo = Beatmap.HitObjects.Count; - beatmapMaxCombo += Beatmap.HitObjects.OfType().Sum(s => s.RepeatCount + s.Ticks.Count()); + beatmapMaxCombo += Beatmap.HitObjects.OfType().Sum(s => s.NestedHitObjects.Count) + 1; } public override double Calculate(Dictionary categoryRatings = null) diff --git a/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs b/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs index 6e5dd18c46..ad9737af52 100644 --- a/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs +++ b/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs @@ -2,6 +2,7 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System.Collections.Generic; +using System.Linq; using osu.Framework.Extensions; using osu.Game.Beatmaps; using osu.Game.Rulesets.Judgements; @@ -39,11 +40,11 @@ namespace osu.Game.Rulesets.Osu.Scoring AddJudgement(new OsuJudgement { Result = HitResult.Great }); // Ticks - foreach (var unused in slider.Ticks) + foreach (var unused in slider.NestedHitObjects.OfType()) AddJudgement(new OsuJudgement { Result = HitResult.Great }); //Repeats - foreach (var unused in slider.RepeatPoints) + foreach (var unused in slider.NestedHitObjects.OfType()) AddJudgement(new OsuJudgement { Result = HitResult.Great }); } diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs index 2396f3bf91..75e988ced6 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs @@ -43,7 +43,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables RelativeChildSize = new Vector2((float)HitObject.Duration, 1) }); - foreach (var tick in drumRoll.Ticks) + foreach (var tick in drumRoll.NestedHitObjects.OfType()) { var newTick = new DrawableDrumRollTick(tick); newTick.OnJudgement += onTickJudgement; diff --git a/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs b/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs index ff20a16c7b..4104b59979 100644 --- a/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs +++ b/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs @@ -3,7 +3,6 @@ using osu.Game.Rulesets.Objects.Types; using System; -using System.Collections.Generic; using System.Linq; using osu.Game.Audio; using osu.Game.Beatmaps; @@ -37,52 +36,40 @@ namespace osu.Game.Rulesets.Taiko.Objects /// public double RequiredGreatHits { get; protected set; } - /// - /// Total number of drum roll ticks. - /// - public int TotalTicks => Ticks.Count(); - - /// - /// Initializes the drum roll ticks if not initialized and returns them. - /// - public IEnumerable Ticks => ticks ?? (ticks = createTicks()); - - private List ticks; - /// /// The length (in milliseconds) between ticks of this drumroll. /// Half of this value is the hit window of the ticks. /// private double tickSpacing = 100; - private ControlPointInfo controlPointInfo; - private BeatmapDifficulty difficulty; - - public override void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) + protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) { - base.ApplyDefaults(controlPointInfo, difficulty); - this.controlPointInfo = controlPointInfo; - this.difficulty = difficulty; + base.ApplyDefaultsToSelf(controlPointInfo, difficulty); TimingControlPoint timingPoint = controlPointInfo.TimingPointAt(StartTime); tickSpacing = timingPoint.BeatLength / TickRate; - RequiredGoodHits = TotalTicks * Math.Min(0.15, 0.05 + 0.10 / 6 * difficulty.OverallDifficulty); - RequiredGreatHits = TotalTicks * Math.Min(0.30, 0.10 + 0.20 / 6 * difficulty.OverallDifficulty); + RequiredGoodHits = NestedHitObjects.Count * Math.Min(0.15, 0.05 + 0.10 / 6 * difficulty.OverallDifficulty); + RequiredGreatHits = NestedHitObjects.Count * Math.Min(0.30, 0.10 + 0.20 / 6 * difficulty.OverallDifficulty); } - private List createTicks() + protected override void CreateNestedHitObjects() { - var ret = new List(); + base.CreateNestedHitObjects(); + createTicks(); + } + + private void createTicks() + { if (tickSpacing == 0) - return ret; + return; bool first = true; for (double t = StartTime; t < EndTime + tickSpacing / 2; t += tickSpacing) { - var tick = new DrumRollTick + AddNested(new DrumRollTick { FirstTick = first, TickSpacing = tickSpacing, @@ -94,16 +81,10 @@ namespace osu.Game.Rulesets.Taiko.Objects Name = @"slidertick", Volume = s.Volume })) - }; + }); - if (controlPointInfo != null && difficulty != null) - tick.ApplyDefaults(controlPointInfo, difficulty); - - ret.Add(tick); first = false; } - - return ret; } } } diff --git a/osu.Game.Rulesets.Taiko/Objects/Hit.cs b/osu.Game.Rulesets.Taiko/Objects/Hit.cs index 03b9be4157..1b9b44fd99 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Hit.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Hit.cs @@ -23,9 +23,9 @@ namespace osu.Game.Rulesets.Taiko.Objects /// public double HitWindowMiss = 95; - public override void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) + protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) { - base.ApplyDefaults(controlPointInfo, difficulty); + base.ApplyDefaultsToSelf(controlPointInfo, difficulty); HitWindowGreat = BeatmapDifficulty.DifficultyRange(difficulty.OverallDifficulty, 50, 35, 20); HitWindowGood = BeatmapDifficulty.DifficultyRange(difficulty.OverallDifficulty, 120, 80, 50); diff --git a/osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs b/osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs index c3e5597f43..df1a19267f 100644 --- a/osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs +++ b/osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Linq; using osu.Game.Beatmaps; using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Taiko.Objects; @@ -83,7 +84,7 @@ namespace osu.Game.Rulesets.Taiko.Replays } else if (drumRoll != null) { - foreach (var tick in drumRoll.Ticks) + foreach (var tick in drumRoll.NestedHitObjects.OfType()) { Frames.Add(new ReplayFrame(tick.StartTime, null, null, hitButton ? ReplayButtonState.Left1 : ReplayButtonState.Left2)); hitButton = !hitButton; diff --git a/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs b/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs index 0048566b15..df9ce5e2eb 100644 --- a/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs +++ b/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs @@ -1,6 +1,7 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System.Linq; using osu.Game.Beatmaps; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Objects.Drawables; @@ -88,7 +89,7 @@ namespace osu.Game.Rulesets.Taiko.Scoring } else if (obj is DrumRoll) { - for (int i = 0; i < ((DrumRoll)obj).TotalTicks; i++) + for (int i = 0; i < ((DrumRoll)obj).NestedHitObjects.OfType().Count(); i++) { AddJudgement(new TaikoDrumRollTickJudgement { Result = HitResult.Great }); diff --git a/osu.Game/Rulesets/Objects/HitObject.cs b/osu.Game/Rulesets/Objects/HitObject.cs index 66e34eac32..9e331dfea9 100644 --- a/osu.Game/Rulesets/Objects/HitObject.cs +++ b/osu.Game/Rulesets/Objects/HitObject.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 System.Collections.Generic; using Newtonsoft.Json; +using osu.Framework.Extensions.IEnumerableExtensions; +using osu.Framework.Lists; using osu.Game.Audio; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; @@ -40,12 +43,26 @@ namespace osu.Game.Rulesets.Objects [JsonIgnore] public bool Kiai { get; private set; } + private readonly SortedList nestedHitObjects = new SortedList((h1, h2) => h1.StartTime.CompareTo(h2.StartTime)); + + [JsonIgnore] + public IReadOnlyList NestedHitObjects => nestedHitObjects; + /// /// Applies default values to this HitObject. /// /// The control points. /// The difficulty settings to use. - public virtual void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) + public void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) + { + ApplyDefaultsToSelf(controlPointInfo, difficulty); + + nestedHitObjects.Clear(); + CreateNestedHitObjects(); + nestedHitObjects.ForEach(h => h.ApplyDefaults(controlPointInfo, difficulty)); + } + + protected virtual void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) { SoundControlPoint soundPoint = controlPointInfo.SoundPointAt(StartTime); EffectControlPoint effectPoint = controlPointInfo.EffectPointAt(StartTime); @@ -53,5 +70,11 @@ namespace osu.Game.Rulesets.Objects Kiai = effectPoint.KiaiMode; SoundControlPoint = soundPoint; } + + protected virtual void CreateNestedHitObjects() + { + } + + protected void AddNested(HitObject hitObject) => nestedHitObjects.Add(hitObject); } } diff --git a/osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs b/osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs index 479cacc52b..698b74cc28 100644 --- a/osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs +++ b/osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs @@ -46,9 +46,9 @@ namespace osu.Game.Rulesets.Objects.Legacy throw new NotImplementedException(); } - public override void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) + protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) { - base.ApplyDefaults(controlPointInfo, difficulty); + base.ApplyDefaultsToSelf(controlPointInfo, difficulty); TimingControlPoint timingPoint = controlPointInfo.TimingPointAt(StartTime); DifficultyControlPoint difficultyPoint = controlPointInfo.DifficultyPointAt(StartTime); From d54b74e13a8ed2d8d5230f611870b2853dea7607 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 22 Dec 2017 21:44:12 +0900 Subject: [PATCH 066/122] Update framework --- osu-framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu-framework b/osu-framework index 675745afa1..08f85f9bf9 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 675745afa19c0ceaa96a43edf76ee295ba394c61 +Subproject commit 08f85f9bf9a7376aec8dfcde8c7c96d267d8c295 From def2e5bd179857d2c56a41a056c2a23a385a8437 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 22 Dec 2017 22:15:22 +0900 Subject: [PATCH 067/122] Make editor discard approach circles Temporary solution for now. --- osu.Game.Rulesets.Osu/Edit/OsuEditPlayfield.cs | 2 ++ osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs | 6 +++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Edit/OsuEditPlayfield.cs b/osu.Game.Rulesets.Osu/Edit/OsuEditPlayfield.cs index d5fc1b606b..0d7fa6c334 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuEditPlayfield.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuEditPlayfield.cs @@ -9,5 +9,7 @@ namespace osu.Game.Rulesets.Osu.Edit public class OsuEditPlayfield : OsuPlayfield { protected override CursorContainer CreateCursor() => null; + + protected override bool ProxyApproachCircles => false; } } diff --git a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs index f03acb2fa0..0dc6feee75 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs @@ -25,6 +25,10 @@ namespace osu.Game.Rulesets.Osu.UI public override bool ProvidingUserCursor => true; + // Todo: This should not be a thing, but is currently required for the editor + // https://github.com/ppy/osu-framework/issues/1283 + protected virtual bool ProxyApproachCircles => true; + public static readonly Vector2 BASE_SIZE = new Vector2(512, 384); public override Vector2 Size @@ -80,7 +84,7 @@ namespace osu.Game.Rulesets.Osu.UI h.Depth = (float)h.HitObject.StartTime; var c = h as IDrawableHitObjectWithProxiedApproach; - if (c != null) + if (c != null && ProxyApproachCircles) approachCircles.Add(c.ProxiedLayer.CreateProxy()); base.Add(h); From 2313ff0ddbe0b04c04beda6fe4df5947ec32711f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 22 Dec 2017 22:19:11 +0900 Subject: [PATCH 068/122] Fix beatmap info wedge not showing up when zero beatmaps are loaded Closes #1722. --- osu.Game/Screens/Select/BeatmapCarousel.cs | 2 +- osu.Game/Screens/Select/BeatmapInfoWedge.cs | 2 ++ osu.Game/Screens/Select/SongSelect.cs | 1 - 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index ff1dd95eac..e0fcba5b3c 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -509,7 +509,7 @@ namespace osu.Game.Screens.Select currentY += DrawHeight / 2; scrollableContent.Height = currentY; - if (selectedBeatmapSet != null && selectedBeatmapSet.State.Value != CarouselItemState.Selected) + if (selectedBeatmapSet == null || selectedBeatmapSet.State.Value != CarouselItemState.Selected) { selectedBeatmapSet = null; SelectionChanged?.Invoke(null); diff --git a/osu.Game/Screens/Select/BeatmapInfoWedge.cs b/osu.Game/Screens/Select/BeatmapInfoWedge.cs index 3ef6ceeaeb..1baacb78ee 100644 --- a/osu.Game/Screens/Select/BeatmapInfoWedge.cs +++ b/osu.Game/Screens/Select/BeatmapInfoWedge.cs @@ -66,6 +66,8 @@ namespace osu.Game.Screens.Select Depth = info?.Depth + 1 ?? 0, }, newInfo => { + State = beatmap == null ? Visibility.Hidden : Visibility.Visible; + // ensure we ourselves are visible if not already. if (!IsPresent) this.FadeIn(250); diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 68ee08e721..9a7dbf002e 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -399,7 +399,6 @@ namespace osu.Game.Screens.Select backgroundModeBeatmap.FadeTo(1, 250); } - beatmapInfoWedge.State = Visibility.Visible; beatmapInfoWedge.UpdateBeatmap(beatmap); } From 26bb3715fecd3ca4e3f43e77ad7fc6075e7f4f1f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 22 Dec 2017 22:41:18 +0900 Subject: [PATCH 069/122] Improve state and feel of leaderboard placeholders Closes #1721. --- .../Select/Leaderboards/Leaderboard.cs | 52 ++++++++++--------- 1 file changed, 28 insertions(+), 24 deletions(-) diff --git a/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs b/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs index b3f2649ab6..4b5eefe5b6 100644 --- a/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs +++ b/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs @@ -29,7 +29,7 @@ namespace osu.Game.Screens.Select.Leaderboards { public class Leaderboard : Container { - private const double fade_duration = 200; + private const double fade_duration = 300; private readonly ScrollContainer scrollContainer; private readonly Container placeholderContainer; @@ -51,7 +51,7 @@ namespace osu.Game.Screens.Select.Leaderboards { scores = value; - scrollFlow?.FadeOut(fade_duration).Expire(); + scrollFlow?.FadeOut(fade_duration, Easing.OutQuint).Expire(); scrollFlow = null; loading.Hide(); @@ -90,6 +90,7 @@ namespace osu.Game.Screens.Select.Leaderboards } private LeaderboardScope scope; + public LeaderboardScope Scope { get { return scope; } @@ -103,6 +104,7 @@ namespace osu.Game.Screens.Select.Leaderboards } private PlaceholderState placeholderState; + protected PlaceholderState PlaceholderState { get { return placeholderState; } @@ -118,19 +120,18 @@ namespace osu.Game.Screens.Select.Leaderboards OnRetry = updateScores, }); break; - + case PlaceholderState.Unavailable: + replacePlaceholder(new MessagePlaceholder(@"Leaderboards are not available for this beatmap!")); + break; case PlaceholderState.NoScores: replacePlaceholder(new MessagePlaceholder(@"No records yet!")); break; - case PlaceholderState.NotLoggedIn: replacePlaceholder(new MessagePlaceholder(@"Please login to view online leaderboards!")); break; - case PlaceholderState.NotSupporter: replacePlaceholder(new MessagePlaceholder(@"Please invest in a supporter tag to view this leaderboard!")); break; - default: replacePlaceholder(null); break; @@ -150,10 +151,7 @@ namespace osu.Game.Screens.Select.Leaderboards loading = new LoadingAnimation(), placeholderContainer = new Container { - Alpha = 0, - AutoSizeAxes = Axes.Both, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both }, }; } @@ -229,15 +227,15 @@ namespace osu.Game.Screens.Select.Leaderboards return; } - if (api?.IsLoggedIn != true) + if (Beatmap?.OnlineBeatmapID == null) { - PlaceholderState = PlaceholderState.NotLoggedIn; + PlaceholderState = PlaceholderState.Unavailable; return; } - if (Beatmap?.OnlineBeatmapID == null) + if (api?.IsLoggedIn != true) { - PlaceholderState = PlaceholderState.NetworkFailure; + PlaceholderState = PlaceholderState.NotLoggedIn; return; } @@ -272,23 +270,22 @@ namespace osu.Game.Screens.Select.Leaderboards private void replacePlaceholder(Placeholder placeholder) { - if (placeholder == null) - { - placeholderContainer.FadeOutFromOne(fade_duration, Easing.OutQuint); - placeholderContainer.Clear(true); + var existingPlaceholder = placeholderContainer.Children.LastOrDefault() as Placeholder; + + if (placeholder != null && placeholder.Equals(existingPlaceholder)) return; - } - var existingPlaceholder = placeholderContainer.Children.FirstOrDefault() as Placeholder; + existingPlaceholder?.FadeOut(150, Easing.OutQuint).Expire(); - if (placeholder.Equals(existingPlaceholder)) + if (placeholder == null) return; Scores = null; - placeholderContainer.Clear(true); - placeholderContainer.Child = placeholder; - placeholderContainer.FadeInFromZero(fade_duration, Easing.OutQuint); + placeholderContainer.Add(placeholder); + + placeholder.ScaleTo(0.8f).Then().ScaleTo(1, fade_duration * 3, Easing.OutQuint); + placeholder.FadeInFromZero(fade_duration, Easing.OutQuint); } protected override void Update() @@ -322,6 +319,12 @@ namespace osu.Game.Screens.Select.Leaderboards private abstract class Placeholder : FillFlowContainer, IEquatable { + protected Placeholder() + { + Anchor = Anchor.Centre; + Origin = Anchor.Centre; + } + public virtual bool Equals(Placeholder other) => GetType() == other?.GetType(); } @@ -429,6 +432,7 @@ namespace osu.Game.Screens.Select.Leaderboards Successful, Retrieving, NetworkFailure, + Unavailable, NoScores, NotLoggedIn, NotSupporter, From bdda1570d1540148ee31f16107897fbb3359ef11 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 22 Dec 2017 22:44:18 +0900 Subject: [PATCH 070/122] Move Placeholder classes to own files --- .../Select/Leaderboards/Leaderboard.cs | 106 ------------------ .../Select/Leaderboards/MessagePlaceholder.cs | 38 +++++++ .../Select/Leaderboards/Placeholder.cs | 20 ++++ .../RetrievalFailurePlaceholder.cs | 77 +++++++++++++ osu.Game/osu.Game.csproj | 3 + 5 files changed, 138 insertions(+), 106 deletions(-) create mode 100644 osu.Game/Screens/Select/Leaderboards/MessagePlaceholder.cs create mode 100644 osu.Game/Screens/Select/Leaderboards/Placeholder.cs create mode 100644 osu.Game/Screens/Select/Leaderboards/RetrievalFailurePlaceholder.cs diff --git a/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs b/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs index 4b5eefe5b6..c15a179e8c 100644 --- a/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs +++ b/osu.Game/Screens/Select/Leaderboards/Leaderboard.cs @@ -19,11 +19,8 @@ using osu.Game.Online.API; using osu.Game.Online.API.Requests; using System.Linq; using osu.Framework.Configuration; -using osu.Game.Graphics.Sprites; -using osu.Game.Graphics; using osu.Framework.Logging; using osu.Game.Rulesets; -using osu.Framework.Input; namespace osu.Game.Screens.Select.Leaderboards { @@ -157,9 +154,7 @@ namespace osu.Game.Screens.Select.Leaderboards } private APIAccess api; - private BeatmapInfo beatmap; - private OsuGame osuGame; private ScheduledDelegate pendingBeatmapSwitch; @@ -316,107 +311,6 @@ namespace osu.Game.Screens.Select.Leaderboards } } } - - private abstract class Placeholder : FillFlowContainer, IEquatable - { - protected Placeholder() - { - Anchor = Anchor.Centre; - Origin = Anchor.Centre; - } - - public virtual bool Equals(Placeholder other) => GetType() == other?.GetType(); - } - - private class MessagePlaceholder : Placeholder - { - private readonly string message; - - public MessagePlaceholder(string message) - { - Direction = FillDirection.Horizontal; - AutoSizeAxes = Axes.Both; - Children = new Drawable[] - { - new SpriteIcon - { - Icon = FontAwesome.fa_exclamation_circle, - Size = new Vector2(26), - Margin = new MarginPadding { Right = 10 }, - }, - new OsuSpriteText - { - Text = this.message = message, - TextSize = 22, - }, - }; - } - - public override bool Equals(Placeholder other) => (other as MessagePlaceholder)?.message == message; - } - - private class RetrievalFailurePlaceholder : Placeholder - { - public Action OnRetry; - - public RetrievalFailurePlaceholder() - { - Direction = FillDirection.Horizontal; - AutoSizeAxes = Axes.Both; - Children = new Drawable[] - { - new RetryButton - { - Action = () => OnRetry?.Invoke(), - Margin = new MarginPadding { Right = 10 }, - }, - new OsuSpriteText - { - Anchor = Anchor.TopLeft, - Text = @"Couldn't retrieve scores!", - TextSize = 22, - }, - }; - } - - private class RetryButton : OsuHoverContainer - { - private readonly SpriteIcon icon; - - public Action Action; - - public RetryButton() - { - Height = 26; - Width = 26; - Child = new OsuClickableContainer - { - AutoSizeAxes = Axes.Both, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Action = () => Action?.Invoke(), - Child = icon = new SpriteIcon - { - Icon = FontAwesome.fa_refresh, - Size = new Vector2(26), - Shadow = true, - }, - }; - } - - protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) - { - icon.ScaleTo(0.8f, 4000, Easing.OutQuint); - return base.OnMouseDown(state, args); - } - - protected override bool OnMouseUp(InputState state, MouseUpEventArgs args) - { - icon.ScaleTo(1, 1000, Easing.OutElastic); - return base.OnMouseUp(state, args); - } - } - } } public enum LeaderboardScope diff --git a/osu.Game/Screens/Select/Leaderboards/MessagePlaceholder.cs b/osu.Game/Screens/Select/Leaderboards/MessagePlaceholder.cs new file mode 100644 index 0000000000..4f94087d30 --- /dev/null +++ b/osu.Game/Screens/Select/Leaderboards/MessagePlaceholder.cs @@ -0,0 +1,38 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using OpenTK; + +namespace osu.Game.Screens.Select.Leaderboards +{ + public class MessagePlaceholder : Placeholder + { + private readonly string message; + + public MessagePlaceholder(string message) + { + Direction = FillDirection.Horizontal; + AutoSizeAxes = Axes.Both; + Children = new Drawable[] + { + new SpriteIcon + { + Icon = FontAwesome.fa_exclamation_circle, + Size = new Vector2(26), + Margin = new MarginPadding { Right = 10 }, + }, + new OsuSpriteText + { + Text = this.message = message, + TextSize = 22, + }, + }; + } + + public override bool Equals(Placeholder other) => (other as MessagePlaceholder)?.message == message; + } +} diff --git a/osu.Game/Screens/Select/Leaderboards/Placeholder.cs b/osu.Game/Screens/Select/Leaderboards/Placeholder.cs new file mode 100644 index 0000000000..8427259106 --- /dev/null +++ b/osu.Game/Screens/Select/Leaderboards/Placeholder.cs @@ -0,0 +1,20 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; + +namespace osu.Game.Screens.Select.Leaderboards +{ + public abstract class Placeholder : FillFlowContainer, IEquatable + { + protected Placeholder() + { + Anchor = Anchor.Centre; + Origin = Anchor.Centre; + } + + public virtual bool Equals(Placeholder other) => GetType() == other?.GetType(); + } +} diff --git a/osu.Game/Screens/Select/Leaderboards/RetrievalFailurePlaceholder.cs b/osu.Game/Screens/Select/Leaderboards/RetrievalFailurePlaceholder.cs new file mode 100644 index 0000000000..7563c08c8b --- /dev/null +++ b/osu.Game/Screens/Select/Leaderboards/RetrievalFailurePlaceholder.cs @@ -0,0 +1,77 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Input; +using osu.Game.Graphics; +using osu.Game.Graphics.Containers; +using osu.Game.Graphics.Sprites; +using OpenTK; + +namespace osu.Game.Screens.Select.Leaderboards +{ + public class RetrievalFailurePlaceholder : Placeholder + { + public Action OnRetry; + + public RetrievalFailurePlaceholder() + { + Direction = FillDirection.Horizontal; + AutoSizeAxes = Axes.Both; + Children = new Drawable[] + { + new RetryButton + { + Action = () => OnRetry?.Invoke(), + Margin = new MarginPadding { Right = 10 }, + }, + new OsuSpriteText + { + Anchor = Anchor.TopLeft, + Text = @"Couldn't retrieve scores!", + TextSize = 22, + }, + }; + } + + public class RetryButton : OsuHoverContainer + { + private readonly SpriteIcon icon; + + public Action Action; + + public RetryButton() + { + Height = 26; + Width = 26; + Child = new OsuClickableContainer + { + AutoSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Action = () => Action?.Invoke(), + Child = icon = new SpriteIcon + { + Icon = FontAwesome.fa_refresh, + Size = new Vector2(26), + Shadow = true, + }, + }; + } + + protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) + { + icon.ScaleTo(0.8f, 4000, Easing.OutQuint); + return base.OnMouseDown(state, args); + } + + protected override bool OnMouseUp(InputState state, MouseUpEventArgs args) + { + icon.ScaleTo(1, 1000, Easing.OutElastic); + return base.OnMouseUp(state, args); + } + } + } +} diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 1004d9dc95..1c78ba379e 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -781,6 +781,9 @@ + + + From ff0927e71b417d7a1e88a078e4c36ea82bacf7db Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 23 Dec 2017 16:23:33 +0900 Subject: [PATCH 071/122] Remove unnecessary newline --- osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index b8eba80a70..4f5f8898f8 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -71,7 +71,6 @@ namespace osu.Game.Rulesets.Objects.Drawables private readonly List judgements = new List(); public IReadOnlyList Judgements => judgements; - protected List Samples = new List(); public readonly Bindable State = new Bindable(); From 5026c7a95e4dc653e556e6d6da129a312a973941 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 23 Dec 2017 16:31:45 +0900 Subject: [PATCH 072/122] SoundControlPoint -> SampleControlPoint --- .../Objects/Drawables/DrawableSlider.cs | 2 +- osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs | 10 +++++----- .../Beatmaps/Formats/LegacyBeatmapDecoderTest.cs | 4 ++-- osu.Game.Tests/Visual/TestCaseEditorSummaryTimeline.cs | 2 +- osu.Game/Audio/SampleInfo.cs | 6 +++--- osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs | 4 ++-- .../{SoundControlPoint.cs => SampleControlPoint.cs} | 2 +- osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs | 6 +++--- .../Rulesets/Objects/Drawables/DrawableHitObject.cs | 8 ++++---- osu.Game/Rulesets/Objects/HitObject.cs | 6 +++--- .../Timelines/Summary/Parts/ControlPointPart.cs | 2 +- osu.Game/osu.Game.csproj | 2 +- 12 files changed, 27 insertions(+), 27 deletions(-) rename osu.Game/Beatmaps/ControlPoints/{SoundControlPoint.cs => SampleControlPoint.cs} (88%) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs index 57c1ffab00..befe84e3e9 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs @@ -57,7 +57,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables Scale = s.Scale, ComboColour = s.ComboColour, Samples = s.Samples, - SoundControlPoint = s.SoundControlPoint + SampleControlPoint = s.SampleControlPoint }) }; diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs index 549c59cba1..864b0f0ca4 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs @@ -208,11 +208,11 @@ namespace osu.Game.Rulesets.Taiko.UI private void load(OsuColour colours, AudioManager audio) { allSamples = new Dictionary>(); - foreach (var soundPoint in controlPointInfo.SoundPoints) + foreach (var s in controlPointInfo.SamplePoints) { - var normalSample = SampleInfo.FromSoundPoint(soundPoint).GetChannel(audio.Sample); - var clapSample = SampleInfo.FromSoundPoint(soundPoint, SampleInfo.HIT_CLAP).GetChannel(audio.Sample); - allSamples.Add(soundPoint.Time, new Tuple(normalSample, clapSample)); + var normalSample = SampleInfo.FromSoundPoint(s).GetChannel(audio.Sample); + var clapSample = SampleInfo.FromSoundPoint(s, SampleInfo.HIT_CLAP).GetChannel(audio.Sample); + allSamples.Add(s.Time, new Tuple(normalSample, clapSample)); } overlayBackgroundContainer.BorderColour = colours.Gray0; @@ -281,7 +281,7 @@ namespace osu.Game.Rulesets.Taiko.UI public bool OnPressed(TaikoAction action) { var currentTime = Clock.CurrentTime; - var soundPoint = currentTime < controlPointInfo.SoundPoints[0].Time ? controlPointInfo.SoundPoints[0] : controlPointInfo.SoundPointAt(currentTime); + var soundPoint = currentTime < controlPointInfo.SamplePoints[0].Time ? controlPointInfo.SamplePoints[0] : controlPointInfo.SamplePointAt(currentTime); if (!allSamples.TryGetValue(soundPoint.Time, out Tuple samples)) throw new InvalidOperationException("Current sample set not found."); diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs index 86413af4b6..d3e7958ec1 100644 --- a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs @@ -146,8 +146,8 @@ namespace osu.Game.Tests.Beatmaps.Formats Assert.AreEqual(116999, difficultyPoint.Time); Assert.AreEqual(0.75000000000000189d, difficultyPoint.SpeedMultiplier); - Assert.AreEqual(34, controlPoints.SoundPoints.Count); - var soundPoint = controlPoints.SoundPoints[0]; + Assert.AreEqual(34, controlPoints.SamplePoints.Count); + var soundPoint = controlPoints.SamplePoints[0]; Assert.AreEqual(956, soundPoint.Time); Assert.AreEqual("soft", soundPoint.SampleBank); Assert.AreEqual(60, soundPoint.SampleVolume); diff --git a/osu.Game.Tests/Visual/TestCaseEditorSummaryTimeline.cs b/osu.Game.Tests/Visual/TestCaseEditorSummaryTimeline.cs index 01371ad78c..ef7404ad49 100644 --- a/osu.Game.Tests/Visual/TestCaseEditorSummaryTimeline.cs +++ b/osu.Game.Tests/Visual/TestCaseEditorSummaryTimeline.cs @@ -56,7 +56,7 @@ namespace osu.Game.Tests.Visual b.ControlPointInfo.EffectPoints.Add(new EffectControlPoint { Time = random.Next(0, length) }); for (int i = 0; i < random.Next(1, 5); i++) - b.ControlPointInfo.SoundPoints.Add(new SoundControlPoint { Time = random.Next(0, length) }); + b.ControlPointInfo.SamplePoints.Add(new SampleControlPoint { Time = random.Next(0, length) }); b.BeatmapInfo.Bookmarks = new int[random.Next(10, 30)]; for (int i = 0; i < b.BeatmapInfo.Bookmarks.Length; i++) diff --git a/osu.Game/Audio/SampleInfo.cs b/osu.Game/Audio/SampleInfo.cs index 3003339ca2..6a95721bd0 100644 --- a/osu.Game/Audio/SampleInfo.cs +++ b/osu.Game/Audio/SampleInfo.cs @@ -17,13 +17,13 @@ namespace osu.Game.Audio public const string HIT_NORMAL = @"hitnormal"; public const string HIT_CLAP = @"hitclap"; - public static SampleInfo FromSoundPoint(SoundControlPoint soundPoint, string sampleName = HIT_NORMAL) + public static SampleInfo FromSoundPoint(SampleControlPoint samplePoint, string sampleName = HIT_NORMAL) { return new SampleInfo { - Bank = soundPoint.SampleBank, + Bank = samplePoint.SampleBank, Name = sampleName, - Volume = soundPoint.SampleVolume, + Volume = samplePoint.SampleVolume, }; } diff --git a/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs b/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs index 64b9b837b6..e8ec6595bd 100644 --- a/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs +++ b/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs @@ -28,7 +28,7 @@ namespace osu.Game.Beatmaps.ControlPoints /// All sound points. /// [JsonProperty] - public SortedList SoundPoints { get; private set; } = new SortedList(Comparer.Default); + public SortedList SamplePoints { get; private set; } = new SortedList(Comparer.Default); /// /// All effect points. @@ -55,7 +55,7 @@ namespace osu.Game.Beatmaps.ControlPoints /// /// The time to find the sound control point at. /// The sound control point. - public SoundControlPoint SoundPointAt(double time) => binarySearch(SoundPoints, time); + public SampleControlPoint SamplePointAt(double time) => binarySearch(SamplePoints, time); /// /// Finds the timing control point that is active at . diff --git a/osu.Game/Beatmaps/ControlPoints/SoundControlPoint.cs b/osu.Game/Beatmaps/ControlPoints/SampleControlPoint.cs similarity index 88% rename from osu.Game/Beatmaps/ControlPoints/SoundControlPoint.cs rename to osu.Game/Beatmaps/ControlPoints/SampleControlPoint.cs index b73a03b95a..e3d6eede44 100644 --- a/osu.Game/Beatmaps/ControlPoints/SoundControlPoint.cs +++ b/osu.Game/Beatmaps/ControlPoints/SampleControlPoint.cs @@ -3,7 +3,7 @@ namespace osu.Game.Beatmaps.ControlPoints { - public class SoundControlPoint : ControlPoint + public class SampleControlPoint : ControlPoint { public const string DEFAULT_BANK = "normal"; diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs index b7004dd3eb..ea29e480ec 100644 --- a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs @@ -313,7 +313,7 @@ namespace osu.Game.Beatmaps.Formats stringSampleSet = @"normal"; DifficultyControlPoint difficultyPoint = beatmap.ControlPointInfo.DifficultyPointAt(time); - SoundControlPoint soundPoint = beatmap.ControlPointInfo.SoundPointAt(time); + SampleControlPoint samplePoint = beatmap.ControlPointInfo.SamplePointAt(time); EffectControlPoint effectPoint = beatmap.ControlPointInfo.EffectPointAt(time); if (timingChange) @@ -336,9 +336,9 @@ namespace osu.Game.Beatmaps.Formats }); } - if (stringSampleSet != soundPoint.SampleBank || sampleVolume != soundPoint.SampleVolume) + if (stringSampleSet != samplePoint.SampleBank || sampleVolume != samplePoint.SampleVolume) { - beatmap.ControlPointInfo.SoundPoints.Add(new SoundControlPoint + beatmap.ControlPointInfo.SamplePoints.Add(new SampleControlPoint { Time = time, SampleBank = stringSampleSet, diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index 4f5f8898f8..8cfdda0413 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -86,16 +86,16 @@ namespace osu.Game.Rulesets.Objects.Drawables { foreach (SampleInfo sample in HitObject.Samples) { - if (HitObject.SoundControlPoint == null) - throw new ArgumentNullException(nameof(HitObject.SoundControlPoint), $"{nameof(HitObject)} must always have an attached {nameof(HitObject.SoundControlPoint)}."); + if (HitObject.SampleControlPoint == null) + throw new ArgumentNullException(nameof(HitObject.SampleControlPoint), $"{nameof(HitObject)} must always have an attached {nameof(HitObject.SampleControlPoint)}."); var bank = sample.Bank; if (string.IsNullOrEmpty(bank)) - bank = HitObject.SoundControlPoint.SampleBank; + bank = HitObject.SampleControlPoint.SampleBank; int volume = sample.Volume; if (volume == 0) - volume = HitObject.SoundControlPoint.SampleVolume; + volume = HitObject.SampleControlPoint.SampleVolume; SampleChannel channel = audio.Sample.Get($@"Gameplay/{bank}-{sample.Name}"); diff --git a/osu.Game/Rulesets/Objects/HitObject.cs b/osu.Game/Rulesets/Objects/HitObject.cs index 9e331dfea9..5ecba7456e 100644 --- a/osu.Game/Rulesets/Objects/HitObject.cs +++ b/osu.Game/Rulesets/Objects/HitObject.cs @@ -35,7 +35,7 @@ namespace osu.Game.Rulesets.Objects public SampleInfoList Samples = new SampleInfoList(); [JsonIgnore] - public SoundControlPoint SoundControlPoint; + public SampleControlPoint SampleControlPoint; /// /// Whether this is in Kiai time. @@ -64,11 +64,11 @@ namespace osu.Game.Rulesets.Objects protected virtual void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) { - SoundControlPoint soundPoint = controlPointInfo.SoundPointAt(StartTime); + SampleControlPoint samplePoint = controlPointInfo.SamplePointAt(StartTime); EffectControlPoint effectPoint = controlPointInfo.EffectPointAt(StartTime); Kiai = effectPoint.KiaiMode; - SoundControlPoint = soundPoint; + SampleControlPoint = samplePoint; } protected virtual void CreateNestedHitObjects() diff --git a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/ControlPointPart.cs b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/ControlPointPart.cs index 405befb80a..3759470c9a 100644 --- a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/ControlPointPart.cs +++ b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/ControlPointPart.cs @@ -25,7 +25,7 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts cpi.TimingPoints.ForEach(addTimingPoint); // Consider all non-timing points as the same type - cpi.SoundPoints.Select(c => (ControlPoint)c) + cpi.SamplePoints.Select(c => (ControlPoint)c) .Concat(cpi.EffectPoints) .Concat(cpi.DifficultyPoints) .Distinct() diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index e78d10cc4f..f9e67623a3 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -258,7 +258,7 @@ - + From 9ca03c02091a8700776c2eeeeac44dc337f30dea Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 23 Dec 2017 16:46:02 +0900 Subject: [PATCH 073/122] Simplify and tidy sample retrieval Less static weirdness --- osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs | 19 ++++++++++--------- osu.Game/Audio/SampleInfo.cs | 11 ----------- .../ControlPoints/ControlPointInfo.cs | 2 +- .../ControlPoints/SampleControlPoint.cs | 14 ++++++++++++++ 4 files changed, 25 insertions(+), 21 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs index 864b0f0ca4..44c7bdb547 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs @@ -62,7 +62,7 @@ namespace osu.Game.Rulesets.Taiko.UI private readonly Box background; private readonly ControlPointInfo controlPointInfo; - private Dictionary> allSamples; + private Dictionary> drumSampleMappings; public TaikoPlayfield(ControlPointInfo controlPointInfo) : base(Axes.X) @@ -207,12 +207,12 @@ namespace osu.Game.Rulesets.Taiko.UI [BackgroundDependencyLoader] private void load(OsuColour colours, AudioManager audio) { - allSamples = new Dictionary>(); + drumSampleMappings = new Dictionary>(); foreach (var s in controlPointInfo.SamplePoints) { - var normalSample = SampleInfo.FromSoundPoint(s).GetChannel(audio.Sample); - var clapSample = SampleInfo.FromSoundPoint(s, SampleInfo.HIT_CLAP).GetChannel(audio.Sample); - allSamples.Add(s.Time, new Tuple(normalSample, clapSample)); + var normalSample = s.GetSampleInfo().GetChannel(audio.Sample); + var clapSample = s.GetSampleInfo(SampleInfo.HIT_CLAP).GetChannel(audio.Sample); + drumSampleMappings.Add(s, new Tuple(normalSample, clapSample)); } overlayBackgroundContainer.BorderColour = colours.Gray0; @@ -268,7 +268,9 @@ namespace osu.Game.Rulesets.Taiko.UI { topLevelHitContainer.Add(judgedObject.CreateProxy()); } - catch { } + catch + { + } } hitExplosionContainer.Add(new HitExplosion(judgedObject, isRim)); @@ -280,10 +282,9 @@ namespace osu.Game.Rulesets.Taiko.UI public bool OnPressed(TaikoAction action) { - var currentTime = Clock.CurrentTime; - var soundPoint = currentTime < controlPointInfo.SamplePoints[0].Time ? controlPointInfo.SamplePoints[0] : controlPointInfo.SamplePointAt(currentTime); + var samplePoint = controlPointInfo.SamplePointAt(Clock.CurrentTime); - if (!allSamples.TryGetValue(soundPoint.Time, out Tuple samples)) + if (!drumSampleMappings.TryGetValue(samplePoint, out var samples)) throw new InvalidOperationException("Current sample set not found."); if (action == TaikoAction.LeftCentre || action == TaikoAction.RightCentre) diff --git a/osu.Game/Audio/SampleInfo.cs b/osu.Game/Audio/SampleInfo.cs index 6a95721bd0..566813dd44 100644 --- a/osu.Game/Audio/SampleInfo.cs +++ b/osu.Game/Audio/SampleInfo.cs @@ -5,7 +5,6 @@ using System; using osu.Framework.Audio; using osu.Framework.Audio.Sample; using osu.Framework.Configuration; -using osu.Game.Beatmaps.ControlPoints; namespace osu.Game.Audio { @@ -17,16 +16,6 @@ namespace osu.Game.Audio public const string HIT_NORMAL = @"hitnormal"; public const string HIT_CLAP = @"hitclap"; - public static SampleInfo FromSoundPoint(SampleControlPoint samplePoint, string sampleName = HIT_NORMAL) - { - return new SampleInfo - { - Bank = samplePoint.SampleBank, - Name = sampleName, - Volume = samplePoint.SampleVolume, - }; - } - public SampleChannel GetChannel(SampleManager manager) { var channel = manager.Get($"Gameplay/{Bank}-{Name}"); diff --git a/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs b/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs index e8ec6595bd..f031ebe353 100644 --- a/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs +++ b/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs @@ -55,7 +55,7 @@ namespace osu.Game.Beatmaps.ControlPoints /// /// The time to find the sound control point at. /// The sound control point. - public SampleControlPoint SamplePointAt(double time) => binarySearch(SamplePoints, time); + public SampleControlPoint SamplePointAt(double time) => binarySearch(SamplePoints, time, SamplePoints.FirstOrDefault()); /// /// Finds the timing control point that is active at . diff --git a/osu.Game/Beatmaps/ControlPoints/SampleControlPoint.cs b/osu.Game/Beatmaps/ControlPoints/SampleControlPoint.cs index e3d6eede44..40e45da13c 100644 --- a/osu.Game/Beatmaps/ControlPoints/SampleControlPoint.cs +++ b/osu.Game/Beatmaps/ControlPoints/SampleControlPoint.cs @@ -1,6 +1,8 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using osu.Game.Audio; + namespace osu.Game.Beatmaps.ControlPoints { public class SampleControlPoint : ControlPoint @@ -16,5 +18,17 @@ namespace osu.Game.Beatmaps.ControlPoints /// The default sample volume at this control point. /// public int SampleVolume; + + /// + /// Create a SampleInfo based on the sample settings in this control point. + /// + /// The name of the same. + /// A populated . + public SampleInfo GetSampleInfo(string sampleName = SampleInfo.HIT_NORMAL) => new SampleInfo + { + Bank = SampleBank, + Name = sampleName, + Volume = SampleVolume, + }; } } From a30400ad29e3cb28d506d4f429b2802a2b3c6185 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 23 Dec 2017 16:49:29 +0900 Subject: [PATCH 074/122] Use a class instead of Tuple --- osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs index 44c7bdb547..2112110be9 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs @@ -62,7 +62,7 @@ namespace osu.Game.Rulesets.Taiko.UI private readonly Box background; private readonly ControlPointInfo controlPointInfo; - private Dictionary> drumSampleMappings; + private Dictionary drumSampleMappings; public TaikoPlayfield(ControlPointInfo controlPointInfo) : base(Axes.X) @@ -207,12 +207,15 @@ namespace osu.Game.Rulesets.Taiko.UI [BackgroundDependencyLoader] private void load(OsuColour colours, AudioManager audio) { - drumSampleMappings = new Dictionary>(); + drumSampleMappings = new Dictionary(); foreach (var s in controlPointInfo.SamplePoints) { - var normalSample = s.GetSampleInfo().GetChannel(audio.Sample); - var clapSample = s.GetSampleInfo(SampleInfo.HIT_CLAP).GetChannel(audio.Sample); - drumSampleMappings.Add(s, new Tuple(normalSample, clapSample)); + drumSampleMappings.Add(s, + new DrumSamples + { + Centre = s.GetSampleInfo().GetChannel(audio.Sample), + Rim = s.GetSampleInfo(SampleInfo.HIT_CLAP).GetChannel(audio.Sample) + }); } overlayBackgroundContainer.BorderColour = colours.Gray0; @@ -296,5 +299,11 @@ namespace osu.Game.Rulesets.Taiko.UI } public bool OnReleased(TaikoAction action) => false; + + private class DrumSamples + { + public SampleChannel Centre; + public SampleChannel Rim; + } } } From cd8e8c832387199b85d48ef7ddddf944c1904aef Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 23 Dec 2017 16:52:23 +0900 Subject: [PATCH 075/122] Actually save changes --- osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs index 2112110be9..2cc95fc981 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs @@ -291,9 +291,9 @@ namespace osu.Game.Rulesets.Taiko.UI throw new InvalidOperationException("Current sample set not found."); if (action == TaikoAction.LeftCentre || action == TaikoAction.RightCentre) - samples.Item1.Play(); + samples.Centre.Play(); else - samples.Item2.Play(); + samples.Rim.Play(); return true; } From 2db68df999e3bbb5d347c682b74e6c4bbdfbd88b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 23 Dec 2017 17:20:14 +0900 Subject: [PATCH 076/122] Simplify DrawableHitObject's sample load code --- osu.Game/Audio/SampleInfo.cs | 5 +--- .../Objects/Drawables/DrawableHitObject.cs | 24 +++++++++---------- 2 files changed, 12 insertions(+), 17 deletions(-) diff --git a/osu.Game/Audio/SampleInfo.cs b/osu.Game/Audio/SampleInfo.cs index 566813dd44..64a9aa50a0 100644 --- a/osu.Game/Audio/SampleInfo.cs +++ b/osu.Game/Audio/SampleInfo.cs @@ -2,9 +2,7 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; -using osu.Framework.Audio; using osu.Framework.Audio.Sample; -using osu.Framework.Configuration; namespace osu.Game.Audio { @@ -19,8 +17,7 @@ namespace osu.Game.Audio public SampleChannel GetChannel(SampleManager manager) { var channel = manager.Get($"Gameplay/{Bank}-{Name}"); - - channel.AddAdjustment(AdjustableProperty.Volume, new BindableDouble(Volume / 100.0)); + channel.Volume.Value = Volume / 100.0; return channel; } diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index 8cfdda0413..47c4c4d05c 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -84,25 +84,23 @@ namespace osu.Game.Rulesets.Objects.Drawables [BackgroundDependencyLoader] private void load(AudioManager audio) { - foreach (SampleInfo sample in HitObject.Samples) + if (HitObject.SampleControlPoint == null) + throw new ArgumentNullException(nameof(HitObject.SampleControlPoint), $"{nameof(HitObject)} must always have an attached {nameof(HitObject.SampleControlPoint)}."); + + foreach (SampleInfo s in HitObject.Samples) { - if (HitObject.SampleControlPoint == null) - throw new ArgumentNullException(nameof(HitObject.SampleControlPoint), $"{nameof(HitObject)} must always have an attached {nameof(HitObject.SampleControlPoint)}."); + SampleInfo localSampleInfo = new SampleInfo + { + Bank = s.Bank ?? HitObject.SampleControlPoint.SampleBank, + Name = s.Name, + Volume = s.Volume > 0 ? s.Volume : HitObject.SampleControlPoint.SampleVolume + }; - var bank = sample.Bank; - if (string.IsNullOrEmpty(bank)) - bank = HitObject.SampleControlPoint.SampleBank; - - int volume = sample.Volume; - if (volume == 0) - volume = HitObject.SampleControlPoint.SampleVolume; - - SampleChannel channel = audio.Sample.Get($@"Gameplay/{bank}-{sample.Name}"); + SampleChannel channel = localSampleInfo.GetChannel(audio.Sample); if (channel == null) continue; - channel.Volume.Value = volume; Samples.Add(channel); } } From 298ac5468fab6cf528549b52caecededf0701263 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 23 Dec 2017 17:24:28 +0900 Subject: [PATCH 077/122] Fix regressions --- osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs | 2 +- osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHitStrong.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs index 9d797b77b5..df33aae94e 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs @@ -68,7 +68,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables validKeyPressed = HitActions.Contains(action); // Only count this as handled if the new judgement is a hit - return UpdateJudgement(true) && Judgements.Last().IsHit; + return UpdateJudgement(true) && Judgements.LastOrDefault()?.IsHit == true; } protected override void Update() diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHitStrong.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHitStrong.cs index a6575df6d7..81b23af1a9 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHitStrong.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHitStrong.cs @@ -83,7 +83,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables return false; // Assume the intention was to hit the strong hit with both keys only if the first key is still being held down - return firstKeyHeld && Judgements.Last().IsHit; + return firstKeyHeld && UpdateJudgement(true) && Judgements.LastOrDefault()?.IsHit == true; } } } From aeafa5645a39e5ec135621784fa95acad58fdcce Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 23 Dec 2017 18:06:46 +0900 Subject: [PATCH 078/122] Make Samples null by default and prepopulate in mania --- osu.Game.Rulesets.Mania/Objects/HoldNote.cs | 5 +++- .../Objects/Drawables/DrawableHitObject.cs | 29 ++++++++++--------- osu.Game/Rulesets/Objects/HitObject.cs | 2 +- 3 files changed, 21 insertions(+), 15 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Objects/HoldNote.cs b/osu.Game.Rulesets.Mania/Objects/HoldNote.cs index f72bed3142..103a33ce04 100644 --- a/osu.Game.Rulesets.Mania/Objects/HoldNote.cs +++ b/osu.Game.Rulesets.Mania/Objects/HoldNote.cs @@ -50,7 +50,10 @@ namespace osu.Game.Rulesets.Mania.Objects /// /// The head note of the hold. /// - public readonly Note Head = new Note(); + public readonly Note Head = new Note + { + Samples = new Audio.SampleInfoList() + }; /// /// The tail note of the hold. diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index 47c4c4d05c..d960ab6b48 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -84,24 +84,27 @@ namespace osu.Game.Rulesets.Objects.Drawables [BackgroundDependencyLoader] private void load(AudioManager audio) { - if (HitObject.SampleControlPoint == null) - throw new ArgumentNullException(nameof(HitObject.SampleControlPoint), $"{nameof(HitObject)} must always have an attached {nameof(HitObject.SampleControlPoint)}."); - - foreach (SampleInfo s in HitObject.Samples) + if (HitObject.Samples != null) { - SampleInfo localSampleInfo = new SampleInfo + if (HitObject.SampleControlPoint == null) + throw new ArgumentNullException(nameof(HitObject.SampleControlPoint), $"{nameof(HitObject)} must always have an attached {nameof(HitObject.SampleControlPoint)}."); + + foreach (SampleInfo s in HitObject.Samples) { - Bank = s.Bank ?? HitObject.SampleControlPoint.SampleBank, - Name = s.Name, - Volume = s.Volume > 0 ? s.Volume : HitObject.SampleControlPoint.SampleVolume - }; + SampleInfo localSampleInfo = new SampleInfo + { + Bank = s.Bank ?? HitObject.SampleControlPoint.SampleBank, + Name = s.Name, + Volume = s.Volume > 0 ? s.Volume : HitObject.SampleControlPoint.SampleVolume + }; - SampleChannel channel = localSampleInfo.GetChannel(audio.Sample); + SampleChannel channel = localSampleInfo.GetChannel(audio.Sample); - if (channel == null) - continue; + if (channel == null) + continue; - Samples.Add(channel); + Samples.Add(channel); + } } } diff --git a/osu.Game/Rulesets/Objects/HitObject.cs b/osu.Game/Rulesets/Objects/HitObject.cs index 5ecba7456e..e950516bf4 100644 --- a/osu.Game/Rulesets/Objects/HitObject.cs +++ b/osu.Game/Rulesets/Objects/HitObject.cs @@ -32,7 +32,7 @@ namespace osu.Game.Rulesets.Objects /// and can be treated as the default samples for the hit object. /// /// - public SampleInfoList Samples = new SampleInfoList(); + public SampleInfoList Samples; [JsonIgnore] public SampleControlPoint SampleControlPoint; From e7c85d38a8a3e5b6c428b92a6a6bf31dd6b623f6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 23 Dec 2017 19:17:05 +0900 Subject: [PATCH 079/122] Move list initialisation to pattern generation code --- .../Patterns/Legacy/EndTimeObjectPatternGenerator.cs | 8 ++++---- osu.Game.Rulesets.Mania/Objects/HoldNote.cs | 5 +---- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/EndTimeObjectPatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/EndTimeObjectPatternGenerator.cs index c353496410..3e9fc1ae27 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/EndTimeObjectPatternGenerator.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/EndTimeObjectPatternGenerator.cs @@ -76,10 +76,10 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy Duration = endTime - HitObject.StartTime }; - hold.Head.Samples.Add(new SampleInfo - { - Name = SampleInfo.HIT_NORMAL - }); + if (hold.Head.Samples == null) + hold.Head.Samples = new SampleInfoList(); + + hold.Head.Samples.Add(new SampleInfo { Name = SampleInfo.HIT_NORMAL }); hold.Tail.Samples = HitObject.Samples; diff --git a/osu.Game.Rulesets.Mania/Objects/HoldNote.cs b/osu.Game.Rulesets.Mania/Objects/HoldNote.cs index 103a33ce04..f72bed3142 100644 --- a/osu.Game.Rulesets.Mania/Objects/HoldNote.cs +++ b/osu.Game.Rulesets.Mania/Objects/HoldNote.cs @@ -50,10 +50,7 @@ namespace osu.Game.Rulesets.Mania.Objects /// /// The head note of the hold. /// - public readonly Note Head = new Note - { - Samples = new Audio.SampleInfoList() - }; + public readonly Note Head = new Note(); /// /// The tail note of the hold. From 1f44e98f9cc823760897cf15d83f937890df21a1 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sat, 23 Dec 2017 20:17:12 +0900 Subject: [PATCH 080/122] Add unavailable state to testcase --- osu.Game.Tests/Visual/TestCaseLeaderboard.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game.Tests/Visual/TestCaseLeaderboard.cs b/osu.Game.Tests/Visual/TestCaseLeaderboard.cs index 30a442594c..a01dbb7a6b 100644 --- a/osu.Game.Tests/Visual/TestCaseLeaderboard.cs +++ b/osu.Game.Tests/Visual/TestCaseLeaderboard.cs @@ -36,6 +36,7 @@ namespace osu.Game.Tests.Visual AddStep(@"Network failure", () => leaderboard.SetRetrievalState(PlaceholderState.NetworkFailure)); AddStep(@"No supporter", () => leaderboard.SetRetrievalState(PlaceholderState.NotSupporter)); AddStep(@"Not logged in", () => leaderboard.SetRetrievalState(PlaceholderState.NotLoggedIn)); + AddStep(@"Unavailable", () => leaderboard.SetRetrievalState(PlaceholderState.Unavailable)); AddStep(@"Real beatmap", realBeatmap); } From c5aba9f24749b5fc4a6039a11b6d40adbf090cae Mon Sep 17 00:00:00 2001 From: Aergwyn Date: Sat, 23 Dec 2017 12:32:21 +0100 Subject: [PATCH 081/122] add Samples to RepeatPoint construction --- osu.Game.Rulesets.Osu/Objects/Slider.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs index 24398c2235..e1d997790f 100644 --- a/osu.Game.Rulesets.Osu/Objects/Slider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs @@ -170,6 +170,7 @@ namespace osu.Game.Rulesets.Osu.Objects StackHeight = StackHeight, Scale = Scale, ComboColour = ComboColour, + Samples = new SampleInfoList(RepeatSamples.ElementAt(repeat)) }); } } From 1d67746d32e43eae2e5cd1946ed116415e260da7 Mon Sep 17 00:00:00 2001 From: Aergwyn Date: Sat, 23 Dec 2017 12:53:11 +0100 Subject: [PATCH 082/122] fix crash in SongSelect when traversing while zero beatmaps are loaded --- .../Visual/TestCaseBeatmapCarousel.cs | 19 ++++++++++++++++++- osu.Game/Screens/Select/BeatmapCarousel.cs | 3 +++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/TestCaseBeatmapCarousel.cs b/osu.Game.Tests/Visual/TestCaseBeatmapCarousel.cs index 66af72dad9..639befef74 100644 --- a/osu.Game.Tests/Visual/TestCaseBeatmapCarousel.cs +++ b/osu.Game.Tests/Visual/TestCaseBeatmapCarousel.cs @@ -69,6 +69,7 @@ namespace osu.Game.Tests.Visual testSorting(); testRemoveAll(); + testEmptyTraversal(); } private void ensureRandomFetchSuccess() => @@ -103,6 +104,8 @@ namespace osu.Game.Tests.Visual AddAssert($"{count} {(diff ? "diffs" : "sets")} visible", () => carousel.Items.Count(s => (diff ? s.Item is CarouselBeatmap : s.Item is CarouselBeatmapSet) && s.Item.Visible) == count); + private void checkNoSelection() => AddAssert("Selection is null", () => currentSelection == null); + private void nextRandom() => AddStep("select random next", () => { @@ -274,9 +277,23 @@ namespace osu.Game.Tests.Visual return false; }, "Remove all"); - AddAssert("Selection is null", () => currentSelection == null); + checkNoSelection(); } + private void testEmptyTraversal() + { + advanceSelection(direction: 1, diff: false); + checkNoSelection(); + + advanceSelection(direction: 1, diff: true); + checkNoSelection(); + + advanceSelection(direction: -1, diff: false); + checkNoSelection(); + + advanceSelection(direction: -1, diff: true); + checkNoSelection(); + } private BeatmapSetInfo createTestBeatmapSet(int i) { diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index ff1dd95eac..be176c1459 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -181,6 +181,9 @@ namespace osu.Game.Screens.Select /// Whether to skip individual difficulties and only increment over full groups. public void SelectNext(int direction = 1, bool skipDifficulties = true) { + if (!Items.Any()) + return; + int originalIndex = Items.IndexOf(selectedBeatmap?.Drawables.First()); int currentIndex = originalIndex; From 68d76d4380f2816088cd7f0344331e79aa4df907 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sat, 23 Dec 2017 20:58:09 +0900 Subject: [PATCH 083/122] Fix taiko strong hits not being handled --- osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index d960ab6b48..c397ea47ef 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -174,7 +174,7 @@ namespace osu.Game.Rulesets.Objects.Drawables { judgementOccurred = false; - if (AllJudged || State != ArmedState.Idle) + if (AllJudged) return false; if (NestedHitObjects != null) From 47c75d01ce5057b5005819a273577c6de4ea2360 Mon Sep 17 00:00:00 2001 From: Aergwyn Date: Sat, 23 Dec 2017 13:30:44 +0100 Subject: [PATCH 084/122] access list with index instead of using LINQ --- osu.Game.Rulesets.Osu/Objects/Slider.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs index e1d997790f..4f5a44e61d 100644 --- a/osu.Game.Rulesets.Osu/Objects/Slider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs @@ -170,7 +170,7 @@ namespace osu.Game.Rulesets.Osu.Objects StackHeight = StackHeight, Scale = Scale, ComboColour = ComboColour, - Samples = new SampleInfoList(RepeatSamples.ElementAt(repeat)) + Samples = new SampleInfoList(RepeatSamples[repeat]) }); } } From 9bb0cda5256a8c14f4cf4bc7b50b2fdc832d5e3b Mon Sep 17 00:00:00 2001 From: Aergwyn Date: Sat, 23 Dec 2017 14:33:43 +0100 Subject: [PATCH 085/122] fix NotificationOverlay going out of bounds at the bottom also fixes the overlap with the Toolbar at the top --- .../Visual/TestCaseNotificationOverlay.cs | 35 +++++++--------- osu.Game/OsuGame.cs | 1 + osu.Game/Overlays/NotificationOverlay.cs | 41 ++++++++++++------- 3 files changed, 42 insertions(+), 35 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseNotificationOverlay.cs b/osu.Game.Tests/Visual/TestCaseNotificationOverlay.cs index 79d3d7d4ba..b93c2d812f 100644 --- a/osu.Game.Tests/Visual/TestCaseNotificationOverlay.cs +++ b/osu.Game.Tests/Visual/TestCaseNotificationOverlay.cs @@ -3,19 +3,17 @@ using System.Collections.Generic; using System.Linq; -using NUnit.Framework; using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; using osu.Framework.MathUtils; using osu.Game.Overlays; using osu.Game.Overlays.Notifications; namespace osu.Game.Tests.Visual { - [TestFixture] public class TestCaseNotificationOverlay : OsuTestCase { private readonly NotificationOverlay manager; + private readonly List progressingNotifications = new List(); public TestCaseNotificationOverlay() { @@ -24,15 +22,14 @@ namespace osu.Game.Tests.Visual Content.Add(manager = new NotificationOverlay { Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, + Origin = Anchor.TopRight }); - AddToggleStep(@"show", state => manager.State = state ? Visibility.Visible : Visibility.Hidden); - - AddStep(@"simple #1", sendNotification1); - AddStep(@"simple #2", sendNotification2); - AddStep(@"progress #1", sendProgress1); - AddStep(@"progress #2", sendProgress2); + AddStep(@"toggle", manager.ToggleVisibility); + AddStep(@"simple #1", sendHelloNotification); + AddStep(@"simple #2", sendAmazingNotification); + AddStep(@"progress #1", sendUploadProgress); + AddStep(@"progress #2", sendDownloadProgress); AddStep(@"barrage", () => sendBarrage()); } @@ -41,16 +38,16 @@ namespace osu.Game.Tests.Visual switch (RNG.Next(0, 4)) { case 0: - sendNotification1(); + sendHelloNotification(); break; case 1: - sendNotification2(); + sendAmazingNotification(); break; case 2: - sendProgress1(); + sendUploadProgress(); break; case 3: - sendProgress2(); + sendDownloadProgress(); break; } @@ -80,7 +77,7 @@ namespace osu.Game.Tests.Visual } } - private void sendProgress2() + private void sendDownloadProgress() { var n = new ProgressNotification { @@ -91,9 +88,7 @@ namespace osu.Game.Tests.Visual progressingNotifications.Add(n); } - private readonly List progressingNotifications = new List(); - - private void sendProgress1() + private void sendUploadProgress() { var n = new ProgressNotification { @@ -104,12 +99,12 @@ namespace osu.Game.Tests.Visual progressingNotifications.Add(n); } - private void sendNotification2() + private void sendAmazingNotification() { manager.Post(new SimpleNotification { Text = @"You are amazing" }); } - private void sendNotification1() + private void sendHelloNotification() { manager.Post(new SimpleNotification { Text = @"Welcome to osu!. Enjoy your stay!" }); } diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 4745733bd9..4c66539cf1 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -209,6 +209,7 @@ namespace osu.Game loadComponentSingleFile(notificationOverlay = new NotificationOverlay { + GetToolbarHeight = () => ToolbarOffset, Depth = -4, Anchor = Anchor.TopRight, Origin = Anchor.TopRight, diff --git a/osu.Game/Overlays/NotificationOverlay.cs b/osu.Game/Overlays/NotificationOverlay.cs index 260214a14f..a4b5486596 100644 --- a/osu.Game/Overlays/NotificationOverlay.cs +++ b/osu.Game/Overlays/NotificationOverlay.cs @@ -10,6 +10,7 @@ using osu.Game.Overlays.Notifications; using OpenTK.Graphics; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics.Containers; +using System; namespace osu.Game.Overlays { @@ -19,9 +20,13 @@ namespace osu.Game.Overlays public const float TRANSITION_LENGTH = 600; - private ScrollContainer scrollContainer; private FlowContainer sections; + /// + /// Provide a source for the toolbar height. + /// + public Func GetToolbarHeight; + [BackgroundDependencyLoader] private void load() { @@ -36,12 +41,12 @@ namespace osu.Game.Overlays { RelativeSizeAxes = Axes.Both, Colour = Color4.Black, - Alpha = 0.6f, + Alpha = 0.6f }, - scrollContainer = new OsuScrollContainer + new OsuScrollContainer { + Masking = true, RelativeSizeAxes = Axes.Both, - Margin = new MarginPadding { Top = Toolbar.Toolbar.HEIGHT }, Children = new[] { sections = new FillFlowContainer @@ -55,14 +60,14 @@ namespace osu.Game.Overlays { Title = @"Notifications", ClearText = @"Clear All", - AcceptTypes = new[] { typeof(SimpleNotification) }, + AcceptTypes = new[] { typeof(SimpleNotification) } }, new NotificationSection { Title = @"Running Tasks", ClearText = @"Cancel All", - AcceptTypes = new[] { typeof(ProgressNotification) }, - }, + AcceptTypes = new[] { typeof(ProgressNotification) } + } } } } @@ -103,14 +108,8 @@ namespace osu.Game.Overlays { base.PopIn(); - scrollContainer.MoveToX(0, TRANSITION_LENGTH, Easing.OutQuint); this.MoveToX(0, TRANSITION_LENGTH, Easing.OutQuint); - this.FadeTo(1, TRANSITION_LENGTH / 2); - } - - private void markAllRead() - { - sections.Children.ForEach(s => s.MarkAllRead()); + this.FadeTo(1, TRANSITION_LENGTH, Easing.OutQuint); } protected override void PopOut() @@ -120,7 +119,19 @@ namespace osu.Game.Overlays markAllRead(); this.MoveToX(width, TRANSITION_LENGTH, Easing.OutQuint); - this.FadeTo(0, TRANSITION_LENGTH / 2); + this.FadeTo(0, TRANSITION_LENGTH, Easing.OutQuint); + } + + private void markAllRead() + { + sections.Children.ForEach(s => s.MarkAllRead()); + } + + protected override void UpdateAfterChildren() + { + base.UpdateAfterChildren(); + + Padding = new MarginPadding { Top = GetToolbarHeight?.Invoke() ?? 0 }; } } } From 2ffc479411ab1edc093aa5416a5ec3e62eacf6a6 Mon Sep 17 00:00:00 2001 From: Aergwyn Date: Sat, 23 Dec 2017 14:56:23 +0100 Subject: [PATCH 086/122] let NotificationOverlay move the background --- osu.Game/OsuGame.cs | 21 +++++++++++++++++++-- osu.Game/Overlays/SettingsOverlay.cs | 6 +++--- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 4745733bd9..121e9360ce 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -75,6 +75,8 @@ namespace osu.Game private SettingsOverlay settings; + private float backgroundOffset; + public OsuGame(string[] args = null) { this.args = args; @@ -276,12 +278,27 @@ namespace osu.Game switch (settings.State) { case Visibility.Hidden: - intro.MoveToX(0, SettingsOverlay.TRANSITION_LENGTH, Easing.OutQuint); + backgroundOffset -= ToolbarButton.WIDTH / 2; break; case Visibility.Visible: - intro.MoveToX(SettingsOverlay.SIDEBAR_WIDTH / 2, SettingsOverlay.TRANSITION_LENGTH, Easing.OutQuint); + backgroundOffset += ToolbarButton.WIDTH / 2; break; } + intro.MoveToX(backgroundOffset, SettingsOverlay.TRANSITION_LENGTH, Easing.OutQuint); + }; + + notificationOverlay.StateChanged += delegate + { + switch (notificationOverlay.State) + { + case Visibility.Hidden: + backgroundOffset += ToolbarButton.WIDTH / 2; + break; + case Visibility.Visible: + backgroundOffset -= ToolbarButton.WIDTH / 2; + break; + } + intro.MoveToX(backgroundOffset, NotificationOverlay.TRANSITION_LENGTH, Easing.OutQuint); }; Cursor.State = Visibility.Hidden; diff --git a/osu.Game/Overlays/SettingsOverlay.cs b/osu.Game/Overlays/SettingsOverlay.cs index 798fa00032..a80f6d4da8 100644 --- a/osu.Game/Overlays/SettingsOverlay.cs +++ b/osu.Game/Overlays/SettingsOverlay.cs @@ -24,7 +24,7 @@ namespace osu.Game.Overlays public const float TRANSITION_LENGTH = 600; - public const float SIDEBAR_WIDTH = Sidebar.DEFAULT_WIDTH; + private const float sidebar_width = Sidebar.DEFAULT_WIDTH; protected const float WIDTH = 400; @@ -102,7 +102,7 @@ namespace osu.Game.Overlays if (showSidebar) { - AddInternal(Sidebar = new Sidebar { Width = SIDEBAR_WIDTH }); + AddInternal(Sidebar = new Sidebar { Width = sidebar_width }); SectionsContainer.SelectedSection.ValueChanged += section => { @@ -167,7 +167,7 @@ namespace osu.Game.Overlays ContentContainer.MoveToX(-WIDTH, TRANSITION_LENGTH, Easing.OutQuint); - Sidebar?.MoveToX(-SIDEBAR_WIDTH, TRANSITION_LENGTH, Easing.OutQuint); + Sidebar?.MoveToX(-sidebar_width, TRANSITION_LENGTH, Easing.OutQuint); this.FadeTo(0, TRANSITION_LENGTH, Easing.OutQuint); searchTextBox.HoldFocus = false; From cf316b3c51661a7a21ae1b47c90b9f169c19b8f6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 24 Dec 2017 15:39:25 +0900 Subject: [PATCH 087/122] Add tests for initial load states of PlaySongSelect --- .../Visual/TestCasePlaySongSelect.cs | 48 ++++++++++++++++--- osu.Game/Screens/Select/BeatmapCarousel.cs | 1 - osu.Game/Screens/Select/SongSelect.cs | 34 ++++++------- 3 files changed, 59 insertions(+), 24 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs b/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs index 6435df7c2c..34b99c6ca6 100644 --- a/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs +++ b/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs @@ -26,6 +26,7 @@ namespace osu.Game.Tests.Visual private RulesetStore rulesets; private DependencyContainer dependencies; + private WorkingBeatmap defaultBeatmap; public override IReadOnlyList RequiredTypes => new[] { @@ -47,10 +48,16 @@ namespace osu.Game.Tests.Visual protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent) => dependencies = new DependencyContainer(parent); + private class TestSongSelect : PlaySongSelect + { + public WorkingBeatmap CurrentBeatmap => Beatmap.Value; + public new BeatmapCarousel Carousel => base.Carousel; + } + [BackgroundDependencyLoader] private void load(BeatmapManager baseManager) { - PlaySongSelect songSelect; + TestSongSelect songSelect = null; if (manager == null) { @@ -64,14 +71,43 @@ namespace osu.Game.Tests.Visual dependencies.Cache(rulesets = new RulesetStore(contextFactory)); dependencies.Cache(manager = new BeatmapManager(storage, contextFactory, rulesets, null) { - DefaultBeatmap = baseManager.GetWorkingBeatmap(null) + DefaultBeatmap = defaultBeatmap = baseManager.GetWorkingBeatmap(null) }); - - for (int i = 0; i < 100; i += 10) - manager.Import(createTestBeatmapSet(i)); } - Add(songSelect = new PlaySongSelect()); + void loadNewSongSelect(bool deleteMaps = false) => AddStep("reload song select", () => + { + if (deleteMaps) manager.DeleteAll(); + + if (songSelect != null) + { + Remove(songSelect); + songSelect.Dispose(); + } + + Add(songSelect = new TestSongSelect()); + }); + + loadNewSongSelect(true); + + AddWaitStep(1); + + AddAssert("dummy selected", () => songSelect.CurrentBeatmap == defaultBeatmap); + + AddStep("import test maps", () => + { + for (int i = 0; i < 100; i += 10) + manager.Import(createTestBeatmapSet(i)); + }); + + AddWaitStep(1); + AddStep("select random", () => songSelect.Carousel.SelectNextRandom()); + + AddWaitStep(1); + AddAssert("random map selected", () => songSelect.CurrentBeatmap != defaultBeatmap); + + loadNewSongSelect(); + AddAssert("random map selected", () => songSelect.CurrentBeatmap != defaultBeatmap); AddStep(@"Sort by Artist", delegate { songSelect.FilterControl.Sort = SortMode.Artist; }); AddStep(@"Sort by Title", delegate { songSelect.FilterControl.Sort = SortMode.Title; }); diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index bfba9a7d6b..b4ca6f10f9 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -142,7 +142,6 @@ namespace osu.Game.Screens.Select if (newSet == null) { itemsCache.Invalidate(); - SelectNext(); return; } diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 9a7dbf002e..a15699d97a 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -55,7 +55,7 @@ namespace osu.Game.Screens.Select protected Container LeftContent; - private readonly BeatmapCarousel carousel; + protected readonly BeatmapCarousel Carousel; private readonly BeatmapInfoWedge beatmapInfoWedge; private DialogOverlay dialogOverlay; private BeatmapManager beatmaps; @@ -103,7 +103,7 @@ namespace osu.Game.Screens.Select Right = left_area_padding * 2, } }, - carousel = new BeatmapCarousel + Carousel = new BeatmapCarousel { RelativeSizeAxes = Axes.Y, Size = new Vector2(carousel_width, 1), @@ -116,7 +116,7 @@ namespace osu.Game.Screens.Select { RelativeSizeAxes = Axes.X, Height = filter_height, - FilterChanged = c => carousel.Filter(c), + FilterChanged = c => Carousel.Filter(c), Exit = Exit, }, beatmapInfoWedge = new BeatmapInfoWedge @@ -130,7 +130,7 @@ namespace osu.Game.Screens.Select Right = left_area_padding, }, }, - new ResetScrollContainer(() => carousel.ScrollToSelected()) + new ResetScrollContainer(() => Carousel.ScrollToSelected()) { RelativeSizeAxes = Axes.Y, Width = 250, @@ -190,15 +190,15 @@ namespace osu.Game.Screens.Select initialAddSetsTask = new CancellationTokenSource(); - carousel.BeatmapSets = this.beatmaps.GetAllUsableBeatmapSets(); + Carousel.BeatmapSets = this.beatmaps.GetAllUsableBeatmapSets(); - Beatmap.DisabledChanged += disabled => carousel.AllowSelection = !disabled; + Beatmap.DisabledChanged += disabled => Carousel.AllowSelection = !disabled; Beatmap.TriggerChange(); Beatmap.ValueChanged += b => { if (IsCurrentScreen) - carousel.SelectBeatmap(b?.BeatmapInfo); + Carousel.SelectBeatmap(b?.BeatmapInfo); }; } @@ -212,9 +212,9 @@ namespace osu.Game.Screens.Select { // if we have a pending filter operation, we want to run it now. // it could change selection (ie. if the ruleset has been changed). - carousel.FlushPendingFilterOperations(); + Carousel.FlushPendingFilterOperations(); - carousel.SelectBeatmap(beatmap); + Carousel.SelectBeatmap(beatmap); if (selectionChangedDebounce?.Completed == false) { @@ -282,9 +282,9 @@ namespace osu.Game.Screens.Select private void triggerRandom() { if (GetContainingInputManager().CurrentState.Keyboard.ShiftPressed) - carousel.SelectPreviousRandom(); + Carousel.SelectPreviousRandom(); else - carousel.SelectNextRandom(); + Carousel.SelectNextRandom(); } protected override void OnEntering(Screen last) @@ -416,17 +416,17 @@ namespace osu.Game.Screens.Select } } - private void onBeatmapSetAdded(BeatmapSetInfo s) => carousel.UpdateBeatmapSet(s); - private void onBeatmapSetRemoved(BeatmapSetInfo s) => carousel.RemoveBeatmapSet(s); - private void onBeatmapRestored(BeatmapInfo b) => carousel.UpdateBeatmapSet(beatmaps.QueryBeatmapSet(s => s.ID == b.BeatmapSetInfoID)); - private void onBeatmapHidden(BeatmapInfo b) => carousel.UpdateBeatmapSet(beatmaps.QueryBeatmapSet(s => s.ID == b.BeatmapSetInfoID)); + private void onBeatmapSetAdded(BeatmapSetInfo s) => Carousel.UpdateBeatmapSet(s); + private void onBeatmapSetRemoved(BeatmapSetInfo s) => Carousel.RemoveBeatmapSet(s); + private void onBeatmapRestored(BeatmapInfo b) => Carousel.UpdateBeatmapSet(beatmaps.QueryBeatmapSet(s => s.ID == b.BeatmapSetInfoID)); + private void onBeatmapHidden(BeatmapInfo b) => Carousel.UpdateBeatmapSet(beatmaps.QueryBeatmapSet(s => s.ID == b.BeatmapSetInfoID)); private void carouselBeatmapsLoaded() { if (Beatmap.Value.BeatmapSetInfo?.DeletePending == false) - carousel.SelectBeatmap(Beatmap.Value.BeatmapInfo); + Carousel.SelectBeatmap(Beatmap.Value.BeatmapInfo); else - carousel.SelectNextRandom(); + Carousel.SelectNextRandom(); } private void delete(BeatmapSetInfo beatmap) From a04ebd0595e423c02e38b57b5e386020d19f7157 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 24 Dec 2017 15:39:44 +0900 Subject: [PATCH 088/122] Update framework --- osu-framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu-framework b/osu-framework index 08f85f9bf9..64e04b9ff2 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 08f85f9bf9a7376aec8dfcde8c7c96d267d8c295 +Subproject commit 64e04b9ff2d5ba53e5c3a46cfa42a79baeffc014 From 482e10966cfb5fd80c892695bfda6f250b6ae4ee Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 24 Dec 2017 17:02:46 +0900 Subject: [PATCH 089/122] Ensure a selection is made on entering song select if no selection is current --- osu.Game.Tests/Visual/TestCasePlaySongSelect.cs | 3 --- osu.Game/Screens/Select/BeatmapCarousel.cs | 4 +++- osu.Game/Screens/Select/SongSelect.cs | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs b/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs index 34b99c6ca6..87f71d215b 100644 --- a/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs +++ b/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs @@ -100,9 +100,6 @@ namespace osu.Game.Tests.Visual manager.Import(createTestBeatmapSet(i)); }); - AddWaitStep(1); - AddStep("select random", () => songSelect.Carousel.SelectNextRandom()); - AddWaitStep(1); AddAssert("random map selected", () => songSelect.CurrentBeatmap != defaultBeatmap); diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index b4ca6f10f9..c33993c68c 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -75,7 +75,8 @@ namespace osu.Game.Screens.Select scrollableContent.Clear(false); itemsCache.Invalidate(); scrollPositionCache.Invalidate(); - BeatmapSetsChanged?.Invoke(); + + Schedule(() => BeatmapSetsChanged?.Invoke()); })); } } @@ -154,6 +155,7 @@ namespace osu.Game.Screens.Select select((CarouselItem)newSet.Beatmaps.FirstOrDefault(b => b.Beatmap.ID == selectedBeatmap?.Beatmap.ID) ?? newSet); itemsCache.Invalidate(); + Schedule(() => BeatmapSetsChanged?.Invoke()); }); } diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index a15699d97a..75c4a68388 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -423,7 +423,7 @@ namespace osu.Game.Screens.Select private void carouselBeatmapsLoaded() { - if (Beatmap.Value.BeatmapSetInfo?.DeletePending == false) + if (!Beatmap.IsDefault && Beatmap.Value.BeatmapSetInfo?.DeletePending == false) Carousel.SelectBeatmap(Beatmap.Value.BeatmapInfo); else Carousel.SelectNextRandom(); From 5b22c5a45371e671b155f11bbcc6e4d94c95eff5 Mon Sep 17 00:00:00 2001 From: Aergwyn Date: Sun, 24 Dec 2017 10:28:37 +0100 Subject: [PATCH 090/122] reduce code duplication to move intro background --- osu.Game/OsuGame.cs | 51 ++++++++++++++++----------------------------- 1 file changed, 18 insertions(+), 33 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 121e9360ce..f91df9b6ba 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -37,7 +37,7 @@ namespace osu.Game private MusicController musicController; - private NotificationOverlay notificationOverlay; + private NotificationOverlay notifications; private DialogOverlay dialogOverlay; @@ -75,8 +75,6 @@ namespace osu.Game private SettingsOverlay settings; - private float backgroundOffset; - public OsuGame(string[] args = null) { this.args = args; @@ -138,7 +136,7 @@ namespace osu.Game if (s.Beatmap == null) { - notificationOverlay.Post(new SimpleNotification + notifications.Post(new SimpleNotification { Text = @"Tried to load a score for a beatmap we don't have!", Icon = FontAwesome.fa_life_saver, @@ -156,7 +154,7 @@ namespace osu.Game base.LoadComplete(); // hook up notifications to components. - BeatmapManager.PostNotification = n => notificationOverlay?.Post(n); + BeatmapManager.PostNotification = n => notifications?.Post(n); BeatmapManager.GetStableStorage = GetStorageForStableInstall; AddRange(new Drawable[] @@ -209,7 +207,7 @@ namespace osu.Game Origin = Anchor.TopRight, }, overlayContent.Add); - loadComponentSingleFile(notificationOverlay = new NotificationOverlay + loadComponentSingleFile(notifications = new NotificationOverlay { Depth = -4, Anchor = Anchor.TopRight, @@ -225,7 +223,7 @@ namespace osu.Game { if (entry.Level < LogLevel.Important) return; - notificationOverlay.Post(new SimpleNotification + notifications.Post(new SimpleNotification { Text = $@"{entry.Level}: {entry.Message}" }); @@ -238,7 +236,7 @@ namespace osu.Game dependencies.Cache(userProfile); dependencies.Cache(musicController); dependencies.Cache(beatmapSetOverlay); - dependencies.Cache(notificationOverlay); + dependencies.Cache(notifications); dependencies.Cache(dialogOverlay); // ensure only one of these overlays are open at once. @@ -273,33 +271,20 @@ namespace osu.Game }; } - settings.StateChanged += delegate + Action stateChanged = delegate { - switch (settings.State) - { - case Visibility.Hidden: - backgroundOffset -= ToolbarButton.WIDTH / 2; - break; - case Visibility.Visible: - backgroundOffset += ToolbarButton.WIDTH / 2; - break; - } - intro.MoveToX(backgroundOffset, SettingsOverlay.TRANSITION_LENGTH, Easing.OutQuint); + float offset = intro.X; + + if (settings.State == Visibility.Hidden || notifications.State == Visibility.Visible) + offset -= ToolbarButton.WIDTH / 2; + else if (settings.State == Visibility.Visible || notifications.State == Visibility.Hidden) + offset += ToolbarButton.WIDTH / 2; + + intro.MoveToX(offset, SettingsOverlay.TRANSITION_LENGTH, Easing.OutQuint); }; - notificationOverlay.StateChanged += delegate - { - switch (notificationOverlay.State) - { - case Visibility.Hidden: - backgroundOffset += ToolbarButton.WIDTH / 2; - break; - case Visibility.Visible: - backgroundOffset -= ToolbarButton.WIDTH / 2; - break; - } - intro.MoveToX(backgroundOffset, NotificationOverlay.TRANSITION_LENGTH, Easing.OutQuint); - }; + settings.StateChanged += stateChanged; + notifications.StateChanged += stateChanged; Cursor.State = Visibility.Hidden; } @@ -368,7 +353,7 @@ namespace osu.Game direct.State = Visibility.Hidden; social.State = Visibility.Hidden; userProfile.State = Visibility.Hidden; - notificationOverlay.State = Visibility.Hidden; + notifications.State = Visibility.Hidden; } private void screenChanged(Screen newScreen) From 68a00235b92fc87d54f88c432892ed8a63e06464 Mon Sep 17 00:00:00 2001 From: Aergwyn Date: Sun, 24 Dec 2017 14:32:56 +0100 Subject: [PATCH 091/122] simplify offset calculation for background --- osu.Game/OsuGame.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index f757d16c85..67f6e6f4e2 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -274,12 +274,12 @@ namespace osu.Game Action stateChanged = delegate { - float offset = intro.X; + float offset = 0; - if (settings.State == Visibility.Hidden || notifications.State == Visibility.Visible) - offset -= ToolbarButton.WIDTH / 2; - else if (settings.State == Visibility.Visible || notifications.State == Visibility.Hidden) + if (settings.State == Visibility.Visible) offset += ToolbarButton.WIDTH / 2; + if (notifications.State == Visibility.Visible) + offset -= ToolbarButton.WIDTH / 2; intro.MoveToX(offset, SettingsOverlay.TRANSITION_LENGTH, Easing.OutQuint); }; From a7ee6985b050fbf6df3f2880c87f7a1085cec863 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 25 Dec 2017 01:06:33 +0900 Subject: [PATCH 092/122] Add wait step --- osu.Game.Tests/Visual/TestCasePlaySongSelect.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs b/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs index 87f71d215b..e27e786a05 100644 --- a/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs +++ b/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs @@ -104,6 +104,7 @@ namespace osu.Game.Tests.Visual AddAssert("random map selected", () => songSelect.CurrentBeatmap != defaultBeatmap); loadNewSongSelect(); + AddWaitStep(1); AddAssert("random map selected", () => songSelect.CurrentBeatmap != defaultBeatmap); AddStep(@"Sort by Artist", delegate { songSelect.FilterControl.Sort = SortMode.Artist; }); From 8529eb1d3a2350da13d8fb445a7d13375afa1c97 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 25 Dec 2017 14:49:39 +0900 Subject: [PATCH 093/122] Make strong hit misses not count as misses --- osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHitStrong.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHitStrong.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHitStrong.cs index 81b23af1a9..07f7b83cef 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHitStrong.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHitStrong.cs @@ -36,7 +36,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables if (!userTriggered) { if (timeOffset > second_hit_window) - AddJudgement(new TaikoStrongHitJudgement { Result = HitResult.Miss }); + AddJudgement(new TaikoStrongHitJudgement { Result = HitResult.None }); return; } From 844e39a9f6f177be8bc4f41fe8ff69425052d622 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 25 Dec 2017 15:04:22 +0900 Subject: [PATCH 094/122] Make Swells play samples while they're being hit --- .../Objects/Drawables/DrawableSwell.cs | 37 ++++++++++++++----- osu.Game.Rulesets.Taiko/Objects/Swell.cs | 28 +++++++++++++- .../Objects/SwellSampleMapping.cs | 28 ++++++++++++++ .../osu.Game.Rulesets.Taiko.csproj | 1 + 4 files changed, 83 insertions(+), 11 deletions(-) create mode 100644 osu.Game.Rulesets.Taiko/Objects/SwellSampleMapping.cs diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs index 738902846b..d657598554 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs @@ -14,6 +14,7 @@ using OpenTK; using OpenTK.Graphics; using osu.Framework.Graphics.Shapes; using osu.Game.Rulesets.Taiko.Judgements; +using osu.Framework.Audio; namespace osu.Game.Rulesets.Taiko.Objects.Drawables { @@ -34,10 +35,6 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables private readonly CircularContainer targetRing; private readonly CircularContainer expandingRing; - private readonly TaikoAction[] rimActions = { TaikoAction.LeftRim, TaikoAction.RightRim }; - private readonly TaikoAction[] centreActions = { TaikoAction.LeftCentre, TaikoAction.RightCentre }; - private TaikoAction[] lastAction; - /// /// The amount of times the user has hit this swell. /// @@ -120,11 +117,14 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables } [BackgroundDependencyLoader] - private void load(OsuColour colours) + private void load(OsuColour colours, AudioManager audio) { MainPiece.AccentColour = colours.YellowDark; expandingRing.Colour = colours.YellowLight; targetRing.BorderColour = colours.YellowDark.Opacity(0.25f); + + foreach (var mapping in HitObject.ProgressionSamples) + mapping.RetrieveChannels(audio); } protected override void LoadComplete() @@ -205,22 +205,39 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables } } + private bool? lastWasCentre; + public override bool OnPressed(TaikoAction action) { // Don't handle keys before the swell starts if (Time.Current < HitObject.StartTime) return false; - // Find the keyset which this key corresponds to - var keySet = rimActions.Contains(action) ? rimActions : centreActions; + var isCentre = action == TaikoAction.LeftCentre || action == TaikoAction.RightCentre; - // Ensure alternating keysets - if (keySet == lastAction) + // Ensure alternating centre and rim hits + if (lastWasCentre == isCentre) return false; - lastAction = keySet; + lastWasCentre = isCentre; UpdateJudgement(true); + if (AllJudged) + return true; + + // While the swell hasn't been fully judged, input is still blocked so it doesn't fall through to other hitobjects + // This causes the playfield to not play sounds, so they need to be handled locally + + var mappingIndex = HitObject.ProgressionSamples.BinarySearch(new SwellSampleMapping { Time = Time.Current }); + if (mappingIndex < 0) + mappingIndex = ~mappingIndex - 1; + + var mapping = HitObject.ProgressionSamples[mappingIndex]; + if (isCentre) + mapping.CentreChannel.Play(); + else + mapping.RimChannel.Play(); + return true; } } diff --git a/osu.Game.Rulesets.Taiko/Objects/Swell.cs b/osu.Game.Rulesets.Taiko/Objects/Swell.cs index f74a543ca9..b4fa736045 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Swell.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Swell.cs @@ -1,6 +1,11 @@ // 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.Linq; +using osu.Game.Audio; +using osu.Game.Beatmaps; +using osu.Game.Beatmaps.ControlPoints; using osu.Game.Rulesets.Objects.Types; namespace osu.Game.Rulesets.Taiko.Objects @@ -15,5 +20,26 @@ namespace osu.Game.Rulesets.Taiko.Objects /// The number of hits required to complete the swell successfully. /// public int RequiredHits = 10; + + public List ProgressionSamples = new List(); + + protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) + { + base.ApplyDefaultsToSelf(controlPointInfo, difficulty); + + var progressionSamplePoints = + new[] { controlPointInfo.SamplePointAt(StartTime) } + .Concat(controlPointInfo.SamplePoints.Where(p => p.Time > StartTime && p.Time <= EndTime)); + + foreach (var point in progressionSamplePoints) + { + ProgressionSamples.Add(new SwellSampleMapping + { + Time = point.Time, + Centre = point.GetSampleInfo(), + Rim = point.GetSampleInfo(SampleInfo.HIT_CLAP) + }); + } + } } -} \ No newline at end of file +} diff --git a/osu.Game.Rulesets.Taiko/Objects/SwellSampleMapping.cs b/osu.Game.Rulesets.Taiko/Objects/SwellSampleMapping.cs new file mode 100644 index 0000000000..99d0e1d0fd --- /dev/null +++ b/osu.Game.Rulesets.Taiko/Objects/SwellSampleMapping.cs @@ -0,0 +1,28 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using osu.Framework.Audio; +using osu.Framework.Audio.Sample; +using osu.Game.Audio; + +namespace osu.Game.Rulesets.Taiko.Objects +{ + public class SwellSampleMapping : IComparable + { + public double Time; + public SampleInfo Centre; + public SampleInfo Rim; + + public SampleChannel CentreChannel { get; private set; } + public SampleChannel RimChannel { get; private set; } + + public void RetrieveChannels(AudioManager audio) + { + CentreChannel = Centre.GetChannel(audio.Sample); + RimChannel = Rim.GetChannel(audio.Sample); + } + + public int CompareTo(SwellSampleMapping other) => Time.CompareTo(other.Time); + } +} diff --git a/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj b/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj index bb02db62b9..9fa3936153 100644 --- a/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj +++ b/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj @@ -74,6 +74,7 @@ + From d288d8a51f370a6f91141c046ad3a67b4a1a6c5a Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 25 Dec 2017 15:35:28 +0900 Subject: [PATCH 095/122] Remove SampleInfoList --- osu.Game.Rulesets.Catch/Objects/JuiceStream.cs | 6 +++--- .../Beatmaps/ManiaBeatmapConverter.cs | 2 +- .../Legacy/DistanceObjectPatternGenerator.cs | 3 ++- .../Legacy/EndTimeObjectPatternGenerator.cs | 3 ++- osu.Game.Rulesets.Osu/Objects/Slider.cs | 6 +++--- .../Beatmaps/TaikoBeatmapConverter.cs | 6 +++--- osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs | 3 ++- .../Tests/TestCaseTaikoPlayfield.cs | 14 ++++++++++++-- osu.Game/Audio/SampleInfoList.cs | 18 ------------------ osu.Game/Rulesets/Objects/HitObject.cs | 2 +- .../Legacy/Catch/ConvertHitObjectParser.cs | 2 +- .../Objects/Legacy/ConvertHitObjectParser.cs | 8 ++++---- .../Rulesets/Objects/Legacy/ConvertSlider.cs | 2 +- .../Legacy/Mania/ConvertHitObjectParser.cs | 2 +- .../Legacy/Osu/ConvertHitObjectParser.cs | 4 ++-- .../Legacy/Taiko/ConvertHitObjectParser.cs | 4 ++-- osu.Game/Rulesets/Objects/Types/IHasRepeats.cs | 2 +- osu.Game/osu.Game.csproj | 1 - 18 files changed, 41 insertions(+), 47 deletions(-) delete mode 100644 osu.Game/Audio/SampleInfoList.cs diff --git a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs index 8e496c3b0c..7d0d80a0ce 100644 --- a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs +++ b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs @@ -86,7 +86,7 @@ namespace osu.Game.Rulesets.Catch.Objects StartTime = lastTickTime, ComboColour = ComboColour, X = Curve.PositionAt(distanceProgress).X / CatchPlayfield.BASE_WIDTH, - Samples = new SampleInfoList(Samples.Select(s => new SampleInfo + Samples = new List(Samples.Select(s => new SampleInfo { Bank = s.Bank, Name = @"slidertick", @@ -108,7 +108,7 @@ namespace osu.Game.Rulesets.Catch.Objects StartTime = repeatStartTime + t, ComboColour = ComboColour, X = Curve.PositionAt(progress).X / CatchPlayfield.BASE_WIDTH, - Samples = new SampleInfoList(Samples.Select(s => new SampleInfo + Samples = new List(Samples.Select(s => new SampleInfo { Bank = s.Bank, Name = @"slidertick", @@ -147,7 +147,7 @@ namespace osu.Game.Rulesets.Catch.Objects set { Curve.ControlPoints = value; } } - public List RepeatSamples { get; set; } = new List(); + public List> RepeatSamples { get; set; } = new List>(); public CurveType CurveType { diff --git a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs index d5a799b4ed..407d4db143 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs @@ -192,7 +192,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps /// /// The time to retrieve the sample info list from. /// - private SampleInfoList sampleInfoListAt(double time) + private List sampleInfoListAt(double time) { var curveData = HitObject as IHasCurve; diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs index 270c264e0c..8251dea5f7 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs @@ -2,6 +2,7 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; +using System.Collections.Generic; using System.Linq; using osu.Game.Audio; using osu.Game.Beatmaps; @@ -435,7 +436,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy /// /// The time to retrieve the sample info list from. /// - private SampleInfoList sampleInfoListAt(double time) + private List sampleInfoListAt(double time) { var curveData = HitObject as IHasCurve; diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/EndTimeObjectPatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/EndTimeObjectPatternGenerator.cs index 3e9fc1ae27..8e832960df 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/EndTimeObjectPatternGenerator.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/EndTimeObjectPatternGenerator.cs @@ -1,6 +1,7 @@ // 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.Beatmaps; using osu.Game.Rulesets.Mania.MathUtils; using osu.Game.Rulesets.Objects; @@ -77,7 +78,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy }; if (hold.Head.Samples == null) - hold.Head.Samples = new SampleInfoList(); + hold.Head.Samples = new List(); hold.Head.Samples.Add(new SampleInfo { Name = SampleInfo.HIT_NORMAL }); diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs index 4f5a44e61d..5f9f11c783 100644 --- a/osu.Game.Rulesets.Osu/Objects/Slider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs @@ -57,7 +57,7 @@ namespace osu.Game.Rulesets.Osu.Objects /// internal float LazyTravelDistance; - public List RepeatSamples { get; set; } = new List(); + public List> RepeatSamples { get; set; } = new List>(); public int RepeatCount { get; set; } = 1; private int stackHeight; @@ -138,7 +138,7 @@ namespace osu.Game.Rulesets.Osu.Objects StackHeight = StackHeight, Scale = Scale, ComboColour = ComboColour, - Samples = new SampleInfoList(Samples.Select(s => new SampleInfo + Samples = new List(Samples.Select(s => new SampleInfo { Bank = s.Bank, Name = @"slidertick", @@ -170,7 +170,7 @@ namespace osu.Game.Rulesets.Osu.Objects StackHeight = StackHeight, Scale = Scale, ComboColour = ComboColour, - Samples = new SampleInfoList(RepeatSamples[repeat]) + Samples = new List(RepeatSamples[repeat]) }); } } diff --git a/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs b/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs index 9b4a6c47a9..690b80b12c 100644 --- a/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs +++ b/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs @@ -78,7 +78,7 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps var curveData = obj as IHasCurve; // Old osu! used hit sounding to determine various hit type information - SampleInfoList samples = obj.Samples; + List samples = obj.Samples; bool strong = samples.Any(s => s.Name == SampleInfo.HIT_FINISH); @@ -115,12 +115,12 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps if (!isForCurrentRuleset && tickSpacing > 0 && osuDuration < 2 * speedAdjustedBeatLength) { - List allSamples = curveData != null ? curveData.RepeatSamples : new List(new[] { samples }); + List> allSamples = curveData != null ? curveData.RepeatSamples : new List>(new[] { samples }); int i = 0; for (double j = obj.StartTime; j <= obj.StartTime + taikoDuration + tickSpacing / 8; j += tickSpacing) { - SampleInfoList currentSamples = allSamples[i]; + List currentSamples = allSamples[i]; bool isRim = currentSamples.Any(s => s.Name == SampleInfo.HIT_CLAP || s.Name == SampleInfo.HIT_WHISTLE); strong = currentSamples.Any(s => s.Name == SampleInfo.HIT_FINISH); diff --git a/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs b/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs index 4104b59979..5a566fd091 100644 --- a/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs +++ b/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs @@ -3,6 +3,7 @@ using osu.Game.Rulesets.Objects.Types; using System; +using System.Collections.Generic; using System.Linq; using osu.Game.Audio; using osu.Game.Beatmaps; @@ -75,7 +76,7 @@ namespace osu.Game.Rulesets.Taiko.Objects TickSpacing = tickSpacing, StartTime = t, IsStrong = IsStrong, - Samples = new SampleInfoList(Samples.Select(s => new SampleInfo + Samples = new List(Samples.Select(s => new SampleInfo { Bank = s.Bank, Name = @"slidertick", diff --git a/osu.Game.Rulesets.Taiko/Tests/TestCaseTaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/Tests/TestCaseTaikoPlayfield.cs index bca4806108..b1e6e9c4ce 100644 --- a/osu.Game.Rulesets.Taiko/Tests/TestCaseTaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko/Tests/TestCaseTaikoPlayfield.cs @@ -165,11 +165,15 @@ namespace osu.Game.Rulesets.Taiko.Tests private void addSwell(double duration = default_duration) { - rulesetContainer.Playfield.Add(new DrawableSwell(new Swell + var swell = new Swell { StartTime = rulesetContainer.Playfield.Time.Current + scroll_time, Duration = duration, - })); + }; + + swell.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); + + rulesetContainer.Playfield.Add(new DrawableSwell(swell)); } private void addDrumRoll(bool strong, double duration = default_duration) @@ -184,6 +188,8 @@ namespace osu.Game.Rulesets.Taiko.Tests Duration = duration, }; + d.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); + rulesetContainer.Playfield.Add(new DrawableDrumRoll(d)); } @@ -195,6 +201,8 @@ namespace osu.Game.Rulesets.Taiko.Tests IsStrong = strong }; + h.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); + if (strong) rulesetContainer.Playfield.Add(new DrawableCentreHitStrong(h)); else @@ -209,6 +217,8 @@ namespace osu.Game.Rulesets.Taiko.Tests IsStrong = strong }; + h.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); + if (strong) rulesetContainer.Playfield.Add(new DrawableRimHitStrong(h)); else diff --git a/osu.Game/Audio/SampleInfoList.cs b/osu.Game/Audio/SampleInfoList.cs deleted file mode 100644 index 06dd716a4a..0000000000 --- a/osu.Game/Audio/SampleInfoList.cs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) 2007-2017 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using System.Collections.Generic; - -namespace osu.Game.Audio -{ - public class SampleInfoList : List - { - public SampleInfoList() - { - } - - public SampleInfoList(IEnumerable elements) : base(elements) - { - } - } -} \ No newline at end of file diff --git a/osu.Game/Rulesets/Objects/HitObject.cs b/osu.Game/Rulesets/Objects/HitObject.cs index e950516bf4..56f7a2e1a2 100644 --- a/osu.Game/Rulesets/Objects/HitObject.cs +++ b/osu.Game/Rulesets/Objects/HitObject.cs @@ -32,7 +32,7 @@ namespace osu.Game.Rulesets.Objects /// and can be treated as the default samples for the hit object. /// /// - public SampleInfoList Samples; + public List Samples; [JsonIgnore] public SampleControlPoint SampleControlPoint; diff --git a/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertHitObjectParser.cs index 667f921e04..fbf02f5345 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertHitObjectParser.cs @@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Catch }; } - protected override HitObject CreateSlider(Vector2 position, bool newCombo, List controlPoints, double length, CurveType curveType, int repeatCount, List repeatSamples) + protected override HitObject CreateSlider(Vector2 position, bool newCombo, List controlPoints, double length, CurveType curveType, int repeatCount, List> repeatSamples) { return new ConvertSlider { diff --git a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs index 0d7d617405..bdbd7a9e65 100644 --- a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs @@ -127,7 +127,7 @@ namespace osu.Game.Rulesets.Objects.Legacy } // Generate the final per-node samples - var nodeSamples = new List(nodes); + var nodeSamples = new List>(nodes); for (int i = 0; i <= repeatCount; i++) nodeSamples.Add(convertSoundType(nodeSoundTypes[i], nodeBankInfos[i])); @@ -216,7 +216,7 @@ namespace osu.Game.Rulesets.Objects.Legacy /// The slider repeat count. /// The samples to be played when the repeat nodes are hit. This includes the head and tail of the slider. /// The hit object. - protected abstract HitObject CreateSlider(Vector2 position, bool newCombo, List controlPoints, double length, CurveType curveType, int repeatCount, List repeatSamples); + protected abstract HitObject CreateSlider(Vector2 position, bool newCombo, List controlPoints, double length, CurveType curveType, int repeatCount, List> repeatSamples); /// /// Creates a legacy Spinner-type hit object. @@ -234,9 +234,9 @@ namespace osu.Game.Rulesets.Objects.Legacy /// The hold end time. protected abstract HitObject CreateHold(Vector2 position, bool newCombo, double endTime); - private SampleInfoList convertSoundType(LegacySoundType type, SampleBankInfo bankInfo) + private List convertSoundType(LegacySoundType type, SampleBankInfo bankInfo) { - var soundTypes = new SampleInfoList + var soundTypes = new List { new SampleInfo { diff --git a/osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs b/osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs index 698b74cc28..6dc8a07630 100644 --- a/osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs +++ b/osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs @@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Objects.Legacy public double Distance { get; set; } - public List RepeatSamples { get; set; } + public List> RepeatSamples { get; set; } public int RepeatCount { get; set; } = 1; public double EndTime => StartTime + RepeatCount * Distance / Velocity; diff --git a/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHitObjectParser.cs index 86dd40b06e..2060b84222 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHitObjectParser.cs @@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Mania }; } - protected override HitObject CreateSlider(Vector2 position, bool newCombo, List controlPoints, double length, CurveType curveType, int repeatCount, List repeatSamples) + protected override HitObject CreateSlider(Vector2 position, bool newCombo, List controlPoints, double length, CurveType curveType, int repeatCount, List> repeatSamples) { return new ConvertSlider { diff --git a/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHitObjectParser.cs index 24c205db13..0062d29446 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHitObjectParser.cs @@ -2,9 +2,9 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using OpenTK; -using osu.Game.Audio; using osu.Game.Rulesets.Objects.Types; using System.Collections.Generic; +using osu.Game.Audio; namespace osu.Game.Rulesets.Objects.Legacy.Osu { @@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu }; } - protected override HitObject CreateSlider(Vector2 position, bool newCombo, List controlPoints, double length, CurveType curveType, int repeatCount, List repeatSamples) + protected override HitObject CreateSlider(Vector2 position, bool newCombo, List controlPoints, double length, CurveType curveType, int repeatCount, List> repeatSamples) { return new ConvertSlider { diff --git a/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHitObjectParser.cs index 0554cfd97d..529a28ac15 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHitObjectParser.cs @@ -2,9 +2,9 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using OpenTK; -using osu.Game.Audio; using osu.Game.Rulesets.Objects.Types; using System.Collections.Generic; +using osu.Game.Audio; namespace osu.Game.Rulesets.Objects.Legacy.Taiko { @@ -21,7 +21,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Taiko }; } - protected override HitObject CreateSlider(Vector2 position, bool newCombo, List controlPoints, double length, CurveType curveType, int repeatCount, List repeatSamples) + protected override HitObject CreateSlider(Vector2 position, bool newCombo, List controlPoints, double length, CurveType curveType, int repeatCount, List> repeatSamples) { return new ConvertSlider { diff --git a/osu.Game/Rulesets/Objects/Types/IHasRepeats.cs b/osu.Game/Rulesets/Objects/Types/IHasRepeats.cs index 5abad2d661..2fe2424d49 100644 --- a/osu.Game/Rulesets/Objects/Types/IHasRepeats.cs +++ b/osu.Game/Rulesets/Objects/Types/IHasRepeats.cs @@ -19,6 +19,6 @@ namespace osu.Game.Rulesets.Objects.Types /// /// The samples to be played when each repeat node is hit (0 -> first repeat node, 1 -> second repeat node, etc). /// - List RepeatSamples { get; } + List> RepeatSamples { get; } } } diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 94678106bf..1c5d20842d 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -239,7 +239,6 @@ - From 0fb620a8d3c730da1f10d1d5ab45482d783a3b2d Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 25 Dec 2017 16:41:18 +0900 Subject: [PATCH 096/122] Make HitObject.Samples non-nullable --- osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs | 5 +++-- osu.Game/Rulesets/Objects/HitObject.cs | 8 +++++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index c397ea47ef..be161b9ad3 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -84,10 +84,11 @@ namespace osu.Game.Rulesets.Objects.Drawables [BackgroundDependencyLoader] private void load(AudioManager audio) { - if (HitObject.Samples != null) + if (Samples.Count > 0) { if (HitObject.SampleControlPoint == null) - throw new ArgumentNullException(nameof(HitObject.SampleControlPoint), $"{nameof(HitObject)} must always have an attached {nameof(HitObject.SampleControlPoint)}."); + throw new ArgumentNullException(nameof(HitObject.SampleControlPoint), $"{nameof(HitObject)}s must always have an attached {nameof(HitObject.SampleControlPoint)}." + + $" This is an indication that {nameof(HitObject.ApplyDefaults)} has not been invoked on {this}."); foreach (SampleInfo s in HitObject.Samples) { diff --git a/osu.Game/Rulesets/Objects/HitObject.cs b/osu.Game/Rulesets/Objects/HitObject.cs index 56f7a2e1a2..4f06f6afe1 100644 --- a/osu.Game/Rulesets/Objects/HitObject.cs +++ b/osu.Game/Rulesets/Objects/HitObject.cs @@ -25,6 +25,8 @@ namespace osu.Game.Rulesets.Objects /// public virtual double StartTime { get; set; } + private List samples; + /// /// The samples to be played when this hit object is hit. /// @@ -32,7 +34,11 @@ namespace osu.Game.Rulesets.Objects /// and can be treated as the default samples for the hit object. /// /// - public List Samples; + public List Samples + { + get => samples ?? (samples = new List()); + set => samples = value; + } [JsonIgnore] public SampleControlPoint SampleControlPoint; From 8bfdee586b6cde7effbc17b8c3ae6b7ed1ae4dec Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 25 Dec 2017 16:47:29 +0900 Subject: [PATCH 097/122] Rename SwellSampleMapping -> DrumSampleMapping --- .../Audio/DrumSampleMapping.cs | 40 +++++++++++++++++++ .../Objects/Drawables/DrawableSwell.cs | 3 +- osu.Game.Rulesets.Taiko/Objects/Swell.cs | 15 ++----- .../Objects/SwellSampleMapping.cs | 28 ------------- .../osu.Game.Rulesets.Taiko.csproj | 2 +- 5 files changed, 47 insertions(+), 41 deletions(-) create mode 100644 osu.Game.Rulesets.Taiko/Audio/DrumSampleMapping.cs delete mode 100644 osu.Game.Rulesets.Taiko/Objects/SwellSampleMapping.cs diff --git a/osu.Game.Rulesets.Taiko/Audio/DrumSampleMapping.cs b/osu.Game.Rulesets.Taiko/Audio/DrumSampleMapping.cs new file mode 100644 index 0000000000..25fa9951df --- /dev/null +++ b/osu.Game.Rulesets.Taiko/Audio/DrumSampleMapping.cs @@ -0,0 +1,40 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using osu.Framework.Audio; +using osu.Framework.Audio.Sample; +using osu.Game.Audio; +using osu.Game.Beatmaps.ControlPoints; + +namespace osu.Game.Rulesets.Taiko.Audio +{ + public class DrumSampleMapping : IComparable + { + public double Time; + public readonly SampleInfo Centre; + public readonly SampleInfo Rim; + + public SampleChannel CentreChannel { get; private set; } + public SampleChannel RimChannel { get; private set; } + + public DrumSampleMapping() + { + } + + public DrumSampleMapping(SampleControlPoint samplePoint) + { + Time = samplePoint.Time; + Centre = samplePoint.GetSampleInfo(); + Rim = samplePoint.GetSampleInfo(SampleInfo.HIT_CLAP); + } + + public void RetrieveChannels(AudioManager audio) + { + CentreChannel = Centre.GetChannel(audio.Sample); + RimChannel = Rim.GetChannel(audio.Sample); + } + + public int CompareTo(DrumSampleMapping other) => Time.CompareTo(other.Time); + } +} diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs index d657598554..5131572abd 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs @@ -15,6 +15,7 @@ using OpenTK.Graphics; using osu.Framework.Graphics.Shapes; using osu.Game.Rulesets.Taiko.Judgements; using osu.Framework.Audio; +using osu.Game.Rulesets.Taiko.Audio; namespace osu.Game.Rulesets.Taiko.Objects.Drawables { @@ -228,7 +229,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables // While the swell hasn't been fully judged, input is still blocked so it doesn't fall through to other hitobjects // This causes the playfield to not play sounds, so they need to be handled locally - var mappingIndex = HitObject.ProgressionSamples.BinarySearch(new SwellSampleMapping { Time = Time.Current }); + var mappingIndex = HitObject.ProgressionSamples.BinarySearch(new DrumSampleMapping { Time = Time.Current }); if (mappingIndex < 0) mappingIndex = ~mappingIndex - 1; diff --git a/osu.Game.Rulesets.Taiko/Objects/Swell.cs b/osu.Game.Rulesets.Taiko/Objects/Swell.cs index b4fa736045..849c88ee4d 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Swell.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Swell.cs @@ -7,6 +7,7 @@ using osu.Game.Audio; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Rulesets.Objects.Types; +using osu.Game.Rulesets.Taiko.Audio; namespace osu.Game.Rulesets.Taiko.Objects { @@ -21,25 +22,17 @@ namespace osu.Game.Rulesets.Taiko.Objects /// public int RequiredHits = 10; - public List ProgressionSamples = new List(); + public List ProgressionSamples = new List(); protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) { base.ApplyDefaultsToSelf(controlPointInfo, difficulty); - var progressionSamplePoints = - new[] { controlPointInfo.SamplePointAt(StartTime) } + var progressionSamplePoints = new[] { controlPointInfo.SamplePointAt(StartTime) } .Concat(controlPointInfo.SamplePoints.Where(p => p.Time > StartTime && p.Time <= EndTime)); foreach (var point in progressionSamplePoints) - { - ProgressionSamples.Add(new SwellSampleMapping - { - Time = point.Time, - Centre = point.GetSampleInfo(), - Rim = point.GetSampleInfo(SampleInfo.HIT_CLAP) - }); - } + ProgressionSamples.Add(new DrumSampleMapping(point)); } } } diff --git a/osu.Game.Rulesets.Taiko/Objects/SwellSampleMapping.cs b/osu.Game.Rulesets.Taiko/Objects/SwellSampleMapping.cs deleted file mode 100644 index 99d0e1d0fd..0000000000 --- a/osu.Game.Rulesets.Taiko/Objects/SwellSampleMapping.cs +++ /dev/null @@ -1,28 +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 osu.Framework.Audio; -using osu.Framework.Audio.Sample; -using osu.Game.Audio; - -namespace osu.Game.Rulesets.Taiko.Objects -{ - public class SwellSampleMapping : IComparable - { - public double Time; - public SampleInfo Centre; - public SampleInfo Rim; - - public SampleChannel CentreChannel { get; private set; } - public SampleChannel RimChannel { get; private set; } - - public void RetrieveChannels(AudioManager audio) - { - CentreChannel = Centre.GetChannel(audio.Sample); - RimChannel = Rim.GetChannel(audio.Sample); - } - - public int CompareTo(SwellSampleMapping other) => Time.CompareTo(other.Time); - } -} diff --git a/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj b/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj index 9fa3936153..f1c29c1a34 100644 --- a/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj +++ b/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj @@ -44,6 +44,7 @@ + @@ -74,7 +75,6 @@ - From ac8b345bfebba4530c67bbf9d0087472825ace18 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 25 Dec 2017 17:29:20 +0900 Subject: [PATCH 098/122] Make TaikoPlayfield use the new DrumSampleMapping --- osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs | 37 +++++++++----------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs index 2cc95fc981..96ef86e3ce 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs @@ -23,6 +23,7 @@ using osu.Framework.Audio.Sample; using System.Collections.Generic; using osu.Game.Audio; using System; +using osu.Game.Rulesets.Taiko.Audio; namespace osu.Game.Rulesets.Taiko.UI { @@ -62,7 +63,7 @@ namespace osu.Game.Rulesets.Taiko.UI private readonly Box background; private readonly ControlPointInfo controlPointInfo; - private Dictionary drumSampleMappings; + private readonly List drumSampleMappings = new List(); public TaikoPlayfield(ControlPointInfo controlPointInfo) : base(Axes.X) @@ -207,15 +208,16 @@ namespace osu.Game.Rulesets.Taiko.UI [BackgroundDependencyLoader] private void load(OsuColour colours, AudioManager audio) { - drumSampleMappings = new Dictionary(); - foreach (var s in controlPointInfo.SamplePoints) + // We may have 0 sample points, but we need at least the default one + var samplePoints = new[] { controlPointInfo.SamplePointAt(double.MinValue) } + .Concat(controlPointInfo.SamplePoints); + + foreach (var s in samplePoints) { - drumSampleMappings.Add(s, - new DrumSamples - { - Centre = s.GetSampleInfo().GetChannel(audio.Sample), - Rim = s.GetSampleInfo(SampleInfo.HIT_CLAP).GetChannel(audio.Sample) - }); + var mapping = new DrumSampleMapping(s); + mapping.RetrieveChannels(audio); + + drumSampleMappings.Add(mapping); } overlayBackgroundContainer.BorderColour = colours.Gray0; @@ -285,25 +287,20 @@ namespace osu.Game.Rulesets.Taiko.UI public bool OnPressed(TaikoAction action) { - var samplePoint = controlPointInfo.SamplePointAt(Clock.CurrentTime); + var mappingIndex = drumSampleMappings.BinarySearch(new DrumSampleMapping { Time = Time.Current }); + if (mappingIndex < 0) + mappingIndex = ~mappingIndex - 1; - if (!drumSampleMappings.TryGetValue(samplePoint, out var samples)) - throw new InvalidOperationException("Current sample set not found."); + var mapping = drumSampleMappings[mappingIndex]; if (action == TaikoAction.LeftCentre || action == TaikoAction.RightCentre) - samples.Centre.Play(); + mapping.CentreChannel.Play(); else - samples.Rim.Play(); + mapping.RimChannel.Play(); return true; } public bool OnReleased(TaikoAction action) => false; - - private class DrumSamples - { - public SampleChannel Centre; - public SampleChannel Rim; - } } } From affdd81563b21d0fdfec753bc2dcdc46cb417ad9 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 25 Dec 2017 17:29:44 +0900 Subject: [PATCH 099/122] Remove unused usings --- osu.Game.Rulesets.Taiko/Objects/Swell.cs | 1 - osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs | 3 --- 2 files changed, 4 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Objects/Swell.cs b/osu.Game.Rulesets.Taiko/Objects/Swell.cs index 849c88ee4d..714e5d29ee 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Swell.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Swell.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.Linq; -using osu.Game.Audio; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Rulesets.Objects.Types; diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs index 96ef86e3ce..229e44cf27 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs @@ -19,10 +19,7 @@ using osu.Game.Rulesets.Taiko.Objects.Drawables; using osu.Framework.Input.Bindings; using osu.Game.Beatmaps.ControlPoints; using osu.Framework.Audio; -using osu.Framework.Audio.Sample; using System.Collections.Generic; -using osu.Game.Audio; -using System; using osu.Game.Rulesets.Taiko.Audio; namespace osu.Game.Rulesets.Taiko.UI From bb4b5bebf915eaf845d702e10b2285274c510839 Mon Sep 17 00:00:00 2001 From: Aergwyn Date: Mon, 25 Dec 2017 15:25:47 +0100 Subject: [PATCH 100/122] fix supporter icon in profile missing its background also it doesn't show up on profiles without supporter anymore --- osu.Game.Tests/Visual/TestCaseUserProfile.cs | 25 +++++++- osu.Game/Overlays/Profile/ProfileHeader.cs | 31 +++------- osu.Game/Overlays/Profile/SupporterIcon.cs | 61 ++++++++++++++++++++ osu.Game/Overlays/UserProfileOverlay.cs | 8 +-- osu.Game/Users/UserPanel.cs | 50 +--------------- osu.Game/osu.Game.csproj | 1 + 6 files changed, 97 insertions(+), 79 deletions(-) create mode 100644 osu.Game/Overlays/Profile/SupporterIcon.cs diff --git a/osu.Game.Tests/Visual/TestCaseUserProfile.cs b/osu.Game.Tests/Visual/TestCaseUserProfile.cs index 38d59f03b5..88627755f4 100644 --- a/osu.Game.Tests/Visual/TestCaseUserProfile.cs +++ b/osu.Game.Tests/Visual/TestCaseUserProfile.cs @@ -13,6 +13,8 @@ namespace osu.Game.Tests.Visual { public class TestCaseUserProfile : OsuTestCase { + private readonly TestUserProfileOverlay profile; + public override IReadOnlyList RequiredTypes => new[] { typeof(ProfileHeader), @@ -23,8 +25,7 @@ namespace osu.Game.Tests.Visual public TestCaseUserProfile() { - var profile = new UserProfileOverlay(); - Add(profile); + Add(profile = new TestUserProfileOverlay()); AddStep("Show offline dummy", () => profile.ShowUser(new User { @@ -48,6 +49,9 @@ namespace osu.Game.Tests.Visual Data = Enumerable.Range(2345, 45).Concat(Enumerable.Range(2109, 40)).ToArray() } }, false)); + + checkSupporterTag(false); + AddStep("Show ppy", () => profile.ShowUser(new User { Username = @"peppy", @@ -55,6 +59,9 @@ namespace osu.Game.Tests.Visual Country = new Country { FullName = @"Australia", FlagName = @"AU" }, CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c3.jpg" })); + + checkSupporterTag(true); + AddStep("Show flyte", () => profile.ShowUser(new User { Username = @"flyte", @@ -62,8 +69,22 @@ namespace osu.Game.Tests.Visual Country = new Country { FullName = @"Japan", FlagName = @"JP" }, CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c6.jpg" })); + AddStep("Hide", profile.Hide); AddStep("Show without reload", profile.Show); } + + private void checkSupporterTag(bool isSupporter) + { + AddUntilStep(() => profile.Header.User != null, "wait for load"); + if(isSupporter) + AddAssert("is supporter", () => profile.Header.SupporterTag.Alpha == 1); + else + AddAssert("no supporter", () => profile.Header.SupporterTag.Alpha == 0); + } + + private class TestUserProfileOverlay : UserProfileOverlay { + public new ProfileHeader Header => base.Header; + } } } diff --git a/osu.Game/Overlays/Profile/ProfileHeader.cs b/osu.Game/Overlays/Profile/ProfileHeader.cs index a706799664..f000ca74d4 100644 --- a/osu.Game/Overlays/Profile/ProfileHeader.cs +++ b/osu.Game/Overlays/Profile/ProfileHeader.cs @@ -29,7 +29,8 @@ namespace osu.Game.Overlays.Profile private readonly FillFlowContainer scoreText, scoreNumberText; private readonly RankGraph rankGraph; - private readonly Container coverContainer, supporterTag; + public readonly SupporterIcon SupporterTag; + private readonly Container coverContainer; private readonly Sprite levelBadge; private readonly SpriteText levelText; private readonly GradeBadge gradeSSPlus, gradeSS, gradeSPlus, gradeS, gradeA; @@ -94,32 +95,13 @@ namespace osu.Game.Overlays.Profile AutoSizeAxes = Axes.Both, Children = new Drawable[] { - supporterTag = new CircularContainer + SupporterTag = new SupporterIcon { + Alpha = 0, Anchor = Anchor.BottomLeft, Origin = Anchor.BottomLeft, Y = -75, - Size = new Vector2(25, 25), - Masking = true, - BorderThickness = 3, - BorderColour = Color4.White, - Alpha = 0, - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Alpha = 0, - AlwaysPresent = true - }, - new SpriteIcon - { - Icon = FontAwesome.fa_heart, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Size = new Vector2(12), - } - } + Size = new Vector2(25, 25) }, new LinkFlowContainer.ProfileLink(user) { @@ -328,7 +310,8 @@ namespace osu.Game.Overlays.Profile Depth = float.MaxValue, }, coverContainer.Add); - if (user.IsSupporter) supporterTag.Show(); + if (user.IsSupporter) + SupporterTag.Show(); if (!string.IsNullOrEmpty(user.Colour)) { diff --git a/osu.Game/Overlays/Profile/SupporterIcon.cs b/osu.Game/Overlays/Profile/SupporterIcon.cs new file mode 100644 index 0000000000..570d5a13bb --- /dev/null +++ b/osu.Game/Overlays/Profile/SupporterIcon.cs @@ -0,0 +1,61 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using OpenTK; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Game.Graphics; +using osu.Game.Graphics.Backgrounds; + +namespace osu.Game.Overlays.Profile +{ + public class SupporterIcon : CircularContainer + { + private readonly Box background; + + public SupporterIcon() + { + Masking = true; + Children = new Drawable[] + { + new Box { RelativeSizeAxes = Axes.Both }, + new CircularContainer + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Scale = new Vector2(0.8f), + Masking = true, + Children = new Drawable[] + { + background = new Box { RelativeSizeAxes = Axes.Both }, + new Triangles + { + TriangleScale = 0.2f, + ColourLight = OsuColour.FromHex(@"ff7db7"), + ColourDark = OsuColour.FromHex(@"de5b95"), + RelativeSizeAxes = Axes.Both, + Velocity = 0.3f, + }, + } + }, + new SpriteIcon + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Icon = FontAwesome.fa_heart, + Scale = new Vector2(0.45f), + } + }; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + background.Colour = colours.Pink; + } + } +} diff --git a/osu.Game/Overlays/UserProfileOverlay.cs b/osu.Game/Overlays/UserProfileOverlay.cs index 7374a9aa44..9aa660147a 100644 --- a/osu.Game/Overlays/UserProfileOverlay.cs +++ b/osu.Game/Overlays/UserProfileOverlay.cs @@ -28,7 +28,7 @@ namespace osu.Game.Overlays private ProfileSection[] sections; private GetUserRequest userReq; private APIAccess api; - private ProfileHeader header; + protected ProfileHeader Header; private SectionsContainer sectionsContainer; private ProfileTabControl tabs; @@ -113,12 +113,12 @@ namespace osu.Game.Overlays Colour = OsuColour.Gray(0.2f) }); - header = new ProfileHeader(user); + Header = new ProfileHeader(user); Add(sectionsContainer = new SectionsContainer { RelativeSizeAxes = Axes.Both, - ExpandableHeader = header, + ExpandableHeader = Header, FixedHeader = tabs, HeaderBackground = new Box { @@ -169,7 +169,7 @@ namespace osu.Game.Overlays private void userLoadComplete(User user) { - header.User = user; + Header.User = user; foreach (string id in user.ProfileOrder) { diff --git a/osu.Game/Users/UserPanel.cs b/osu.Game/Users/UserPanel.cs index d056afcf54..a2cc8e8d49 100644 --- a/osu.Game/Users/UserPanel.cs +++ b/osu.Game/Users/UserPanel.cs @@ -16,8 +16,8 @@ using osu.Game.Overlays; using osu.Framework.Graphics.UserInterface; using osu.Game.Graphics.UserInterface; using osu.Framework.Graphics.Cursor; -using osu.Game.Graphics.Backgrounds; using osu.Game.Graphics.Containers; +using osu.Game.Overlays.Profile; namespace osu.Game.Users { @@ -220,53 +220,5 @@ namespace osu.Game.Users { new OsuMenuItem("View Profile", MenuItemType.Highlighted, ViewProfile), }; - - private class SupporterIcon : CircularContainer - { - private readonly Box background; - - public SupporterIcon() - { - Masking = true; - Children = new Drawable[] - { - new Box { RelativeSizeAxes = Axes.Both }, - new CircularContainer - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - Scale = new Vector2(0.8f), - Masking = true, - Children = new Drawable[] - { - background = new Box { RelativeSizeAxes = Axes.Both }, - new Triangles - { - TriangleScale = 0.2f, - ColourLight = OsuColour.FromHex(@"ff7db7"), - ColourDark = OsuColour.FromHex(@"de5b95"), - RelativeSizeAxes = Axes.Both, - Velocity = 0.3f, - }, - } - }, - new SpriteIcon - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - Icon = FontAwesome.fa_heart, - Scale = new Vector2(0.45f), - } - }; - } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - background.Colour = colours.Pink; - } - } } } diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 94678106bf..18134582f3 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -268,6 +268,7 @@ + From f76878e2fea6b2e7fd23163cd9d42dc6211f623d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 26 Dec 2017 00:34:12 +0900 Subject: [PATCH 101/122] Add a very basic popup testcase --- osu.Game.Tests/Visual/TestCasePopupDialog.cs | 37 ++++++++++++++++++++ osu.Game.Tests/osu.Game.Tests.csproj | 1 + 2 files changed, 38 insertions(+) create mode 100644 osu.Game.Tests/Visual/TestCasePopupDialog.cs diff --git a/osu.Game.Tests/Visual/TestCasePopupDialog.cs b/osu.Game.Tests/Visual/TestCasePopupDialog.cs new file mode 100644 index 0000000000..ed9c47a253 --- /dev/null +++ b/osu.Game.Tests/Visual/TestCasePopupDialog.cs @@ -0,0 +1,37 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Graphics; +using osu.Game.Graphics; +using osu.Game.Overlays.Dialog; + +namespace osu.Game.Tests.Visual +{ + public class TestCasePopupDialog : OsuTestCase + { + public TestCasePopupDialog() + { + var popup = new PopupDialog + { + RelativeSizeAxes = Axes.Both, + State = Framework.Graphics.Containers.Visibility.Visible, + Icon = FontAwesome.fa_assistive_listening_systems, + HeaderText = @"This is a test popup", + BodyText = "I can say lots of stuff and even wrap my words!", + Buttons = new PopupDialogButton[] + { + new PopupDialogCancelButton + { + Text = @"Yes. That you can.", + }, + new PopupDialogOkButton + { + Text = @"You're a fake!", + }, + } + }; + + Add(popup); + } + } +} diff --git a/osu.Game.Tests/osu.Game.Tests.csproj b/osu.Game.Tests/osu.Game.Tests.csproj index ff012bb6e2..134fc4a6ac 100644 --- a/osu.Game.Tests/osu.Game.Tests.csproj +++ b/osu.Game.Tests/osu.Game.Tests.csproj @@ -134,6 +134,7 @@ + From 929633efaa8ad611969e678a9cfe796d4014b86b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 26 Dec 2017 00:34:40 +0900 Subject: [PATCH 102/122] Make body text in popups word wrap properly --- osu.Game/Overlays/Dialog/PopupDialog.cs | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/osu.Game/Overlays/Dialog/PopupDialog.cs b/osu.Game/Overlays/Dialog/PopupDialog.cs index 9b19b8150e..d2bd50cad6 100644 --- a/osu.Game/Overlays/Dialog/PopupDialog.cs +++ b/osu.Game/Overlays/Dialog/PopupDialog.cs @@ -32,7 +32,7 @@ namespace osu.Game.Overlays.Dialog private readonly FillFlowContainer buttonsContainer; private readonly SpriteIcon icon; private readonly SpriteText header; - private readonly SpriteText body; + private readonly TextFlowContainer body; public FontAwesome Icon { @@ -48,7 +48,6 @@ namespace osu.Game.Overlays.Dialog public string BodyText { - get { return body.Text; } set { body.Text = value; } } @@ -220,17 +219,15 @@ namespace osu.Game.Overlays.Dialog { Origin = Anchor.TopCentre, Anchor = Anchor.TopCentre, - Text = @"Header", TextSize = 25, Shadow = true, }, - body = new OsuSpriteText + body = new OsuTextFlowContainer(t => t.TextSize = 18) { - Origin = Anchor.TopCentre, - Anchor = Anchor.TopCentre, - Text = @"Body", - TextSize = 18, - Shadow = true, + Padding = new MarginPadding(15), + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + TextAnchor = Anchor.TopCentre, }, }, }, From 3c1654e5e496d8c22927019ca9a90d0177045b58 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 26 Dec 2017 00:44:35 +0900 Subject: [PATCH 103/122] Fix many instances of non-osu-prefixed text classes being used Results in incorrect default formatting. --- osu.Game/Overlays/BeatmapSet/Info.cs | 3 ++- osu.Game/Overlays/MedalSplash/DrawableMedal.cs | 3 ++- osu.Game/Overlays/Notifications/ProgressNotification.cs | 3 ++- osu.Game/Overlays/Notifications/SimpleNotification.cs | 5 +++-- osu.Game/Overlays/OnScreenDisplay.cs | 7 ++++--- osu.Game/Overlays/Profile/ProfileHeader.cs | 2 +- osu.Game/Overlays/Profile/Sections/Kudosu/KudosuInfo.cs | 3 ++- osu.Game/Screens/Ranking/Results.cs | 9 +++++---- osu.Game/Screens/Ranking/ResultsPageScore.cs | 4 ++-- osu.Game/Screens/Select/BeatmapDetails.cs | 5 +++-- osu.Game/Tests/Visual/TestCasePerformancePoints.cs | 3 +-- osu.sln.DotSettings | 5 +++++ 12 files changed, 32 insertions(+), 20 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSet/Info.cs b/osu.Game/Overlays/BeatmapSet/Info.cs index bd108a193b..b4aea898b2 100644 --- a/osu.Game/Overlays/BeatmapSet/Info.cs +++ b/osu.Game/Overlays/BeatmapSet/Info.cs @@ -8,6 +8,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Game.Beatmaps; using osu.Game.Graphics; +using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using OpenTK; using OpenTK.Graphics; @@ -176,7 +177,7 @@ namespace osu.Game.Overlays.BeatmapSet Shadow = false, Margin = new MarginPadding { Top = 20 }, }, - textFlow = new TextFlowContainer + textFlow = new OsuTextFlowContainer { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, diff --git a/osu.Game/Overlays/MedalSplash/DrawableMedal.cs b/osu.Game/Overlays/MedalSplash/DrawableMedal.cs index 53d77dab6c..c6be428987 100644 --- a/osu.Game/Overlays/MedalSplash/DrawableMedal.cs +++ b/osu.Game/Overlays/MedalSplash/DrawableMedal.cs @@ -10,6 +10,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; using osu.Game.Graphics; +using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Users; @@ -88,7 +89,7 @@ namespace osu.Game.Overlays.MedalSplash Alpha = 0f, Scale = new Vector2(1f / scale_when_full), }, - description = new TextFlowContainer + description = new OsuTextFlowContainer { TextAnchor = Anchor.TopCentre, Anchor = Anchor.TopCentre, diff --git a/osu.Game/Overlays/Notifications/ProgressNotification.cs b/osu.Game/Overlays/Notifications/ProgressNotification.cs index 12c7fe64ba..9211c227f8 100644 --- a/osu.Game/Overlays/Notifications/ProgressNotification.cs +++ b/osu.Game/Overlays/Notifications/ProgressNotification.cs @@ -7,6 +7,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; +using osu.Game.Graphics.Containers; using OpenTK; using OpenTK.Graphics; @@ -114,7 +115,7 @@ namespace osu.Game.Overlays.Notifications RelativeSizeAxes = Axes.Both, }); - Content.Add(textDrawable = new TextFlowContainer(t => + Content.Add(textDrawable = new OsuTextFlowContainer(t => { t.TextSize = 16; }) diff --git a/osu.Game/Overlays/Notifications/SimpleNotification.cs b/osu.Game/Overlays/Notifications/SimpleNotification.cs index daf1ac838d..0b8b365c48 100644 --- a/osu.Game/Overlays/Notifications/SimpleNotification.cs +++ b/osu.Game/Overlays/Notifications/SimpleNotification.cs @@ -7,6 +7,7 @@ using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; +using osu.Game.Graphics.Containers; using OpenTK; namespace osu.Game.Overlays.Notifications @@ -58,7 +59,7 @@ namespace osu.Game.Overlays.Notifications } }); - Content.Add(textDrawable = new TextFlowContainer(t => t.TextSize = 16) + Content.Add(textDrawable = new OsuTextFlowContainer(t => t.TextSize = 16) { Colour = OsuColour.Gray(128), AutoSizeAxes = Axes.Y, @@ -87,4 +88,4 @@ namespace osu.Game.Overlays.Notifications } } } -} \ No newline at end of file +} diff --git a/osu.Game/Overlays/OnScreenDisplay.cs b/osu.Game/Overlays/OnScreenDisplay.cs index dcab942522..ce0feeb4c6 100644 --- a/osu.Game/Overlays/OnScreenDisplay.cs +++ b/osu.Game/Overlays/OnScreenDisplay.cs @@ -14,6 +14,7 @@ using osu.Game.Graphics; using OpenTK; using OpenTK.Graphics; using osu.Framework.Extensions.Color4Extensions; +using osu.Game.Graphics.Sprites; namespace osu.Game.Overlays { @@ -63,7 +64,7 @@ namespace osu.Game.Overlays Width = 240, RelativeSizeAxes = Axes.Y, }, - textLine1 = new SpriteText + textLine1 = new OsuSpriteText { Padding = new MarginPadding(10), Font = @"Exo2.0-Black", @@ -72,7 +73,7 @@ namespace osu.Game.Overlays Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, }, - textLine2 = new SpriteText + textLine2 = new OsuSpriteText { TextSize = 24, Font = @"Exo2.0-Light", @@ -97,7 +98,7 @@ namespace osu.Game.Overlays Origin = Anchor.TopCentre, AutoSizeAxes = Axes.Both }, - textLine3 = new SpriteText + textLine3 = new OsuSpriteText { Padding = new MarginPadding { Bottom = 15 }, Font = @"Exo2.0-Bold", diff --git a/osu.Game/Overlays/Profile/ProfileHeader.cs b/osu.Game/Overlays/Profile/ProfileHeader.cs index a706799664..4cdb6ec958 100644 --- a/osu.Game/Overlays/Profile/ProfileHeader.cs +++ b/osu.Game/Overlays/Profile/ProfileHeader.cs @@ -473,7 +473,7 @@ namespace osu.Game.Overlays.Profile Width = width, Height = 26 }); - Add(numberText = new SpriteText + Add(numberText = new OsuSpriteText { Anchor = Anchor.BottomCentre, Origin = Anchor.BottomCentre, diff --git a/osu.Game/Overlays/Profile/Sections/Kudosu/KudosuInfo.cs b/osu.Game/Overlays/Profile/Sections/Kudosu/KudosuInfo.cs index 8a835634b8..904ed609e8 100644 --- a/osu.Game/Overlays/Profile/Sections/Kudosu/KudosuInfo.cs +++ b/osu.Game/Overlays/Profile/Sections/Kudosu/KudosuInfo.cs @@ -10,6 +10,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Input; using osu.Game.Graphics; +using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Users; @@ -120,7 +121,7 @@ namespace osu.Game.Overlays.Profile.Sections.Kudosu } } }, - new TextFlowContainer(t => { t.TextSize = 19; }) + new OsuTextFlowContainer(t => { t.TextSize = 19; }) { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, diff --git a/osu.Game/Screens/Ranking/Results.cs b/osu.Game/Screens/Ranking/Results.cs index 8e27cb235c..406887624c 100644 --- a/osu.Game/Screens/Ranking/Results.cs +++ b/osu.Game/Screens/Ranking/Results.cs @@ -17,6 +17,7 @@ using OpenTK.Graphics; using osu.Game.Graphics; using osu.Game.Graphics.UserInterface; using osu.Framework.Graphics.Shapes; +using osu.Game.Graphics.Sprites; namespace osu.Game.Screens.Ranking { @@ -183,7 +184,7 @@ namespace osu.Game.Screens.Ranking Height = 50, Margin = new MarginPadding { Bottom = 110 }, }, - new SpriteText + new OsuSpriteText { Text = $"{score.MaxCombo}x", TextSize = 40, @@ -194,7 +195,7 @@ namespace osu.Game.Screens.Ranking Anchor = Anchor.CentreLeft, Origin = Anchor.BottomCentre, }, - new SpriteText + new OsuSpriteText { Text = "max combo", TextSize = 20, @@ -204,7 +205,7 @@ namespace osu.Game.Screens.Ranking Anchor = Anchor.CentreLeft, Origin = Anchor.TopCentre, }, - new SpriteText + new OsuSpriteText { Text = $"{score.Accuracy:P2}", TextSize = 40, @@ -215,7 +216,7 @@ namespace osu.Game.Screens.Ranking Anchor = Anchor.CentreLeft, Origin = Anchor.BottomCentre, }, - new SpriteText + new OsuSpriteText { Text = "accuracy", TextSize = 20, diff --git a/osu.Game/Screens/Ranking/ResultsPageScore.cs b/osu.Game/Screens/Ranking/ResultsPageScore.cs index 911b688669..4c776aa7ab 100644 --- a/osu.Game/Screens/Ranking/ResultsPageScore.cs +++ b/osu.Game/Screens/Ranking/ResultsPageScore.cs @@ -201,14 +201,14 @@ namespace osu.Game.Screens.Ranking { Children = new Drawable[] { - new SpriteText { + new OsuSpriteText { Text = statistic.Value.ToString().PadLeft(4, '0'), Colour = colours.Gray7, TextSize = 30, Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, }, - new SpriteText { + new OsuSpriteText { Text = statistic.Key, Colour = colours.Gray7, Font = @"Exo2.0-Bold", diff --git a/osu.Game/Screens/Select/BeatmapDetails.cs b/osu.Game/Screens/Select/BeatmapDetails.cs index a9a778fe17..79d76dd00e 100644 --- a/osu.Game/Screens/Select/BeatmapDetails.cs +++ b/osu.Game/Screens/Select/BeatmapDetails.cs @@ -17,6 +17,7 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Extensions.Color4Extensions; using osu.Game.Screens.Select.Details; using osu.Game.Beatmaps; +using osu.Game.Graphics.Containers; namespace osu.Game.Screens.Select { @@ -334,7 +335,7 @@ namespace osu.Game.Screens.Select TextSize = 14, }, }, - textFlow = new TextFlowContainer + textFlow = new OsuTextFlowContainer { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, @@ -359,7 +360,7 @@ namespace osu.Game.Screens.Select private void setTextAsync(string text) { - LoadComponentAsync(new TextFlowContainer(s => s.TextSize = 14) + LoadComponentAsync(new OsuTextFlowContainer(s => s.TextSize = 14) { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, diff --git a/osu.Game/Tests/Visual/TestCasePerformancePoints.cs b/osu.Game/Tests/Visual/TestCasePerformancePoints.cs index f71bece279..8984fc843f 100644 --- a/osu.Game/Tests/Visual/TestCasePerformancePoints.cs +++ b/osu.Game/Tests/Visual/TestCasePerformancePoints.cs @@ -12,7 +12,6 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.Sprites; using osu.Framework.Input; using osu.Game.Beatmaps; using osu.Game.Graphics.Sprites; @@ -224,7 +223,7 @@ namespace osu.Game.Tests.Visual if (!api.IsLoggedIn) { - InternalChild = new SpriteText + InternalChild = new OsuSpriteText { Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, diff --git a/osu.sln.DotSettings b/osu.sln.DotSettings index 2f52881d6d..20007e3306 100644 --- a/osu.sln.DotSettings +++ b/osu.sln.DotSettings @@ -172,6 +172,7 @@ NEXT_LINE NEXT_LINE True + NEVER False False True @@ -655,7 +656,11 @@ Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-frame <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> True + True + True + True True True + True True True From 3c8d30f8e67158ce5b105ce28eff9b726aa09093 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 26 Dec 2017 00:37:50 +0900 Subject: [PATCH 104/122] Add a dialog offering to import beatmaps from stable --- osu.Game/Beatmaps/BeatmapManager.cs | 6 ++-- .../Sections/Maintenance/GeneralSettings.cs | 3 +- .../Screens/Select/ImportFromStablePopup.cs | 33 +++++++++++++++++++ osu.Game/Screens/Select/PlaySongSelect.cs | 15 +++++++-- osu.Game/osu.Game.csproj | 1 + 5 files changed, 52 insertions(+), 6 deletions(-) create mode 100644 osu.Game/Screens/Select/ImportFromStablePopup.cs diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 0325785016..c86860f7b0 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -697,10 +697,12 @@ namespace osu.Game.Beatmaps } } + public bool StableInstallationAvailable => GetStableStorage?.Invoke() != null; + /// /// This is a temporary method and will likely be replaced by a full-fledged (and more correctly placed) migration process in the future. /// - public void ImportFromStable() + public async Task ImportFromStable() { var stable = GetStableStorage?.Invoke(); @@ -710,7 +712,7 @@ namespace osu.Game.Beatmaps return; } - Import(stable.GetDirectories("Songs")); + await Task.Factory.StartNew(() => Import(stable.GetDirectories("Songs")), TaskCreationOptions.LongRunning); } public void DeleteAll() diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs index e288445c6d..9ab4143613 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs @@ -30,8 +30,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance Action = () => { importButton.Enabled.Value = false; - Task.Factory.StartNew(beatmaps.ImportFromStable) - .ContinueWith(t => Schedule(() => importButton.Enabled.Value = true), TaskContinuationOptions.LongRunning); + beatmaps.ImportFromStable().ContinueWith(t => Schedule(() => importButton.Enabled.Value = true)); } }, deleteButton = new DangerousSettingsButton diff --git a/osu.Game/Screens/Select/ImportFromStablePopup.cs b/osu.Game/Screens/Select/ImportFromStablePopup.cs new file mode 100644 index 0000000000..489ab79fa4 --- /dev/null +++ b/osu.Game/Screens/Select/ImportFromStablePopup.cs @@ -0,0 +1,33 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using osu.Game.Graphics; +using osu.Game.Overlays.Dialog; + +namespace osu.Game.Screens.Select +{ + public class ImportFromStablePopup : PopupDialog + { + public ImportFromStablePopup(Action importFromStable) + { + HeaderText = @"You have no beatmaps!"; + BodyText = "An existing copy of osu! was found, though.\nWould you like to import your beatmaps?"; + + Icon = FontAwesome.fa_trash_o; + + Buttons = new PopupDialogButton[] + { + new PopupDialogOkButton + { + Text = @"Yes please!", + Action = importFromStable + }, + new PopupDialogCancelButton + { + Text = @"No, I'd like to start from scratch", + }, + }; + } + } +} diff --git a/osu.Game/Screens/Select/PlaySongSelect.cs b/osu.Game/Screens/Select/PlaySongSelect.cs index 4a0ee31fbb..727cdb9959 100644 --- a/osu.Game/Screens/Select/PlaySongSelect.cs +++ b/osu.Game/Screens/Select/PlaySongSelect.cs @@ -11,6 +11,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Screens; using osu.Game.Beatmaps; using osu.Game.Graphics; +using osu.Game.Overlays; using osu.Game.Overlays.Mods; using osu.Game.Screens.Edit; using osu.Game.Screens.Play; @@ -45,8 +46,8 @@ namespace osu.Game.Screens.Select private SampleChannel sampleConfirm; - [BackgroundDependencyLoader] - private void load(OsuColour colours, AudioManager audio) + [BackgroundDependencyLoader(true)] + private void load(OsuColour colours, AudioManager audio, BeatmapManager beatmaps, DialogOverlay dialogOverlay) { sampleConfirm = audio.Sample.Get(@"SongSelect/confirm-selection"); @@ -59,6 +60,16 @@ namespace osu.Game.Screens.Select ValidForResume = false; Push(new Editor()); }, Key.Number3); + + if (dialogOverlay != null) + { + Schedule(() => + { + // if we have no beatmaps but osu-stable is found, let's prompt the user to import. + if (!beatmaps.GetAllUsableBeatmapSets().Any() && beatmaps.StableInstallationAvailable) + dialogOverlay.Push(new ImportFromStablePopup(() => beatmaps.ImportFromStable())); + }); + } } protected override void UpdateBeatmap(WorkingBeatmap beatmap) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 94678106bf..fa25fa7048 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -310,6 +310,7 @@ + From 48e55a06865ab8cf50987edfb588c3d6b7ba3d71 Mon Sep 17 00:00:00 2001 From: Aergwyn Date: Mon, 25 Dec 2017 16:52:17 +0100 Subject: [PATCH 105/122] fix formatting and test add missing line --- osu.Game.Tests/Visual/TestCaseUserProfile.cs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseUserProfile.cs b/osu.Game.Tests/Visual/TestCaseUserProfile.cs index 88627755f4..13b6509740 100644 --- a/osu.Game.Tests/Visual/TestCaseUserProfile.cs +++ b/osu.Game.Tests/Visual/TestCaseUserProfile.cs @@ -26,6 +26,11 @@ namespace osu.Game.Tests.Visual public TestCaseUserProfile() { Add(profile = new TestUserProfileOverlay()); + } + + protected override void LoadComplete() + { + base.LoadComplete(); AddStep("Show offline dummy", () => profile.ShowUser(new User { @@ -77,13 +82,14 @@ namespace osu.Game.Tests.Visual private void checkSupporterTag(bool isSupporter) { AddUntilStep(() => profile.Header.User != null, "wait for load"); - if(isSupporter) + if (isSupporter) AddAssert("is supporter", () => profile.Header.SupporterTag.Alpha == 1); else AddAssert("no supporter", () => profile.Header.SupporterTag.Alpha == 0); } - private class TestUserProfileOverlay : UserProfileOverlay { + private class TestUserProfileOverlay : UserProfileOverlay + { public new ProfileHeader Header => base.Header; } } From dff082ed940ad1cd93e0a52f62bd8dd46a5546f6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 26 Dec 2017 01:12:46 +0900 Subject: [PATCH 106/122] Make toolbar testable and add the most basic of visual tests --- osu.Game.Tests/Visual/TestCaseToolbar.cs | 25 +++++++++++++++++++ osu.Game.Tests/osu.Game.Tests.csproj | 1 + .../Overlays/Toolbar/ToolbarChatButton.cs | 2 +- .../Overlays/Toolbar/ToolbarDirectButton.cs | 2 +- .../Overlays/Toolbar/ToolbarModeSelector.cs | 7 ++++-- .../Overlays/Toolbar/ToolbarMusicButton.cs | 2 +- .../Toolbar/ToolbarNotificationButton.cs | 2 +- .../Toolbar/ToolbarOverlayToggleButton.cs | 7 ++++-- .../Overlays/Toolbar/ToolbarSettingsButton.cs | 2 +- .../Overlays/Toolbar/ToolbarSocialButton.cs | 2 +- 10 files changed, 42 insertions(+), 10 deletions(-) create mode 100644 osu.Game.Tests/Visual/TestCaseToolbar.cs diff --git a/osu.Game.Tests/Visual/TestCaseToolbar.cs b/osu.Game.Tests/Visual/TestCaseToolbar.cs new file mode 100644 index 0000000000..9045249b9a --- /dev/null +++ b/osu.Game.Tests/Visual/TestCaseToolbar.cs @@ -0,0 +1,25 @@ +// 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 osu.Framework.Graphics.Containers; +using osu.Game.Overlays.Toolbar; + +namespace osu.Game.Tests.Visual +{ + public class TestCaseToolbar : OsuTestCase + { + public override IReadOnlyList RequiredTypes => new[] + { + typeof(ToolbarButton), + typeof(ToolbarModeSelector), + typeof(ToolbarModeButton), + }; + + public TestCaseToolbar() + { + Add(new Toolbar { State = Visibility.Visible }); + } + } +} diff --git a/osu.Game.Tests/osu.Game.Tests.csproj b/osu.Game.Tests/osu.Game.Tests.csproj index ff012bb6e2..71703d264a 100644 --- a/osu.Game.Tests/osu.Game.Tests.csproj +++ b/osu.Game.Tests/osu.Game.Tests.csproj @@ -148,6 +148,7 @@ + diff --git a/osu.Game/Overlays/Toolbar/ToolbarChatButton.cs b/osu.Game/Overlays/Toolbar/ToolbarChatButton.cs index ed206e7e1d..b0171feb30 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarChatButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarChatButton.cs @@ -13,7 +13,7 @@ namespace osu.Game.Overlays.Toolbar SetIcon(FontAwesome.fa_comments); } - [BackgroundDependencyLoader] + [BackgroundDependencyLoader(true)] private void load(ChatOverlay chat) { StateContainer = chat; diff --git a/osu.Game/Overlays/Toolbar/ToolbarDirectButton.cs b/osu.Game/Overlays/Toolbar/ToolbarDirectButton.cs index 7d25440e2c..5c64ae69ec 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarDirectButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarDirectButton.cs @@ -13,7 +13,7 @@ namespace osu.Game.Overlays.Toolbar SetIcon(FontAwesome.fa_osu_chevron_down_o); } - [BackgroundDependencyLoader] + [BackgroundDependencyLoader(true)] private void load(DirectOverlay direct) { StateContainer = direct; diff --git a/osu.Game/Overlays/Toolbar/ToolbarModeSelector.cs b/osu.Game/Overlays/Toolbar/ToolbarModeSelector.cs index 319dd63bc9..f38c772890 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarModeSelector.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarModeSelector.cs @@ -64,7 +64,7 @@ namespace osu.Game.Overlays.Toolbar }; } - [BackgroundDependencyLoader] + [BackgroundDependencyLoader(true)] private void load(RulesetStore rulesets, OsuGame game) { foreach (var r in rulesets.AvailableRulesets) @@ -81,7 +81,10 @@ namespace osu.Game.Overlays.Toolbar ruleset.ValueChanged += rulesetChanged; ruleset.DisabledChanged += disabledChanged; - ruleset.BindTo(game.Ruleset); + if (game != null) + ruleset.BindTo(game.Ruleset); + else + ruleset.Value = rulesets.AvailableRulesets.FirstOrDefault(); } public override bool HandleInput => !ruleset.Disabled; diff --git a/osu.Game/Overlays/Toolbar/ToolbarMusicButton.cs b/osu.Game/Overlays/Toolbar/ToolbarMusicButton.cs index d150aacdf9..81c57a984f 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarMusicButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarMusicButton.cs @@ -13,7 +13,7 @@ namespace osu.Game.Overlays.Toolbar Icon = FontAwesome.fa_music; } - [BackgroundDependencyLoader] + [BackgroundDependencyLoader(true)] private void load(MusicController music) { StateContainer = music; diff --git a/osu.Game/Overlays/Toolbar/ToolbarNotificationButton.cs b/osu.Game/Overlays/Toolbar/ToolbarNotificationButton.cs index e11a22d675..dbe8b48424 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarNotificationButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarNotificationButton.cs @@ -18,7 +18,7 @@ namespace osu.Game.Overlays.Toolbar TooltipSub = "Waiting for 'ya"; } - [BackgroundDependencyLoader] + [BackgroundDependencyLoader(true)] private void load(NotificationOverlay notificationOverlay) { StateContainer = notificationOverlay; diff --git a/osu.Game/Overlays/Toolbar/ToolbarOverlayToggleButton.cs b/osu.Game/Overlays/Toolbar/ToolbarOverlayToggleButton.cs index 69fdd27d5d..59314b8771 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarOverlayToggleButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarOverlayToggleButton.cs @@ -21,8 +21,11 @@ namespace osu.Game.Overlays.Toolbar set { stateContainer = value; - Action = stateContainer.ToggleVisibility; - stateContainer.StateChanged += stateChanged; + if (stateContainer != null) + { + Action = stateContainer.ToggleVisibility; + stateContainer.StateChanged += stateChanged; + } } } diff --git a/osu.Game/Overlays/Toolbar/ToolbarSettingsButton.cs b/osu.Game/Overlays/Toolbar/ToolbarSettingsButton.cs index cf4f664e81..d0d76dd5d2 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarSettingsButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarSettingsButton.cs @@ -15,7 +15,7 @@ namespace osu.Game.Overlays.Toolbar TooltipSub = "Change your settings"; } - [BackgroundDependencyLoader] + [BackgroundDependencyLoader(true)] private void load(SettingsOverlay settings) { StateContainer = settings; diff --git a/osu.Game/Overlays/Toolbar/ToolbarSocialButton.cs b/osu.Game/Overlays/Toolbar/ToolbarSocialButton.cs index 234d6f0f9a..74d1da4384 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarSocialButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarSocialButton.cs @@ -13,7 +13,7 @@ namespace osu.Game.Overlays.Toolbar Icon = FontAwesome.fa_users; } - [BackgroundDependencyLoader] + [BackgroundDependencyLoader(true)] private void load(SocialOverlay chat) { StateContainer = chat; From bb33d0211a5802c6706c3a18570cbc16ffa4c227 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 26 Dec 2017 01:36:58 +0900 Subject: [PATCH 107/122] Add a count of unread notifications to the toolbar --- osu.Game.Tests/Visual/TestCaseToolbar.cs | 16 ++++- .../Toolbar/ToolbarNotificationButton.cs | 64 +++++++++++++++++++ 2 files changed, 79 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/TestCaseToolbar.cs b/osu.Game.Tests/Visual/TestCaseToolbar.cs index 9045249b9a..9f538af09b 100644 --- a/osu.Game.Tests/Visual/TestCaseToolbar.cs +++ b/osu.Game.Tests/Visual/TestCaseToolbar.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Linq; using osu.Framework.Graphics.Containers; using osu.Game.Overlays.Toolbar; @@ -15,11 +16,24 @@ namespace osu.Game.Tests.Visual typeof(ToolbarButton), typeof(ToolbarModeSelector), typeof(ToolbarModeButton), + typeof(ToolbarNotificationButton), }; public TestCaseToolbar() { - Add(new Toolbar { State = Visibility.Visible }); + var toolbar = new Toolbar { State = Visibility.Visible }; + + Add(toolbar); + + var notificationButton = toolbar.Children.OfType().Last().Children.OfType().First(); + + void setNotifications(int count) => AddStep($"set notification count to {count}", () => notificationButton.NotificationCount.Value = count); + + setNotifications(1); + setNotifications(2); + setNotifications(3); + setNotifications(0); + setNotifications(144); } } } diff --git a/osu.Game/Overlays/Toolbar/ToolbarNotificationButton.cs b/osu.Game/Overlays/Toolbar/ToolbarNotificationButton.cs index dbe8b48424..78a04d156a 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarNotificationButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarNotificationButton.cs @@ -2,8 +2,14 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using osu.Framework.Allocation; +using osu.Framework.Configuration; using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using OpenTK; +using OpenTK.Graphics; namespace osu.Game.Overlays.Toolbar { @@ -11,17 +17,75 @@ namespace osu.Game.Overlays.Toolbar { protected override Anchor TooltipAnchor => Anchor.TopRight; + public BindableInt NotificationCount = new BindableInt(); + + private CountCircle countDisplay; + public ToolbarNotificationButton() { Icon = FontAwesome.fa_bars; TooltipMain = "Notifications"; TooltipSub = "Waiting for 'ya"; + + Add(countDisplay = new CountCircle + { + Alpha = 0, + Height = 16, + RelativePositionAxes = Axes.Both, + Origin = Anchor.TopCentre, + Position = new Vector2(0.7f, 0.05f), + }); } [BackgroundDependencyLoader(true)] private void load(NotificationOverlay notificationOverlay) { StateContainer = notificationOverlay; + + NotificationCount.ValueChanged += count => + { + if (count == 0) + countDisplay.FadeOut(200, Easing.OutQuint); + else + countDisplay.FadeIn(200, Easing.OutQuint); + + countDisplay.Count = count; + }; + } + + private class CountCircle : CompositeDrawable + { + private readonly OsuSpriteText count; + + public int Count + { + set { count.Text = value.ToString("#,0"); } + } + + public CountCircle() + { + AutoSizeAxes = Axes.X; + + InternalChildren = new Drawable[] + { + new Circle + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Red + }, + count = new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Y = -1, + TextSize = 14, + Padding = new MarginPadding(5), + Colour = Color4.White, + UseFullGlyphHeight = true, + Font = "Exo2.0-Bold", + } + }; + } } } } From 1fc240f6c594ad7f1469f4276a0778034c59bb2e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 26 Dec 2017 01:50:05 +0900 Subject: [PATCH 108/122] Expose unread notification count --- .../Visual/TestCaseNotificationOverlay.cs | 7 ++++ osu.Game/Overlays/NotificationOverlay.cs | 42 ++++++++++++------- .../Notifications/NotificationSection.cs | 4 +- 3 files changed, 37 insertions(+), 16 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseNotificationOverlay.cs b/osu.Game.Tests/Visual/TestCaseNotificationOverlay.cs index b93c2d812f..233914767d 100644 --- a/osu.Game.Tests/Visual/TestCaseNotificationOverlay.cs +++ b/osu.Game.Tests/Visual/TestCaseNotificationOverlay.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Linq; using osu.Framework.Graphics; +using osu.Framework.Graphics.Sprites; using osu.Framework.MathUtils; using osu.Game.Overlays; using osu.Game.Overlays.Notifications; @@ -25,6 +26,12 @@ namespace osu.Game.Tests.Visual Origin = Anchor.TopRight }); + SpriteText displayedCount = new SpriteText(); + + Content.Add(displayedCount); + + manager.UnreadCount.ValueChanged += count => { displayedCount.Text = $"displayed count: {count}"; }; + AddStep(@"toggle", manager.ToggleVisibility); AddStep(@"simple #1", sendHelloNotification); AddStep(@"simple #2", sendAmazingNotification); diff --git a/osu.Game/Overlays/NotificationOverlay.cs b/osu.Game/Overlays/NotificationOverlay.cs index a4b5486596..2f1c3285ef 100644 --- a/osu.Game/Overlays/NotificationOverlay.cs +++ b/osu.Game/Overlays/NotificationOverlay.cs @@ -11,6 +11,7 @@ using OpenTK.Graphics; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics.Containers; using System; +using osu.Framework.Configuration; namespace osu.Game.Overlays { @@ -75,34 +76,38 @@ namespace osu.Game.Overlays }; } + private int totalCount => sections.Select(c => c.DisplayedCount).Sum(); + private int unreadCount => sections.Select(c => c.UnreadCount).Sum(); + + public readonly BindableInt UnreadCount = new BindableInt(); + private int runningDepth; private void notificationClosed() { // hide ourselves if all notifications have been dismissed. - if (sections.Select(c => c.DisplayedCount).Sum() == 0) + if (totalCount == 0) State = Visibility.Hidden; + + updateCounts(); } - public void Post(Notification notification) + public void Post(Notification notification) => Schedule(() => { - Schedule(() => - { - State = Visibility.Visible; + ++runningDepth; + notification.Depth = notification.DisplayOnTop ? runningDepth : -runningDepth; - ++runningDepth; - notification.Depth = notification.DisplayOnTop ? runningDepth : -runningDepth; + notification.Closed += notificationClosed; - notification.Closed += notificationClosed; + var hasCompletionTarget = notification as IHasCompletionTarget; + if (hasCompletionTarget != null) + hasCompletionTarget.CompletionTarget = Post; - var hasCompletionTarget = notification as IHasCompletionTarget; - if (hasCompletionTarget != null) - hasCompletionTarget.CompletionTarget = Post; + var ourType = notification.GetType(); + sections.Children.FirstOrDefault(s => s.AcceptTypes.Any(accept => accept.IsAssignableFrom(ourType)))?.Add(notification); - var ourType = notification.GetType(); - sections.Children.FirstOrDefault(s => s.AcceptTypes.Any(accept => accept.IsAssignableFrom(ourType)))?.Add(notification); - }); - } + updateCounts(); + }); protected override void PopIn() { @@ -122,9 +127,16 @@ namespace osu.Game.Overlays this.FadeTo(0, TRANSITION_LENGTH, Easing.OutQuint); } + private void updateCounts() + { + UnreadCount.Value = unreadCount; + } + private void markAllRead() { sections.Children.ForEach(s => s.MarkAllRead()); + + updateCounts(); } protected override void UpdateAfterChildren() diff --git a/osu.Game/Overlays/Notifications/NotificationSection.cs b/osu.Game/Overlays/Notifications/NotificationSection.cs index 09768ba0ea..2bd0321d12 100644 --- a/osu.Game/Overlays/Notifications/NotificationSection.cs +++ b/osu.Game/Overlays/Notifications/NotificationSection.cs @@ -26,6 +26,8 @@ namespace osu.Game.Overlays.Notifications public int DisplayedCount => notifications.Count(n => !n.WasClosed); + public int UnreadCount => notifications.Count(n => !n.WasClosed && !n.Read); + public void Add(Notification notification) => notifications.Add(notification); public IEnumerable AcceptTypes; @@ -157,4 +159,4 @@ namespace osu.Game.Overlays.Notifications notifications?.Children.ForEach(n => n.Read = true); } } -} \ No newline at end of file +} From 0886107ec911c79d6d3f25317b31c0586ddc0ba2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 26 Dec 2017 01:56:57 +0900 Subject: [PATCH 109/122] Connect counter with button display --- .../Toolbar/ToolbarNotificationButton.cs | 24 +++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/osu.Game/Overlays/Toolbar/ToolbarNotificationButton.cs b/osu.Game/Overlays/Toolbar/ToolbarNotificationButton.cs index 78a04d156a..faf802f5e7 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarNotificationButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarNotificationButton.cs @@ -19,7 +19,7 @@ namespace osu.Game.Overlays.Toolbar public BindableInt NotificationCount = new BindableInt(); - private CountCircle countDisplay; + private readonly CountCircle countDisplay; public ToolbarNotificationButton() { @@ -32,8 +32,8 @@ namespace osu.Game.Overlays.Toolbar Alpha = 0, Height = 16, RelativePositionAxes = Axes.Both, - Origin = Anchor.TopCentre, - Position = new Vector2(0.7f, 0.05f), + Origin = Anchor.Centre, + Position = new Vector2(0.7f, 0.25f), }); } @@ -42,24 +42,34 @@ namespace osu.Game.Overlays.Toolbar { StateContainer = notificationOverlay; + if (notificationOverlay != null) + NotificationCount.BindTo(notificationOverlay.UnreadCount); + NotificationCount.ValueChanged += count => { if (count == 0) countDisplay.FadeOut(200, Easing.OutQuint); else + { + countDisplay.Count = count; countDisplay.FadeIn(200, Easing.OutQuint); - - countDisplay.Count = count; + } }; } private class CountCircle : CompositeDrawable { private readonly OsuSpriteText count; + private readonly Circle circle; public int Count { - set { count.Text = value.ToString("#,0"); } + set + { + count.Text = value.ToString("#,0"); + circle.FlashColour(Color4.White, 600, Easing.OutQuint); + this.ScaleTo(1.1f).Then().ScaleTo(1, 600, Easing.OutElastic); + } } public CountCircle() @@ -68,7 +78,7 @@ namespace osu.Game.Overlays.Toolbar InternalChildren = new Drawable[] { - new Circle + circle = new Circle { RelativeSizeAxes = Axes.Both, Colour = Color4.Red From d8f084474216cccb9add01ec3ec40f282bc42bce Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 25 Dec 2017 11:24:13 +0900 Subject: [PATCH 110/122] Fix null reference in release builds Intro may not be initialised yet --- osu.Game/OsuGame.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 67f6e6f4e2..fe7ca77d44 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -272,7 +272,7 @@ namespace osu.Game }; } - Action stateChanged = delegate + void updateScreenOffset() { float offset = 0; @@ -281,11 +281,11 @@ namespace osu.Game if (notifications.State == Visibility.Visible) offset -= ToolbarButton.WIDTH / 2; - intro.MoveToX(offset, SettingsOverlay.TRANSITION_LENGTH, Easing.OutQuint); - }; + screenStack.MoveToX(offset, SettingsOverlay.TRANSITION_LENGTH, Easing.OutQuint); + } - settings.StateChanged += stateChanged; - notifications.StateChanged += stateChanged; + settings.StateChanged += _ => updateScreenOffset(); + notifications.StateChanged += _ => updateScreenOffset(); Cursor.State = Visibility.Hidden; } From 798c2c66667cdb7f5b2c54d59731d3ae71486894 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 25 Dec 2017 12:57:45 +0900 Subject: [PATCH 111/122] Add special logic to song select to avoid obvious clipping when notifications are displayed Not sure if we will keep this going forward (there will likely be an opaque tab control on the notifications overlay similar to options) but let's go with this for now. --- osu.Game/Screens/Select/FilterControl.cs | 4 +- osu.Game/Screens/Select/SongSelect.cs | 48 +++++++++++++++++------- 2 files changed, 37 insertions(+), 15 deletions(-) diff --git a/osu.Game/Screens/Select/FilterControl.cs b/osu.Game/Screens/Select/FilterControl.cs index 1b86cec613..2dbd63f77b 100644 --- a/osu.Game/Screens/Select/FilterControl.cs +++ b/osu.Game/Screens/Select/FilterControl.cs @@ -75,7 +75,7 @@ namespace osu.Game.Screens.Select { Children = new Drawable[] { - new Box + Background = new Box { Colour = Color4.Black, Alpha = 0.8f, @@ -167,6 +167,8 @@ namespace osu.Game.Screens.Select private Bindable showConverted; + public readonly Box Background; + [BackgroundDependencyLoader(permitNulls: true)] private void load(OsuColour colours, OsuGame osu, OsuConfigManager config) { diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 68ee08e721..8189624ce1 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -103,21 +103,41 @@ namespace osu.Game.Screens.Select Right = left_area_padding * 2, } }, - carousel = new BeatmapCarousel + new Container { - RelativeSizeAxes = Axes.Y, - Size = new Vector2(carousel_width, 1), - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreRight, - SelectionChanged = carouselSelectionChanged, - BeatmapSetsChanged = carouselBeatmapsLoaded, - }, - FilterControl = new FilterControl - { - RelativeSizeAxes = Axes.X, - Height = filter_height, - FilterChanged = c => carousel.Filter(c), - Exit = Exit, + RelativeSizeAxes = Axes.Both, + Masking = true, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Width = 2, //avoid horizontal masking so the panels don't clip when screen stack is pushed. + Child = new Container + { + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Width = 0.5f, + Children = new Drawable[] + { + carousel = new BeatmapCarousel + { + Masking = false, + RelativeSizeAxes = Axes.Y, + Size = new Vector2(carousel_width, 1), + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + SelectionChanged = carouselSelectionChanged, + BeatmapSetsChanged = carouselBeatmapsLoaded, + }, + FilterControl = new FilterControl + { + RelativeSizeAxes = Axes.X, + Height = filter_height, + FilterChanged = c => carousel.Filter(c), + Background = { Width = 2 }, + Exit = Exit, + }, + } + }, }, beatmapInfoWedge = new BeatmapInfoWedge { From c737e5245e0442d097d7e9efd6cd6c18cd9dfc60 Mon Sep 17 00:00:00 2001 From: FreezyLemon Date: Tue, 26 Dec 2017 01:50:05 +0100 Subject: [PATCH 112/122] Removed unnecessary SelectNext() call and change to dummy map when no items present --- osu.Game/Screens/Select/BeatmapCarousel.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index be176c1459..802667e6a0 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -142,7 +142,6 @@ namespace osu.Game.Screens.Select if (newSet == null) { itemsCache.Invalidate(); - SelectNext(); return; } @@ -512,7 +511,7 @@ namespace osu.Game.Screens.Select currentY += DrawHeight / 2; scrollableContent.Height = currentY; - if (selectedBeatmapSet != null && selectedBeatmapSet.State.Value != CarouselItemState.Selected) + if (!Items.Any() || selectedBeatmapSet != null && selectedBeatmapSet.State.Value != CarouselItemState.Selected) { selectedBeatmapSet = null; SelectionChanged?.Invoke(null); From c82273572430b6bcefa1b3dbfe45644e543fed2f Mon Sep 17 00:00:00 2001 From: FreezyLemon Date: Tue, 26 Dec 2017 03:57:18 +0100 Subject: [PATCH 113/122] Added tests for hiding diffs (and especially the last visible diff) --- .../Visual/TestCaseBeatmapCarousel.cs | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/osu.Game.Tests/Visual/TestCaseBeatmapCarousel.cs b/osu.Game.Tests/Visual/TestCaseBeatmapCarousel.cs index 639befef74..c09b987407 100644 --- a/osu.Game.Tests/Visual/TestCaseBeatmapCarousel.cs +++ b/osu.Game.Tests/Visual/TestCaseBeatmapCarousel.cs @@ -70,6 +70,7 @@ namespace osu.Game.Tests.Visual testRemoveAll(); testEmptyTraversal(); + testHiding(); } private void ensureRandomFetchSuccess() => @@ -295,6 +296,40 @@ namespace osu.Game.Tests.Visual checkNoSelection(); } + private void testHiding() + { + var hidingSet = createTestBeatmapSet(1); + hidingSet.Beatmaps[1].Hidden = true; + AddStep("Add set with diff 2 hidden", () => carousel.UpdateBeatmapSet(hidingSet)); + setSelected(1, 1); + + checkVisibleItemCount(true, 2); + advanceSelection(true); + checkSelected(1, 3); + + setHidden(3); + checkSelected(1, 1); + + setHidden(2, false); + advanceSelection(true); + checkSelected(1, 2); + + setHidden(1); + checkSelected(1, 2); + + setHidden(2); + checkNoSelection(); + + void setHidden(int diff, bool hidden = true) + { + AddStep((hidden ? "" : "un") + $"hide diff {diff}", () => + { + hidingSet.Beatmaps[diff - 1].Hidden = hidden; + carousel.UpdateBeatmapSet(hidingSet); + }); + } + } + private BeatmapSetInfo createTestBeatmapSet(int i) { return new BeatmapSetInfo From 09ce24a7dba54deb34d629e75eee48978d1f26a8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 26 Dec 2017 13:41:02 +0900 Subject: [PATCH 114/122] Switch to a better way of deciding on null selection This avoids `SelectionChanged` potentially being invoked multiple times after `selectedBeatmapSet` is already `null`. --- osu.Game/Screens/Select/BeatmapCarousel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index 802667e6a0..87edfe9692 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -511,7 +511,7 @@ namespace osu.Game.Screens.Select currentY += DrawHeight / 2; scrollableContent.Height = currentY; - if (!Items.Any() || selectedBeatmapSet != null && selectedBeatmapSet.State.Value != CarouselItemState.Selected) + if (selectedBeatmapSet != null && (selectedBeatmap == null || selectedBeatmapSet.State.Value != CarouselItemState.Selected)) { selectedBeatmapSet = null; SelectionChanged?.Invoke(null); From 14162b5d46a56f4f8da0e01829c25c67c331b1e9 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 26 Dec 2017 14:18:23 +0900 Subject: [PATCH 115/122] Make InputDrum handle all Normals/Claps, hitobjects all others --- .../Audio/DrumSampleMapping.cs | 47 +++++++++++-------- .../Objects/Drawables/DrawableSwell.cs | 19 -------- .../Drawables/DrawableTaikoHitObject.cs | 7 +++ osu.Game.Rulesets.Taiko/Objects/Swell.cs | 13 ----- osu.Game.Rulesets.Taiko/UI/InputDrum.cs | 36 ++++++++++++-- osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs | 38 ++------------- .../Objects/Drawables/DrawableHitObject.cs | 6 ++- 7 files changed, 72 insertions(+), 94 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Audio/DrumSampleMapping.cs b/osu.Game.Rulesets.Taiko/Audio/DrumSampleMapping.cs index 25fa9951df..9d0037b97a 100644 --- a/osu.Game.Rulesets.Taiko/Audio/DrumSampleMapping.cs +++ b/osu.Game.Rulesets.Taiko/Audio/DrumSampleMapping.cs @@ -1,7 +1,8 @@ // 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.Linq; using osu.Framework.Audio; using osu.Framework.Audio.Sample; using osu.Game.Audio; @@ -9,32 +10,38 @@ using osu.Game.Beatmaps.ControlPoints; namespace osu.Game.Rulesets.Taiko.Audio { - public class DrumSampleMapping : IComparable + public class DrumSampleMapping { - public double Time; - public readonly SampleInfo Centre; - public readonly SampleInfo Rim; + private readonly ControlPointInfo controlPoints; + private readonly Dictionary mappings = new Dictionary(); - public SampleChannel CentreChannel { get; private set; } - public SampleChannel RimChannel { get; private set; } - - public DrumSampleMapping() + public DrumSampleMapping(ControlPointInfo controlPoints, AudioManager audio) { + this.controlPoints = controlPoints; + + IEnumerable samplePoints; + if (controlPoints.SamplePoints.Count == 0) + // Get the default sample point + samplePoints = new[] { controlPoints.SamplePointAt(double.MinValue) }; + else + samplePoints = controlPoints.SamplePoints; + + foreach (var s in samplePoints.Distinct()) + { + mappings[s] = new DrumSample + { + Centre = s.GetSampleInfo().GetChannel(audio.Sample), + Rim = s.GetSampleInfo(SampleInfo.HIT_CLAP).GetChannel(audio.Sample) + }; + } } - public DrumSampleMapping(SampleControlPoint samplePoint) - { - Time = samplePoint.Time; - Centre = samplePoint.GetSampleInfo(); - Rim = samplePoint.GetSampleInfo(SampleInfo.HIT_CLAP); - } + public DrumSample SampleAt(double time) => mappings[controlPoints.SamplePointAt(time)]; - public void RetrieveChannels(AudioManager audio) + public class DrumSample { - CentreChannel = Centre.GetChannel(audio.Sample); - RimChannel = Rim.GetChannel(audio.Sample); + public SampleChannel Centre; + public SampleChannel Rim; } - - public int CompareTo(DrumSampleMapping other) => Time.CompareTo(other.Time); } } diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs index 5131572abd..3099c6984c 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs @@ -123,9 +123,6 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables MainPiece.AccentColour = colours.YellowDark; expandingRing.Colour = colours.YellowLight; targetRing.BorderColour = colours.YellowDark.Opacity(0.25f); - - foreach (var mapping in HitObject.ProgressionSamples) - mapping.RetrieveChannels(audio); } protected override void LoadComplete() @@ -223,22 +220,6 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables UpdateJudgement(true); - if (AllJudged) - return true; - - // While the swell hasn't been fully judged, input is still blocked so it doesn't fall through to other hitobjects - // This causes the playfield to not play sounds, so they need to be handled locally - - var mappingIndex = HitObject.ProgressionSamples.BinarySearch(new DrumSampleMapping { Time = Time.Current }); - if (mappingIndex < 0) - mappingIndex = ~mappingIndex - 1; - - var mapping = HitObject.ProgressionSamples[mappingIndex]; - if (isCentre) - mapping.CentreChannel.Play(); - else - mapping.RimChannel.Play(); - return true; } } diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs index 7976cbbbc1..cf0df260b1 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs @@ -6,6 +6,10 @@ using osu.Framework.Input.Bindings; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces; using OpenTK; +using System; +using System.Linq; +using osu.Game.Audio; +using System.Collections.Generic; namespace osu.Game.Rulesets.Taiko.Objects.Drawables { @@ -35,6 +39,9 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables MainPiece.KiaiMode = HitObject.Kiai; } + // Normal and clap samples are handled by the drum + protected override IEnumerable GetSamples() => HitObject.Samples.Where(s => s.Name != SampleInfo.HIT_NORMAL && s.Name != SampleInfo.HIT_CLAP); + protected virtual TaikoPiece CreateMainPiece() => new CirclePiece(); public abstract bool OnPressed(TaikoAction action); diff --git a/osu.Game.Rulesets.Taiko/Objects/Swell.cs b/osu.Game.Rulesets.Taiko/Objects/Swell.cs index 714e5d29ee..95ea9f8aa4 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Swell.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Swell.cs @@ -20,18 +20,5 @@ namespace osu.Game.Rulesets.Taiko.Objects /// The number of hits required to complete the swell successfully. /// public int RequiredHits = 10; - - public List ProgressionSamples = new List(); - - protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) - { - base.ApplyDefaultsToSelf(controlPointInfo, difficulty); - - var progressionSamplePoints = new[] { controlPointInfo.SamplePointAt(StartTime) } - .Concat(controlPointInfo.SamplePoints.Where(p => p.Time > StartTime && p.Time <= EndTime)); - - foreach (var point in progressionSamplePoints) - ProgressionSamples.Add(new DrumSampleMapping(point)); - } } } diff --git a/osu.Game.Rulesets.Taiko/UI/InputDrum.cs b/osu.Game.Rulesets.Taiko/UI/InputDrum.cs index 5e79166bec..8c02b21733 100644 --- a/osu.Game.Rulesets.Taiko/UI/InputDrum.cs +++ b/osu.Game.Rulesets.Taiko/UI/InputDrum.cs @@ -2,14 +2,20 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; +using System.Collections.Generic; +using System.Linq; using OpenTK; using osu.Framework.Allocation; +using osu.Framework.Audio; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; using osu.Framework.Input.Bindings; +using osu.Game.Audio; +using osu.Game.Beatmaps.ControlPoints; using osu.Game.Graphics; +using osu.Game.Rulesets.Taiko.Audio; namespace osu.Game.Rulesets.Taiko.UI { @@ -18,16 +24,26 @@ namespace osu.Game.Rulesets.Taiko.UI /// internal class InputDrum : Container { - public InputDrum() + private const float middle_split = 0.025f; + + private readonly ControlPointInfo controlPoints; + + public InputDrum(ControlPointInfo controlPoints) { + this.controlPoints = controlPoints; + RelativeSizeAxes = Axes.Both; FillMode = FillMode.Fit; + } - const float middle_split = 0.025f; + [BackgroundDependencyLoader] + private void load(AudioManager audio) + { + var sampleMappings = new DrumSampleMapping(controlPoints, audio); Children = new Drawable[] { - new TaikoHalfDrum(false) + new TaikoHalfDrum(false, sampleMappings) { Name = "Left Half", Anchor = Anchor.Centre, @@ -38,7 +54,7 @@ namespace osu.Game.Rulesets.Taiko.UI RimAction = TaikoAction.LeftRim, CentreAction = TaikoAction.LeftCentre }, - new TaikoHalfDrum(true) + new TaikoHalfDrum(true, sampleMappings) { Name = "Right Half", Anchor = Anchor.Centre, @@ -72,8 +88,12 @@ namespace osu.Game.Rulesets.Taiko.UI private readonly Sprite centre; private readonly Sprite centreHit; - public TaikoHalfDrum(bool flipped) + private readonly DrumSampleMapping sampleMappings; + + public TaikoHalfDrum(bool flipped, DrumSampleMapping sampleMappings) { + this.sampleMappings = sampleMappings; + Masking = true; Children = new Drawable[] @@ -128,15 +148,21 @@ namespace osu.Game.Rulesets.Taiko.UI Drawable target = null; Drawable back = null; + var drumSample = sampleMappings.SampleAt(Time.Current); + if (action == CentreAction) { target = centreHit; back = centre; + + drumSample.Centre.Play(); } else if (action == RimAction) { target = rimHit; back = rim; + + drumSample.Rim.Play(); } if (target != null) diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs index 229e44cf27..14f8de0f48 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs @@ -24,7 +24,7 @@ using osu.Game.Rulesets.Taiko.Audio; namespace osu.Game.Rulesets.Taiko.UI { - public class TaikoPlayfield : ScrollingPlayfield, IKeyBindingHandler + public class TaikoPlayfield : ScrollingPlayfield { /// /// Default height of a when inside a . @@ -59,13 +59,9 @@ namespace osu.Game.Rulesets.Taiko.UI private readonly Box overlayBackground; private readonly Box background; - private readonly ControlPointInfo controlPointInfo; - private readonly List drumSampleMappings = new List(); - - public TaikoPlayfield(ControlPointInfo controlPointInfo) + public TaikoPlayfield(ControlPointInfo controlPoints) : base(Axes.X) { - this.controlPointInfo = controlPointInfo; AddRangeInternal(new Drawable[] { backgroundContainer = new Container @@ -158,7 +154,7 @@ namespace osu.Game.Rulesets.Taiko.UI { RelativeSizeAxes = Axes.Both, }, - new InputDrum + new InputDrum(controlPoints) { Anchor = Anchor.CentreRight, Origin = Anchor.CentreRight, @@ -205,17 +201,7 @@ namespace osu.Game.Rulesets.Taiko.UI [BackgroundDependencyLoader] private void load(OsuColour colours, AudioManager audio) { - // We may have 0 sample points, but we need at least the default one - var samplePoints = new[] { controlPointInfo.SamplePointAt(double.MinValue) } - .Concat(controlPointInfo.SamplePoints); - foreach (var s in samplePoints) - { - var mapping = new DrumSampleMapping(s); - mapping.RetrieveChannels(audio); - - drumSampleMappings.Add(mapping); - } overlayBackgroundContainer.BorderColour = colours.Gray0; overlayBackground.Colour = colours.Gray1; @@ -281,23 +267,5 @@ namespace osu.Game.Rulesets.Taiko.UI kiaiExplosionContainer.Add(new KiaiHitExplosion(judgedObject, isRim)); } } - - public bool OnPressed(TaikoAction action) - { - var mappingIndex = drumSampleMappings.BinarySearch(new DrumSampleMapping { Time = Time.Current }); - if (mappingIndex < 0) - mappingIndex = ~mappingIndex - 1; - - var mapping = drumSampleMappings[mappingIndex]; - - if (action == TaikoAction.LeftCentre || action == TaikoAction.RightCentre) - mapping.CentreChannel.Play(); - else - mapping.RimChannel.Play(); - - return true; - } - - public bool OnReleased(TaikoAction action) => false; } } diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index be161b9ad3..ab4c04be3f 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -72,6 +72,7 @@ namespace osu.Game.Rulesets.Objects.Drawables public IReadOnlyList Judgements => judgements; protected List Samples = new List(); + protected virtual IEnumerable GetSamples() => HitObject.Samples; public readonly Bindable State = new Bindable(); @@ -84,13 +85,14 @@ namespace osu.Game.Rulesets.Objects.Drawables [BackgroundDependencyLoader] private void load(AudioManager audio) { - if (Samples.Count > 0) + var samples = GetSamples(); + if (samples.Any()) { if (HitObject.SampleControlPoint == null) throw new ArgumentNullException(nameof(HitObject.SampleControlPoint), $"{nameof(HitObject)}s must always have an attached {nameof(HitObject.SampleControlPoint)}." + $" This is an indication that {nameof(HitObject.ApplyDefaults)} has not been invoked on {this}."); - foreach (SampleInfo s in HitObject.Samples) + foreach (SampleInfo s in samples) { SampleInfo localSampleInfo = new SampleInfo { From 35d7fa8a81ae017f964c1644ddac3db0b7f94135 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 26 Dec 2017 14:18:38 +0900 Subject: [PATCH 116/122] Cleanup things that are now not needed with these changes --- osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs | 2 +- .../Objects/Drawables/DrawableHitStrong.cs | 2 +- .../Objects/Drawables/DrawableSwell.cs | 4 +--- .../Objects/Drawables/DrawableTaikoHitObject.cs | 1 - osu.Game.Rulesets.Taiko/Objects/Swell.cs | 5 ----- osu.Game.Rulesets.Taiko/UI/InputDrum.cs | 3 --- osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs | 8 +------- 7 files changed, 4 insertions(+), 21 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs index df33aae94e..fd35f0eaec 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs @@ -68,7 +68,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables validKeyPressed = HitActions.Contains(action); // Only count this as handled if the new judgement is a hit - return UpdateJudgement(true) && Judgements.LastOrDefault()?.IsHit == true; + return UpdateJudgement(true); } protected override void Update() diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHitStrong.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHitStrong.cs index 07f7b83cef..cda82afe0e 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHitStrong.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHitStrong.cs @@ -83,7 +83,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables return false; // Assume the intention was to hit the strong hit with both keys only if the first key is still being held down - return firstKeyHeld && UpdateJudgement(true) && Judgements.LastOrDefault()?.IsHit == true; + return firstKeyHeld && UpdateJudgement(true); } } } diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs index 3099c6984c..5ca33aaea2 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs @@ -14,8 +14,6 @@ using OpenTK; using OpenTK.Graphics; using osu.Framework.Graphics.Shapes; using osu.Game.Rulesets.Taiko.Judgements; -using osu.Framework.Audio; -using osu.Game.Rulesets.Taiko.Audio; namespace osu.Game.Rulesets.Taiko.Objects.Drawables { @@ -118,7 +116,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables } [BackgroundDependencyLoader] - private void load(OsuColour colours, AudioManager audio) + private void load(OsuColour colours) { MainPiece.AccentColour = colours.YellowDark; expandingRing.Colour = colours.YellowLight; diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs index cf0df260b1..92da3fe09e 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs @@ -6,7 +6,6 @@ using osu.Framework.Input.Bindings; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces; using OpenTK; -using System; using System.Linq; using osu.Game.Audio; using System.Collections.Generic; diff --git a/osu.Game.Rulesets.Taiko/Objects/Swell.cs b/osu.Game.Rulesets.Taiko/Objects/Swell.cs index 95ea9f8aa4..cd2876ea2d 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Swell.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Swell.cs @@ -1,12 +1,7 @@ // 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.Linq; -using osu.Game.Beatmaps; -using osu.Game.Beatmaps.ControlPoints; using osu.Game.Rulesets.Objects.Types; -using osu.Game.Rulesets.Taiko.Audio; namespace osu.Game.Rulesets.Taiko.Objects { diff --git a/osu.Game.Rulesets.Taiko/UI/InputDrum.cs b/osu.Game.Rulesets.Taiko/UI/InputDrum.cs index 8c02b21733..bf1274256b 100644 --- a/osu.Game.Rulesets.Taiko/UI/InputDrum.cs +++ b/osu.Game.Rulesets.Taiko/UI/InputDrum.cs @@ -2,8 +2,6 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; -using System.Collections.Generic; -using System.Linq; using OpenTK; using osu.Framework.Allocation; using osu.Framework.Audio; @@ -12,7 +10,6 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; using osu.Framework.Input.Bindings; -using osu.Game.Audio; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Graphics; using osu.Game.Rulesets.Taiko.Audio; diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs index 14f8de0f48..3fdbd056ce 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs @@ -16,11 +16,7 @@ using osu.Framework.Extensions.Color4Extensions; using System.Linq; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Taiko.Objects.Drawables; -using osu.Framework.Input.Bindings; using osu.Game.Beatmaps.ControlPoints; -using osu.Framework.Audio; -using System.Collections.Generic; -using osu.Game.Rulesets.Taiko.Audio; namespace osu.Game.Rulesets.Taiko.UI { @@ -199,10 +195,8 @@ namespace osu.Game.Rulesets.Taiko.UI } [BackgroundDependencyLoader] - private void load(OsuColour colours, AudioManager audio) + private void load(OsuColour colours) { - - overlayBackgroundContainer.BorderColour = colours.Gray0; overlayBackground.Colour = colours.Gray1; From 9ccc49c9b5a2b61c73e30a9cea35118614f5f4fb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 26 Dec 2017 15:32:39 +0900 Subject: [PATCH 117/122] Make selection triggering more liberal --- osu.Game/Screens/Select/BeatmapCarousel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index e3566f3206..9d7867659d 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -513,7 +513,7 @@ namespace osu.Game.Screens.Select currentY += DrawHeight / 2; scrollableContent.Height = currentY; - if (selectedBeatmapSet != null && (selectedBeatmap == null || selectedBeatmapSet.State.Value != CarouselItemState.Selected)) + if (selectedBeatmapSet == null || selectedBeatmap == null || selectedBeatmapSet.State.Value != CarouselItemState.Selected) { selectedBeatmapSet = null; SelectionChanged?.Invoke(null); From e14ad31a071cacfc10f4ab8668f3d00634776c68 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 26 Dec 2017 15:32:53 +0900 Subject: [PATCH 118/122] Increase wait durations for test stability --- osu.Game.Tests/Visual/TestCasePlaySongSelect.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs b/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs index e27e786a05..69aa371958 100644 --- a/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs +++ b/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs @@ -90,7 +90,7 @@ namespace osu.Game.Tests.Visual loadNewSongSelect(true); - AddWaitStep(1); + AddWaitStep(3); AddAssert("dummy selected", () => songSelect.CurrentBeatmap == defaultBeatmap); @@ -100,11 +100,11 @@ namespace osu.Game.Tests.Visual manager.Import(createTestBeatmapSet(i)); }); - AddWaitStep(1); + AddWaitStep(3); AddAssert("random map selected", () => songSelect.CurrentBeatmap != defaultBeatmap); loadNewSongSelect(); - AddWaitStep(1); + AddWaitStep(3); AddAssert("random map selected", () => songSelect.CurrentBeatmap != defaultBeatmap); AddStep(@"Sort by Artist", delegate { songSelect.FilterControl.Sort = SortMode.Artist; }); From 024d9a6850c9071225cba706b77e8f21d9f426e6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 26 Dec 2017 15:33:02 +0900 Subject: [PATCH 119/122] Remove unnecessary null check --- .../Visual/TestCasePlaySongSelect.cs | 25 ++++++++----------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs b/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs index 69aa371958..18e40db064 100644 --- a/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs +++ b/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs @@ -59,21 +59,18 @@ namespace osu.Game.Tests.Visual { TestSongSelect songSelect = null; - if (manager == null) + var storage = new TestStorage(@"TestCasePlaySongSelect"); + + // this is by no means clean. should be replacing inside of OsuGameBase somehow. + var context = new OsuDbContext(); + + Func contextFactory = () => context; + + dependencies.Cache(rulesets = new RulesetStore(contextFactory)); + dependencies.Cache(manager = new BeatmapManager(storage, contextFactory, rulesets, null) { - var storage = new TestStorage(@"TestCasePlaySongSelect"); - - // this is by no means clean. should be replacing inside of OsuGameBase somehow. - var context = new OsuDbContext(); - - Func contextFactory = () => context; - - dependencies.Cache(rulesets = new RulesetStore(contextFactory)); - dependencies.Cache(manager = new BeatmapManager(storage, contextFactory, rulesets, null) - { - DefaultBeatmap = defaultBeatmap = baseManager.GetWorkingBeatmap(null) - }); - } + DefaultBeatmap = defaultBeatmap = baseManager.GetWorkingBeatmap(null) + }); void loadNewSongSelect(bool deleteMaps = false) => AddStep("reload song select", () => { From ed1df94f778d983933e72183a386e0f3bbd1b11d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 26 Dec 2017 15:48:01 +0900 Subject: [PATCH 120/122] Fix unread light not turning off --- osu.Game/Overlays/Notifications/Notification.cs | 2 +- osu.Game/Overlays/Notifications/SimpleNotification.cs | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Notifications/Notification.cs b/osu.Game/Overlays/Notifications/Notification.cs index 422051364e..b4720e79c4 100644 --- a/osu.Game/Overlays/Notifications/Notification.cs +++ b/osu.Game/Overlays/Notifications/Notification.cs @@ -261,4 +261,4 @@ namespace osu.Game.Overlays.Notifications } } } -} \ No newline at end of file +} diff --git a/osu.Game/Overlays/Notifications/SimpleNotification.cs b/osu.Game/Overlays/Notifications/SimpleNotification.cs index 0b8b365c48..1e691e2a5a 100644 --- a/osu.Game/Overlays/Notifications/SimpleNotification.cs +++ b/osu.Game/Overlays/Notifications/SimpleNotification.cs @@ -83,8 +83,10 @@ namespace osu.Game.Overlays.Notifications set { + if (value == base.Read) return; + base.Read = value; - Light.FadeTo(value ? 1 : 0, 100); + Light.FadeTo(value ? 0 : 1, 100); } } } From 45b3acdd6f1ad89ade0f0abd8564c0fcaa7fefb7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 26 Dec 2017 15:50:59 +0900 Subject: [PATCH 121/122] Fix progress notifications not closing properly when opening their continuation --- osu.Game/Overlays/Notifications/ProgressNotification.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Notifications/ProgressNotification.cs b/osu.Game/Overlays/Notifications/ProgressNotification.cs index 9211c227f8..c39c630858 100644 --- a/osu.Game/Overlays/Notifications/ProgressNotification.cs +++ b/osu.Game/Overlays/Notifications/ProgressNotification.cs @@ -95,7 +95,7 @@ namespace osu.Game.Overlays.Notifications protected virtual void Completed() { - Expire(); + base.Close(); CompletionTarget?.Invoke(CreateCompletionNotification()); } From 24d8d357d07e762fb233411c5e8860400664f151 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 26 Dec 2017 15:52:36 +0900 Subject: [PATCH 122/122] Only bounce and flash notification count when increasing --- .../Toolbar/ToolbarNotificationButton.cs | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/osu.Game/Overlays/Toolbar/ToolbarNotificationButton.cs b/osu.Game/Overlays/Toolbar/ToolbarNotificationButton.cs index faf802f5e7..c093767e52 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarNotificationButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarNotificationButton.cs @@ -59,16 +59,27 @@ namespace osu.Game.Overlays.Toolbar private class CountCircle : CompositeDrawable { - private readonly OsuSpriteText count; + private readonly OsuSpriteText countText; private readonly Circle circle; + private int count; + public int Count { + get { return count; } set { - count.Text = value.ToString("#,0"); - circle.FlashColour(Color4.White, 600, Easing.OutQuint); - this.ScaleTo(1.1f).Then().ScaleTo(1, 600, Easing.OutElastic); + if (count == value) + return; + + if (value > count) + { + circle.FlashColour(Color4.White, 600, Easing.OutQuint); + this.ScaleTo(1.1f).Then().ScaleTo(1, 600, Easing.OutElastic); + } + + count = value; + countText.Text = value.ToString("#,0"); } } @@ -83,7 +94,7 @@ namespace osu.Game.Overlays.Toolbar RelativeSizeAxes = Axes.Both, Colour = Color4.Red }, - count = new OsuSpriteText + countText = new OsuSpriteText { Anchor = Anchor.Centre, Origin = Anchor.Centre,