diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModAutoplay.cs b/osu.Game.Rulesets.Catch/Mods/CatchModAutoplay.cs index 612df5bde5..692e63fa69 100644 --- a/osu.Game.Rulesets.Catch/Mods/CatchModAutoplay.cs +++ b/osu.Game.Rulesets.Catch/Mods/CatchModAutoplay.cs @@ -12,7 +12,7 @@ namespace osu.Game.Rulesets.Catch.Mods { public class CatchModAutoplay : ModAutoplay { - protected override Score CreateReplayScore(Beatmap beatmap) => new Score + public override Score CreateReplayScore(IBeatmap beatmap) => new Score { ScoreInfo = new ScoreInfo { User = new User { Username = "osu!salad!" } }, Replay = new CatchAutoGenerator(beatmap).Generate(), diff --git a/osu.Game.Rulesets.Catch/Replays/CatchAutoGenerator.cs b/osu.Game.Rulesets.Catch/Replays/CatchAutoGenerator.cs index 2fd05483ef..daa3f61de3 100644 --- a/osu.Game.Rulesets.Catch/Replays/CatchAutoGenerator.cs +++ b/osu.Game.Rulesets.Catch/Replays/CatchAutoGenerator.cs @@ -6,17 +6,20 @@ using osu.Framework.MathUtils; using osu.Game.Beatmaps; using osu.Game.Replays; +using osu.Game.Rulesets.Catch.Beatmaps; using osu.Game.Rulesets.Catch.Objects; using osu.Game.Rulesets.Catch.UI; using osu.Game.Rulesets.Replays; namespace osu.Game.Rulesets.Catch.Replays { - internal class CatchAutoGenerator : AutoGenerator + internal class CatchAutoGenerator : AutoGenerator { public const double RELEASE_DELAY = 20; - public CatchAutoGenerator(Beatmap beatmap) + public new CatchBeatmap Beatmap => (CatchBeatmap)base.Beatmap; + + public CatchAutoGenerator(IBeatmap beatmap) : base(beatmap) { Replay = new Replay(); diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModAutoplay.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModAutoplay.cs index 02eb7ac883..c05e979e9a 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModAutoplay.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModAutoplay.cs @@ -13,7 +13,7 @@ namespace osu.Game.Rulesets.Mania.Mods { public class ManiaModAutoplay : ModAutoplay { - protected override Score CreateReplayScore(Beatmap beatmap) => new Score + public override Score CreateReplayScore(IBeatmap beatmap) => new Score { ScoreInfo = new ScoreInfo { User = new User { Username = "osu!topus!" } }, Replay = new ManiaAutoGenerator((ManiaBeatmap)beatmap).Generate(), diff --git a/osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs b/osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs index df6afa040e..65b7d54cd2 100644 --- a/osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs +++ b/osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs @@ -5,13 +5,12 @@ using System.Linq; using osu.Game.Replays; using osu.Game.Rulesets.Mania.Beatmaps; -using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Replays; namespace osu.Game.Rulesets.Mania.Replays { - internal class ManiaAutoGenerator : AutoGenerator + internal class ManiaAutoGenerator : AutoGenerator { public const double RELEASE_DELAY = 20; diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs index a164b7e6bb..e257369ad9 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs @@ -38,7 +38,7 @@ public PathControlPointPiece(Slider slider, int index) path = new SmoothPath { Anchor = Anchor.Centre, - PathWidth = 1 + PathRadius = 1 }, marker = new CircularContainer { diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs index 179fa1bc72..957550a051 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs @@ -24,7 +24,7 @@ public SliderBodyPiece(Slider slider) InternalChild = body = new ManualSliderBody { AccentColour = Color4.Transparent, - PathWidth = slider.Scale * 64 + PathRadius = slider.Scale * 64 }; } @@ -34,7 +34,7 @@ private void load(OsuColour colours) body.BorderColour = colours.Yellow; PositionBindable.BindValueChanged(_ => updatePosition(), true); - ScaleBindable.BindValueChanged(scale => body.PathWidth = scale.NewValue * 64, true); + ScaleBindable.BindValueChanged(scale => body.PathRadius = scale.NewValue * 64, true); } private void updatePosition() => Position = slider.StackedPosition; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModAutoplay.cs b/osu.Game.Rulesets.Osu/Mods/OsuModAutoplay.cs index d7ba0d4da9..bea2bbcb32 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModAutoplay.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModAutoplay.cs @@ -16,7 +16,7 @@ public class OsuModAutoplay : ModAutoplay { public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(OsuModAutopilot)).Append(typeof(OsuModSpunOut)).ToArray(); - protected override Score CreateReplayScore(Beatmap beatmap) => new Score + public override Score CreateReplayScore(IBeatmap beatmap) => new Score { ScoreInfo = new ScoreInfo { User = new User { Username = "Autoplay" } }, Replay = new OsuAutoGenerator(beatmap).Generate() diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs index ff74954552..57ea0abdd8 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs @@ -50,7 +50,7 @@ public DrawableSlider(Slider s) { Body = new SnakingSliderBody(s) { - PathWidth = s.Scale * 64, + PathRadius = s.Scale * 64, }, ticks = new Container { RelativeSizeAxes = Axes.Both }, repeatPoints = new Container { RelativeSizeAxes = Axes.Both }, @@ -105,7 +105,7 @@ private void load() positionBindable.BindValueChanged(_ => Position = HitObject.StackedPosition); scaleBindable.BindValueChanged(scale => { - Body.PathWidth = scale.NewValue * 64; + Body.PathRadius = scale.NewValue * 64; Ball.Scale = new Vector2(scale.NewValue); }); diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBody.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBody.cs index b088f1914b..2f5c326bda 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBody.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBody.cs @@ -19,10 +19,10 @@ public abstract class SliderBody : CompositeDrawable private readonly BufferedContainer container; - public float PathWidth + public float PathRadius { - get => path.PathWidth; - set => path.PathWidth = value; + get => path.PathRadius; + set => path.PathRadius = value; } /// diff --git a/osu.Game.Rulesets.Osu/Replays/OsuAutoGenerator.cs b/osu.Game.Rulesets.Osu/Replays/OsuAutoGenerator.cs index b0fb85d7ed..c1aaa7767e 100644 --- a/osu.Game.Rulesets.Osu/Replays/OsuAutoGenerator.cs +++ b/osu.Game.Rulesets.Osu/Replays/OsuAutoGenerator.cs @@ -10,12 +10,15 @@ using osu.Framework.Graphics; using osu.Game.Replays; using osu.Game.Rulesets.Objects.Types; +using osu.Game.Rulesets.Osu.Beatmaps; using osu.Game.Rulesets.Scoring; namespace osu.Game.Rulesets.Osu.Replays { public class OsuAutoGenerator : OsuAutoGeneratorBase { + public new OsuBeatmap Beatmap => (OsuBeatmap)base.Beatmap; + #region Parameters /// @@ -42,7 +45,7 @@ public class OsuAutoGenerator : OsuAutoGeneratorBase #region Construction / Initialisation - public OsuAutoGenerator(Beatmap beatmap) + public OsuAutoGenerator(IBeatmap beatmap) : base(beatmap) { // Already superhuman, but still somewhat realistic diff --git a/osu.Game.Rulesets.Osu/Replays/OsuAutoGeneratorBase.cs b/osu.Game.Rulesets.Osu/Replays/OsuAutoGeneratorBase.cs index 9a60f0cafc..9ab358ee12 100644 --- a/osu.Game.Rulesets.Osu/Replays/OsuAutoGeneratorBase.cs +++ b/osu.Game.Rulesets.Osu/Replays/OsuAutoGeneratorBase.cs @@ -3,7 +3,6 @@ using osuTK; using osu.Game.Beatmaps; -using osu.Game.Rulesets.Osu.Objects; using System; using System.Collections.Generic; using osu.Game.Replays; @@ -12,7 +11,7 @@ namespace osu.Game.Rulesets.Osu.Replays { - public abstract class OsuAutoGeneratorBase : AutoGenerator + public abstract class OsuAutoGeneratorBase : AutoGenerator { #region Constants @@ -35,7 +34,7 @@ public abstract class OsuAutoGeneratorBase : AutoGenerator protected Replay Replay; protected List Frames => Replay.Frames; - protected OsuAutoGeneratorBase(Beatmap beatmap) + protected OsuAutoGeneratorBase(IBeatmap beatmap) : base(beatmap) { Replay = new Replay(); diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs b/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs index 0f8a0ce1ae..03dbf7ac63 100644 --- a/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs +++ b/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs @@ -24,7 +24,7 @@ internal class CursorTrail : Drawable, IRequireHighFrequencyMousePosition { private int currentIndex; - private Shader shader; + private IShader shader; private Texture texture; private Vector2 size => texture.Size * Scale; @@ -35,7 +35,6 @@ internal class CursorTrail : Drawable, IRequireHighFrequencyMousePosition public override bool IsPresent => true; - private readonly TrailDrawNodeSharedData trailDrawNodeSharedData = new TrailDrawNodeSharedData(); private const int max_sprites = 2048; private readonly TrailPart[] parts = new TrailPart[max_sprites]; @@ -55,7 +54,6 @@ protected override void ApplyDrawNode(DrawNode node) tNode.Texture = texture; tNode.Size = size; tNode.Time = time; - tNode.Shared = trailDrawNodeSharedData; for (int i = 0; i < parts.Length; ++i) if (parts[i].InvalidationID > tNode.Parts[i].InvalidationID) @@ -81,7 +79,7 @@ public CursorTrail() [BackgroundDependencyLoader] private void load(ShaderManager shaders, TextureStore textures) { - shader = shaders?.Load(@"CursorTrail", FragmentShaderDescriptor.TEXTURE); + shader = shaders.Load(@"CursorTrail", FragmentShaderDescriptor.TEXTURE); texture = textures.Get(@"Cursor/cursortrail"); Scale = new Vector2(1 / texture.ScaleAdjust); } @@ -167,22 +165,18 @@ private struct TrailPart public bool WasUpdated; } - private class TrailDrawNodeSharedData - { - public VertexBuffer VertexBuffer; - } - private class TrailDrawNode : DrawNode { - public Shader Shader; + public IShader Shader; public Texture Texture; public float Time; - public TrailDrawNodeSharedData Shared; public readonly TrailPart[] Parts = new TrailPart[max_sprites]; public Vector2 Size; + private readonly VertexBuffer vertexBuffer = new QuadVertexBuffer(max_sprites, BufferUsageHint.DynamicDraw); + public TrailDrawNode() { for (int i = 0; i < max_sprites; i++) @@ -194,9 +188,6 @@ public TrailDrawNode() public override void Draw(Action vertexAction) { - if (Shared.VertexBuffer == null) - Shared.VertexBuffer = new QuadVertexBuffer(max_sprites, BufferUsageHint.DynamicDraw); - Shader.GetUniform("g_FadeClock").UpdateValue(ref Time); int updateStart = -1, updateEnd = 0; @@ -218,7 +209,7 @@ public override void Draw(Action vertexAction) new Quad(pos.X - Size.X / 2, pos.Y - Size.Y / 2, Size.X, Size.Y), DrawColourInfo.Colour, null, - v => Shared.VertexBuffer.Vertices[end++] = new TexturedTrailVertex + v => vertexBuffer.Vertices[end++] = new TexturedTrailVertex { Position = v.Position, TexturePosition = v.TexturePosition, @@ -230,24 +221,31 @@ public override void Draw(Action vertexAction) } else if (updateStart != -1) { - Shared.VertexBuffer.UpdateRange(updateStart * 4, updateEnd * 4); + vertexBuffer.UpdateRange(updateStart * 4, updateEnd * 4); updateStart = -1; } } // Update all remaining vertices that have been changed. if (updateStart != -1) - Shared.VertexBuffer.UpdateRange(updateStart * 4, updateEnd * 4); + vertexBuffer.UpdateRange(updateStart * 4, updateEnd * 4); base.Draw(vertexAction); Shader.Bind(); Texture.TextureGL.Bind(); - Shared.VertexBuffer.Draw(); + vertexBuffer.Draw(); Shader.Unbind(); } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + vertexBuffer.Dispose(); + } } [StructLayout(LayoutKind.Sequential)] diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModAutoplay.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModAutoplay.cs index 4e5491da9c..5b890b3d03 100644 --- a/osu.Game.Rulesets.Taiko/Mods/TaikoModAutoplay.cs +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModAutoplay.cs @@ -12,7 +12,7 @@ namespace osu.Game.Rulesets.Taiko.Mods { public class TaikoModAutoplay : ModAutoplay { - protected override Score CreateReplayScore(Beatmap beatmap) => new Score + public override Score CreateReplayScore(IBeatmap beatmap) => new Score { ScoreInfo = new ScoreInfo { User = new User { Username = "mekkadosu!" } }, Replay = new TaikoAutoGenerator(beatmap).Generate(), diff --git a/osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs b/osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs index 14a6f98480..01ba53e07b 100644 --- a/osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs +++ b/osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs @@ -9,14 +9,17 @@ using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Taiko.Objects; using osu.Game.Rulesets.Replays; +using osu.Game.Rulesets.Taiko.Beatmaps; namespace osu.Game.Rulesets.Taiko.Replays { - public class TaikoAutoGenerator : AutoGenerator + public class TaikoAutoGenerator : AutoGenerator { + public new TaikoBeatmap Beatmap => (TaikoBeatmap)base.Beatmap; + private const double swell_hit_speed = 50; - public TaikoAutoGenerator(Beatmap beatmap) + public TaikoAutoGenerator(IBeatmap beatmap) : base(beatmap) { Replay = new Replay(); diff --git a/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs index d5ab0e43d1..a867ddebae 100644 --- a/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs @@ -113,6 +113,7 @@ public void TestDecodeHitObjects() [TestCase(normal)] [TestCase(marathon)] + [Ignore("temporarily disabled pending DeepEqual fix (https://github.com/jamesfoster/DeepEqual/pull/35)")] // Currently fails: // [TestCase(with_sb)] public void TestParity(string beatmap) diff --git a/osu.Game.Tests/Visual/TestCaseReplay.cs b/osu.Game.Tests/Visual/TestCaseReplay.cs index c12015a019..c34190d567 100644 --- a/osu.Game.Tests/Visual/TestCaseReplay.cs +++ b/osu.Game.Tests/Visual/TestCaseReplay.cs @@ -1,10 +1,12 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; using System.ComponentModel; using System.Linq; using osu.Game.Rulesets; -using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Scoring; +using osu.Game.Scoring; using osu.Game.Screens.Play; namespace osu.Game.Tests.Visual @@ -14,15 +16,27 @@ public class TestCaseReplay : TestCasePlayer { protected override Player CreatePlayer(Ruleset ruleset) { - // We create a dummy RulesetContainer just to get the replay - we don't want to use mods here - // to simulate setting a replay rather than having the replay already set for us - Beatmap.Value.Mods.Value = Beatmap.Value.Mods.Value.Concat(new[] { ruleset.GetAutoplayMod() }); - var dummyRulesetContainer = ruleset.CreateRulesetContainerWith(Beatmap.Value); + var beatmap = Beatmap.Value.GetPlayableBeatmap(ruleset.RulesetInfo); - // Reset the mods - Beatmap.Value.Mods.Value = Beatmap.Value.Mods.Value.Where(m => !(m is ModAutoplay)); + return new ScoreAccessibleReplayPlayer(ruleset.GetAutoplayMod().CreateReplayScore(beatmap)); + } - return new ReplayPlayer(dummyRulesetContainer.ReplayScore); + protected override void AddCheckSteps(Func player) + { + base.AddCheckSteps(player); + AddUntilStep(() => ((ScoreAccessibleReplayPlayer)player()).ScoreProcessor.TotalScore.Value > 0, "score above zero"); + AddUntilStep(() => ((ScoreAccessibleReplayPlayer)player()).HUDOverlay.KeyCounter.Children.Any(kc => kc.CountPresses > 0), "key counter counted keys"); + } + + private class ScoreAccessibleReplayPlayer : ReplayPlayer + { + public new ScoreProcessor ScoreProcessor => base.ScoreProcessor; + public new HUDOverlay HUDOverlay => base.HUDOverlay; + + public ScoreAccessibleReplayPlayer(Score score) + : base(score) + { + } } } } diff --git a/osu.Game.Tests/Visual/TestCaseUpdateableBeatmapBackgroundSprite.cs b/osu.Game.Tests/Visual/TestCaseUpdateableBeatmapBackgroundSprite.cs index 3ee617e092..506121efd7 100644 --- a/osu.Game.Tests/Visual/TestCaseUpdateableBeatmapBackgroundSprite.cs +++ b/osu.Game.Tests/Visual/TestCaseUpdateableBeatmapBackgroundSprite.cs @@ -16,7 +16,7 @@ namespace osu.Game.Tests.Visual { public class TestCaseUpdateableBeatmapBackgroundSprite : OsuTestCase { - private UpdateableBeatmapBackgroundSprite backgroundSprite; + private TestUpdateableBeatmapBackgroundSprite backgroundSprite; [Resolved] private BeatmapManager beatmaps { get; set; } @@ -28,30 +28,36 @@ private void load(OsuGameBase osu, APIAccess api, RulesetStore rulesets) var imported = ImportBeatmapTest.LoadOszIntoOsu(osu); - Child = backgroundSprite = new UpdateableBeatmapBackgroundSprite { RelativeSizeAxes = Axes.Both }; + Child = backgroundSprite = new TestUpdateableBeatmapBackgroundSprite { RelativeSizeAxes = Axes.Both }; backgroundSprite.Beatmap.BindTo(beatmapBindable); var req = new GetBeatmapSetRequest(1); api.Queue(req); - AddStep("null", () => beatmapBindable.Value = null); - - AddStep("imported", () => beatmapBindable.Value = imported.Beatmaps.First()); + AddStep("load null beatmap", () => beatmapBindable.Value = null); + AddUntilStep(() => backgroundSprite.ChildCount == 1, "wait for cleanup..."); + AddStep("load imported beatmap", () => beatmapBindable.Value = imported.Beatmaps.First()); + AddUntilStep(() => backgroundSprite.ChildCount == 1, "wait for cleanup..."); if (api.IsLoggedIn) { AddUntilStep(() => req.Result != null, "wait for api response"); - - AddStep("online", () => beatmapBindable.Value = new BeatmapInfo + AddStep("load online beatmap", () => beatmapBindable.Value = new BeatmapInfo { BeatmapSet = req.Result?.ToBeatmapSet(rulesets) }); + AddUntilStep(() => backgroundSprite.ChildCount == 1, "wait for cleanup..."); } else { AddStep("online (login first)", () => { }); } } + + private class TestUpdateableBeatmapBackgroundSprite : UpdateableBeatmapBackgroundSprite + { + public int ChildCount => InternalChildren.Count; + } } } diff --git a/osu.Game/Beatmaps/Drawables/UpdateableBeatmapBackgroundSprite.cs b/osu.Game/Beatmaps/Drawables/UpdateableBeatmapBackgroundSprite.cs index 6fa7d47683..f0af09459f 100644 --- a/osu.Game/Beatmaps/Drawables/UpdateableBeatmapBackgroundSprite.cs +++ b/osu.Game/Beatmaps/Drawables/UpdateableBeatmapBackgroundSprite.cs @@ -9,7 +9,7 @@ namespace osu.Game.Beatmaps.Drawables { /// - /// Display a baetmap background from a local source, but fallback to online source if not available. + /// Display a beatmap background from a local source, but fallback to online source if not available. /// public class UpdateableBeatmapBackgroundSprite : ModelBackedDrawable { @@ -18,34 +18,59 @@ public class UpdateableBeatmapBackgroundSprite : ModelBackedDrawable Model = b.NewValue); + this.beatmapSetCoverType = beatmapSetCoverType; + } + + private BeatmapInfo lastModel; + + protected override DelayedLoadWrapper CreateDelayedLoadWrapper(Drawable content, double timeBeforeLoad) + { + return new DelayedLoadUnloadWrapper(() => + { + // If DelayedLoadUnloadWrapper is attempting to RELOAD the same content (Beatmap), that means that it was + // previously UNLOADED and thus its children have been disposed of, so we need to recreate them here. + if (lastModel == Beatmap.Value && Beatmap.Value != null) + return CreateDrawable(Beatmap.Value); + + // If the model has changed since the previous unload (or if there was no load), then we can safely use the given content + lastModel = Beatmap.Value; + return content; + }, timeBeforeLoad, 10000); } protected override Drawable CreateDrawable(BeatmapInfo model) { - return new DelayedLoadUnloadWrapper(() => + Drawable drawable; + + var localBeatmap = beatmaps.GetWorkingBeatmap(model); + + if (model?.BeatmapSet?.OnlineInfo != null) { - Drawable drawable; + drawable = new BeatmapSetCover(model.BeatmapSet, beatmapSetCoverType); + } + else if (localBeatmap.BeatmapInfo.ID != 0) + { + // Fall back to local background if one exists + drawable = new BeatmapBackgroundSprite(localBeatmap); + } + else + { + // Use the default background if somehow an online set does not exist and we don't have a local copy. + drawable = new BeatmapBackgroundSprite(beatmaps.DefaultBeatmap); + } - var localBeatmap = beatmaps.GetWorkingBeatmap(model); + drawable.RelativeSizeAxes = Axes.Both; + drawable.Anchor = Anchor.Centre; + drawable.Origin = Anchor.Centre; + drawable.FillMode = FillMode.Fill; + drawable.OnLoadComplete = d => d.FadeInFromZero(400); - if (localBeatmap.BeatmapInfo.ID == 0 && model?.BeatmapSet?.OnlineInfo != null) - drawable = new BeatmapSetCover(model.BeatmapSet); - else - drawable = new BeatmapBackgroundSprite(localBeatmap); - - drawable.RelativeSizeAxes = Axes.Both; - drawable.Anchor = Anchor.Centre; - drawable.Origin = Anchor.Centre; - drawable.FillMode = FillMode.Fill; - drawable.OnLoadComplete = d => d.FadeInFromZero(400); - - return drawable; - }, 500, 10000); + return drawable; } - - protected override double FadeDuration => 0; } } diff --git a/osu.Game/Graphics/Backgrounds/Triangles.cs b/osu.Game/Graphics/Backgrounds/Triangles.cs index ebd9db786f..c67d779c37 100644 --- a/osu.Game/Graphics/Backgrounds/Triangles.cs +++ b/osu.Game/Graphics/Backgrounds/Triangles.cs @@ -64,7 +64,7 @@ public class Triangles : Drawable private readonly SortedList parts = new SortedList(Comparer.Default); - private Shader shader; + private IShader shader; private readonly Texture texture; public Triangles() @@ -75,7 +75,7 @@ public Triangles() [BackgroundDependencyLoader] private void load(ShaderManager shaders) { - shader = shaders?.Load(VertexShaderDescriptor.TEXTURE_2, FragmentShaderDescriptor.TEXTURE_ROUNDED); + shader = shaders.Load(VertexShaderDescriptor.TEXTURE_2, FragmentShaderDescriptor.TEXTURE_ROUNDED); } protected override void LoadComplete() @@ -180,8 +180,6 @@ protected virtual TriangleParticle CreateTriangle() protected override DrawNode CreateDrawNode() => new TrianglesDrawNode(); - private readonly TrianglesDrawNodeSharedData sharedData = new TrianglesDrawNodeSharedData(); - protected override void ApplyDrawNode(DrawNode node) { base.ApplyDrawNode(node); @@ -191,27 +189,21 @@ protected override void ApplyDrawNode(DrawNode node) trianglesNode.Shader = shader; trianglesNode.Texture = texture; trianglesNode.Size = DrawSize; - trianglesNode.Shared = sharedData; trianglesNode.Parts.Clear(); trianglesNode.Parts.AddRange(parts); } - private class TrianglesDrawNodeSharedData - { - public readonly LinearBatch VertexBatch = new LinearBatch(100 * 3, 10, PrimitiveType.Triangles); - } - private class TrianglesDrawNode : DrawNode { - public Shader Shader; + public IShader Shader; public Texture Texture; - public TrianglesDrawNodeSharedData Shared; - public readonly List Parts = new List(); public Vector2 Size; + private readonly LinearBatch vertexBatch = new LinearBatch(100 * 3, 10, PrimitiveType.Triangles); + public override void Draw(Action vertexAction) { base.Draw(vertexAction); @@ -239,12 +231,19 @@ public override void Draw(Action vertexAction) triangle, colourInfo, null, - Shared.VertexBatch.AddAction, + vertexBatch.AddAction, Vector2.Divide(localInflationAmount, size)); } Shader.Unbind(); } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + vertexBatch.Dispose(); + } } protected struct TriangleParticle : IComparable diff --git a/osu.Game/Graphics/UserInterface/LineGraph.cs b/osu.Game/Graphics/UserInterface/LineGraph.cs index 7a20dd3d16..74025b71ff 100644 --- a/osu.Game/Graphics/UserInterface/LineGraph.cs +++ b/osu.Game/Graphics/UserInterface/LineGraph.cs @@ -69,7 +69,7 @@ public LineGraph() { Masking = true, RelativeSizeAxes = Axes.Both, - Child = path = new SmoothPath { RelativeSizeAxes = Axes.Both, PathWidth = 1 } + Child = path = new SmoothPath { RelativeSizeAxes = Axes.Both, PathRadius = 1 } }); } @@ -102,9 +102,10 @@ private void applyPath() for (int i = 0; i < values.Length; i++) { - float x = (i + count - values.Length) / (float)(count - 1) * DrawWidth - 1; - float y = GetYPosition(values[i]) * DrawHeight - 1; - // the -1 is for inner offset in path (actually -PathWidth) + // Make sure that we are accounting for path width when calculating vertex positions + // We need to apply 2x the path radius to account for it because the full diameter of the line accounts into height + float x = (i + count - values.Length) / (float)(count - 1) * (DrawWidth - 2 * path.PathRadius); + float y = GetYPosition(values[i]) * (DrawHeight - 2 * path.PathRadius); path.AddVertex(new Vector2(x, y)); } } diff --git a/osu.Game/Online/Multiplayer/Room.cs b/osu.Game/Online/Multiplayer/Room.cs index 77236ce3c8..53089897f7 100644 --- a/osu.Game/Online/Multiplayer/Room.cs +++ b/osu.Game/Online/Multiplayer/Room.cs @@ -124,6 +124,7 @@ public void CopyFrom(Room other) if (other.Host.Value != null && Host.Value?.Id != other.Host.Value.Id) Host.Value = other.Host.Value; + ChannelId.Value = other.ChannelId.Value; Status.Value = other.Status.Value; Availability.Value = other.Availability.Value; Type.Value = other.Type.Value; diff --git a/osu.Game/Rulesets/Mods/ModAutoplay.cs b/osu.Game/Rulesets/Mods/ModAutoplay.cs index 22e70b446e..44c78f8436 100644 --- a/osu.Game/Rulesets/Mods/ModAutoplay.cs +++ b/osu.Game/Rulesets/Mods/ModAutoplay.cs @@ -14,10 +14,6 @@ namespace osu.Game.Rulesets.Mods public abstract class ModAutoplay : ModAutoplay, IApplicableToRulesetContainer where T : HitObject { - protected virtual Score CreateReplayScore(Beatmap beatmap) => new Score { Replay = new Replay() }; - - public override bool HasImplementation => GetType().GenericTypeArguments.Length == 0; - public virtual void ApplyToRulesetContainer(RulesetContainer rulesetContainer) => rulesetContainer.SetReplayScore(CreateReplayScore(rulesetContainer.Beatmap)); } @@ -31,5 +27,9 @@ public abstract class ModAutoplay : Mod, IApplicableFailOverride public override double ScoreMultiplier => 1; public bool AllowFail => false; public override Type[] IncompatibleMods => new[] { typeof(ModRelax), typeof(ModSuddenDeath), typeof(ModNoFail) }; + + public override bool HasImplementation => GetType().GenericTypeArguments.Length == 0; + + public virtual Score CreateReplayScore(IBeatmap beatmap) => new Score { Replay = new Replay() }; } } diff --git a/osu.Game/Rulesets/Mods/ModFlashlight.cs b/osu.Game/Rulesets/Mods/ModFlashlight.cs index dfada5614a..ab095f417a 100644 --- a/osu.Game/Rulesets/Mods/ModFlashlight.cs +++ b/osu.Game/Rulesets/Mods/ModFlashlight.cs @@ -61,7 +61,7 @@ public virtual void ApplyToRulesetContainer(RulesetContainer rulesetContainer public abstract class Flashlight : Drawable { internal BindableInt Combo; - private Shader shader; + private IShader shader; protected override DrawNode CreateDrawNode() => new FlashlightDrawNode(); @@ -139,7 +139,7 @@ protected Vector2 FlashlightSize private class FlashlightDrawNode : DrawNode { - public Shader Shader; + public IShader Shader; public Quad ScreenSpaceDrawQuad; public Vector2 FlashlightPosition; public Vector2 FlashlightSize; diff --git a/osu.Game/Rulesets/Replays/AutoGenerator.cs b/osu.Game/Rulesets/Replays/AutoGenerator.cs index efca0a5883..1d4cdbf04c 100644 --- a/osu.Game/Rulesets/Replays/AutoGenerator.cs +++ b/osu.Game/Rulesets/Replays/AutoGenerator.cs @@ -1,14 +1,12 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using osu.Game.Rulesets.Objects; using osu.Game.Beatmaps; using osu.Game.Replays; namespace osu.Game.Rulesets.Replays { - public abstract class AutoGenerator : IAutoGenerator - where T : HitObject + public abstract class AutoGenerator : IAutoGenerator { /// /// Creates the auto replay and returns it. @@ -21,11 +19,11 @@ public abstract class AutoGenerator : IAutoGenerator /// /// The beatmap we're making. /// - protected Beatmap Beatmap; + protected IBeatmap Beatmap; #endregion - protected AutoGenerator(Beatmap beatmap) + protected AutoGenerator(IBeatmap beatmap) { Beatmap = beatmap; } diff --git a/osu.Game/Rulesets/Ruleset.cs b/osu.Game/Rulesets/Ruleset.cs index ffab0abebf..70f15b99bd 100644 --- a/osu.Game/Rulesets/Ruleset.cs +++ b/osu.Game/Rulesets/Ruleset.cs @@ -42,7 +42,7 @@ public IEnumerable GetAllMods() => Enum.GetValues(typeof(ModType)).CastAn enumerable of constructed s public virtual IEnumerable ConvertLegacyMods(LegacyMods mods) => new Mod[] { }; - public Mod GetAutoplayMod() => GetAllMods().First(mod => mod is ModAutoplay); + public ModAutoplay GetAutoplayMod() => GetAllMods().OfType().First(); protected Ruleset(RulesetInfo rulesetInfo = null) { diff --git a/osu.Game/Screens/Loader.cs b/osu.Game/Screens/Loader.cs index 0db0f1a1a3..d858cb076a 100644 --- a/osu.Game/Screens/Loader.cs +++ b/osu.Game/Screens/Loader.cs @@ -89,7 +89,7 @@ private void load(OsuGameBase game) /// public class ShaderPrecompiler : Drawable { - private readonly List loadTargets = new List(); + private readonly List loadTargets = new List(); public bool FinishedCompiling { get; private set; } @@ -106,7 +106,7 @@ private void load(ShaderManager manager) loadTargets.Add(manager.Load(VertexShaderDescriptor.TEXTURE_3, FragmentShaderDescriptor.TEXTURE)); } - protected virtual bool AllLoaded => loadTargets.All(s => s.Loaded); + protected virtual bool AllLoaded => loadTargets.All(s => s.IsLoaded); protected override void Update() { diff --git a/osu.Game/Screens/Menu/LogoVisualisation.cs b/osu.Game/Screens/Menu/LogoVisualisation.cs index e930f924be..a41a12927b 100644 --- a/osu.Game/Screens/Menu/LogoVisualisation.cs +++ b/osu.Game/Screens/Menu/LogoVisualisation.cs @@ -63,7 +63,7 @@ public class LogoVisualisation : Drawable, IHasAccentColour private readonly float[] frequencyAmplitudes = new float[256]; - private Shader shader; + private IShader shader; private readonly Texture texture; public LogoVisualisation() @@ -131,8 +131,6 @@ protected override void Update() protected override DrawNode CreateDrawNode() => new VisualisationDrawNode(); - private readonly VisualiserSharedData sharedData = new VisualiserSharedData(); - protected override void ApplyDrawNode(DrawNode node) { base.ApplyDrawNode(node); @@ -142,29 +140,23 @@ protected override void ApplyDrawNode(DrawNode node) visNode.Shader = shader; visNode.Texture = texture; visNode.Size = DrawSize.X; - visNode.Shared = sharedData; visNode.Colour = AccentColour; visNode.AudioData = frequencyAmplitudes; } - private class VisualiserSharedData - { - public readonly QuadBatch VertexBatch = new QuadBatch(100, 10); - } - private class VisualisationDrawNode : DrawNode { - public Shader Shader; + public IShader Shader; public Texture Texture; - public VisualiserSharedData Shared; - //Asuming the logo is a circle, we don't need a second dimension. public float Size; public Color4 Colour; public float[] AudioData; + private readonly QuadBatch vertexBatch = new QuadBatch(100, 10); + public override void Draw(Action vertexAction) { base.Draw(vertexAction); @@ -209,7 +201,7 @@ public override void Draw(Action vertexAction) rectangle, colourInfo, null, - Shared.VertexBatch.AddAction, + vertexBatch.AddAction, //barSize by itself will make it smooth more in the X axis than in the Y axis, this reverts that. Vector2.Divide(inflation, barSize.Yx)); } @@ -218,6 +210,13 @@ public override void Draw(Action vertexAction) Shader.Unbind(); } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + vertexBatch.Dispose(); + } } } } diff --git a/osu.Game/Screens/Multi/Components/MultiplayerBackgroundSprite.cs b/osu.Game/Screens/Multi/Components/MultiplayerBackgroundSprite.cs index 512f79942d..968fa6e72e 100644 --- a/osu.Game/Screens/Multi/Components/MultiplayerBackgroundSprite.cs +++ b/osu.Game/Screens/Multi/Components/MultiplayerBackgroundSprite.cs @@ -9,6 +9,13 @@ namespace osu.Game.Screens.Multi.Components { public class MultiplayerBackgroundSprite : MultiplayerComposite { + private readonly BeatmapSetCoverType beatmapSetCoverType; + + public MultiplayerBackgroundSprite(BeatmapSetCoverType beatmapSetCoverType = BeatmapSetCoverType.Cover) + { + this.beatmapSetCoverType = beatmapSetCoverType; + } + [BackgroundDependencyLoader] private void load() { @@ -19,6 +26,6 @@ private void load() CurrentItem.BindValueChanged(item => sprite.Beatmap.Value = item.NewValue?.Beatmap, true); } - protected virtual UpdateableBeatmapBackgroundSprite CreateBackgroundSprite() => new UpdateableBeatmapBackgroundSprite { RelativeSizeAxes = Axes.Both }; + protected virtual UpdateableBeatmapBackgroundSprite CreateBackgroundSprite() => new UpdateableBeatmapBackgroundSprite(beatmapSetCoverType) { RelativeSizeAxes = Axes.Both }; } } diff --git a/osu.Game/Screens/Multi/Lounge/Components/DrawableRoom.cs b/osu.Game/Screens/Multi/Lounge/Components/DrawableRoom.cs index e41238a7ff..4bab68058f 100644 --- a/osu.Game/Screens/Multi/Lounge/Components/DrawableRoom.cs +++ b/osu.Game/Screens/Multi/Lounge/Components/DrawableRoom.cs @@ -11,6 +11,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Game.Beatmaps; +using osu.Game.Beatmaps.Drawables; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; @@ -137,7 +138,7 @@ private void load(OsuColour colours) Width = cover_width, Masking = true, Margin = new MarginPadding { Left = side_strip_width }, - Child = new MultiplayerBackgroundSprite { RelativeSizeAxes = Axes.Both } + Child = new MultiplayerBackgroundSprite(BeatmapSetCoverType.List) { RelativeSizeAxes = Axes.Both } }, new Container { diff --git a/osu.Game/Screens/Multi/Match/Components/MatchChatDisplay.cs b/osu.Game/Screens/Multi/Match/Components/MatchChatDisplay.cs index bd8e4c7335..f8b64a54ef 100644 --- a/osu.Game/Screens/Multi/Match/Components/MatchChatDisplay.cs +++ b/osu.Game/Screens/Multi/Match/Components/MatchChatDisplay.cs @@ -28,13 +28,15 @@ protected override void LoadComplete() { base.LoadComplete(); - roomId.BindValueChanged(_ => updateChannel(), true); + channelId.BindValueChanged(_ => updateChannel(), true); } private void updateChannel() { - if (roomId.Value != null) - Channel.Value = channelManager?.JoinChannel(new Channel { Id = channelId.Value, Type = ChannelType.Multiplayer, Name = $"#mp_{roomId.Value}" }); + if (roomId.Value == null || channelId.Value == 0) + return; + + Channel.Value = channelManager?.JoinChannel(new Channel { Id = channelId.Value, Type = ChannelType.Multiplayer, Name = $"#lazermp_{roomId.Value}" }); } } } diff --git a/osu.Game/Screens/Select/MatchSongSelect.cs b/osu.Game/Screens/Select/MatchSongSelect.cs index f6d758df29..3dc152eebe 100644 --- a/osu.Game/Screens/Select/MatchSongSelect.cs +++ b/osu.Game/Screens/Select/MatchSongSelect.cs @@ -60,9 +60,12 @@ public override bool OnExiting(IScreen next) if (base.OnExiting(next)) return true; - Beatmap.Value = beatmaps.GetWorkingBeatmap(CurrentItem.Value?.Beatmap); - Beatmap.Value.Mods.Value = selectedMods.Value = CurrentItem.Value?.RequiredMods; - Ruleset.Value = CurrentItem.Value?.Ruleset; + if (CurrentItem.Value != null) + { + Ruleset.Value = CurrentItem.Value.Ruleset; + Beatmap.Value = beatmaps.GetWorkingBeatmap(CurrentItem.Value.Beatmap); + Beatmap.Value.Mods.Value = selectedMods.Value = CurrentItem.Value.RequiredMods; + } Beatmap.Disabled = true; Ruleset.Disabled = true; diff --git a/osu.Game/Utils/RavenLogger.cs b/osu.Game/Utils/RavenLogger.cs index acc3ab28b5..7f4faa60ae 100644 --- a/osu.Game/Utils/RavenLogger.cs +++ b/osu.Game/Utils/RavenLogger.cs @@ -20,14 +20,14 @@ public class RavenLogger : IDisposable private readonly List tasks = new List(); - private Exception lastException; - public RavenLogger(OsuGame game) { raven.Release = game.Version; if (!game.IsDeployedBuild) return; + Exception lastException = null; + Logger.NewEntry += entry => { if (entry.Level < LogLevel.Verbose) return; diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 8f9a7cd14b..882c6ef064 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -16,7 +16,7 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index 499878347b..bc3e553fef 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -105,12 +105,12 @@ - - + + - + diff --git a/osu.sln.DotSettings b/osu.sln.DotSettings index 3c6a6dd2a9..b1ac31f2ce 100644 --- a/osu.sln.DotSettings +++ b/osu.sln.DotSettings @@ -262,6 +262,7 @@ IL IP IPC + JIT LTRB MD5 NS