1
0
mirror of https://github.com/ppy/osu.git synced 2024-09-21 19:27:24 +08:00

Merge branch 'master' into intro-testing-improvements

This commit is contained in:
Dean Herbert 2019-07-22 23:44:14 +09:00 committed by GitHub
commit ade661236a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
108 changed files with 635 additions and 604 deletions

View File

@ -1,5 +1,5 @@
<p align="center">
<img width="256" height="256" src="assets/lazer.png">
<img width="500px" src="assets/lazer.png">
</p>
# osu!
@ -100,7 +100,7 @@ Before starting, please make sure you are familiar with the [development and tes
Note that while we already have certain standards in place, nothing is set in stone. If you have an issue with the way code is structured; with any libraries we are using; with any processes involved with contributing, *please* bring it up. We welcome all feedback so we can make contributing to this project as pain-free as possible.
For those interested, we love to reward quality contributions via bounties, paid out via paypal or osu! supporter tags. Don't hesitate to [request a bounty](https://docs.google.com/forms/d/e/1FAIpQLSet_8iFAgPMG526pBZ2Kic6HSh7XPM3fE8xPcnWNkMzINDdYg/viewform) for your work on this project.
For those interested, we love to reward quality contributions via [bounties](https://docs.google.com/spreadsheets/d/1jNXfj_S3Pb5PErA-czDdC9DUu4IgUbe1Lt8E7CYUJuE/view?&rm=minimal#gid=523803337), paid out via paypal or osu! supporter tags. Don't hesitate to [request a bounty](https://docs.google.com/forms/d/e/1FAIpQLSet_8iFAgPMG526pBZ2Kic6HSh7XPM3fE8xPcnWNkMzINDdYg/viewform) for your work on this project.
## Licence

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 187 KiB

View File

@ -63,6 +63,6 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="ppy.osu.Game.Resources" Version="2019.702.0" />
<PackageReference Include="ppy.osu.Framework.Android" Version="2019.711.0" />
<PackageReference Include="ppy.osu.Framework.Android" Version="2019.719.0" />
</ItemGroup>
</Project>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 38 KiB

BIN
osu.Desktop/lazer.ico Normal file → Executable file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 91 KiB

After

Width:  |  Height:  |  Size: 85 KiB

View File

@ -15,6 +15,7 @@ namespace osu.Game.Rulesets.Osu.Tests
protected override string ResourceAssembly => "osu.Game.Rulesets.Osu";
[TestCase(6.931145117263422, "diffcalc-test")]
[TestCase(1.0736587013228804d, "zero-length-sliders")]
public void Test(double expected, string name)
=> base.Test(expected, name);

View File

@ -20,7 +20,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components
this.hitCircle = hitCircle;
Origin = Anchor.Centre;
Size = new Vector2((float)OsuHitObject.OBJECT_RADIUS * 2);
Size = new Vector2(OsuHitObject.OBJECT_RADIUS * 2);
Scale = new Vector2(hitCircle.Scale);
CornerRadius = Size.X / 2;

View File

@ -24,7 +24,6 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
InternalChild = body = new ManualSliderBody
{
AccentColour = Color4.Transparent,
PathRadius = slider.Scale * 64
};
}
@ -34,7 +33,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
body.BorderColour = colours.Yellow;
PositionBindable.BindValueChanged(_ => updatePosition(), true);
ScaleBindable.BindValueChanged(scale => body.PathRadius = scale.NewValue * 64, true);
ScaleBindable.BindValueChanged(scale => body.PathRadius = scale.NewValue * OsuHitObject.OBJECT_RADIUS, true);
}
private void updatePosition() => Position = slider.StackedPosition;

View File

@ -29,6 +29,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
ShakeDuration = 30,
RelativeSizeAxes = Axes.Both
});
Alpha = 0;
}
@ -38,6 +39,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
protected override void ClearInternal(bool disposeChildren = true) => shakeContainer.Clear(disposeChildren);
protected override bool RemoveInternal(Drawable drawable) => shakeContainer.Remove(drawable);
protected sealed override double InitialLifetimeOffset => HitObject.TimePreempt;
protected sealed override void UpdateState(ArmedState state)
{
double transformTime = HitObject.StartTime - HitObject.TimePreempt;

View File

@ -50,7 +50,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
{
Body = new SnakingSliderBody(s)
{
PathRadius = s.Scale * 64,
PathRadius = s.Scale * OsuHitObject.OBJECT_RADIUS,
},
ticks = new Container<DrawableSliderTick> { RelativeSizeAxes = Axes.Both },
repeatPoints = new Container<DrawableRepeatPoint> { RelativeSizeAxes = Axes.Both },
@ -156,6 +156,12 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
}
}
public override void OnKilled()
{
base.OnKilled();
Body.RecyclePath();
}
protected override void SkinChanged(ISkinSource skin, bool allowFallback)
{
base.SkinChanged(skin, allowFallback);

View File

@ -21,7 +21,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
public CirclePiece()
{
Size = new Vector2((float)OsuHitObject.OBJECT_RADIUS * 2);
Size = new Vector2(OsuHitObject.OBJECT_RADIUS * 2);
Masking = true;
CornerRadius = Size.X / 2;

View File

@ -12,7 +12,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
{
public ExplodePiece()
{
Size = new Vector2(128);
Size = new Vector2(OsuHitObject.OBJECT_RADIUS * 2);
Anchor = Anchor.Centre;
Origin = Anchor.Centre;

View File

@ -1,4 +1,4 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Graphics;
@ -13,7 +13,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
{
public FlashPiece()
{
Size = new Vector2(128);
Size = new Vector2(OsuHitObject.OBJECT_RADIUS * 2);
Anchor = Anchor.Centre;
Origin = Anchor.Centre;

View File

@ -1,4 +1,4 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Graphics;
@ -14,7 +14,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
{
public RingPiece()
{
Size = new Vector2(128);
Size = new Vector2(OsuHitObject.OBJECT_RADIUS * 2);
Anchor = Anchor.Centre;
Origin = Anchor.Centre;

View File

@ -17,8 +17,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
{
public class SliderBall : CircularContainer, ISliderProgress, IRequireHighFrequencyMousePosition
{
private const float width = 128;
private Color4 accentColour = Color4.Black;
public Func<OsuAction?> GetInitialHitAction;
@ -57,8 +55,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
{
Origin = Anchor.Centre,
Anchor = Anchor.Centre,
Width = width,
Height = width,
Width = OsuHitObject.OBJECT_RADIUS * 2,
Height = OsuHitObject.OBJECT_RADIUS * 2,
Alpha = 0,
Child = new SkinnableDrawable("Play/osu/sliderfollowcircle", _ => new CircularContainer
{
@ -84,8 +82,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
Alpha = 1,
Child = new Container
{
Width = width,
Height = width,
Width = OsuHitObject.OBJECT_RADIUS * 2,
Height = OsuHitObject.OBJECT_RADIUS * 2,
// TODO: support skin filename animation (sliderb0, sliderb1...)
Child = new SkinnableDrawable("Play/osu/sliderb", _ => new CircularContainer
{

View File

@ -13,7 +13,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
{
public const float DEFAULT_BORDER_SIZE = 1;
private readonly SliderPath path;
private SliderPath path;
protected Path Path => path;
public float PathRadius
@ -77,6 +78,22 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
InternalChild = path = new SliderPath();
}
/// <summary>
/// Initialises a new <see cref="SliderPath"/>, releasing all resources retained by the old one.
/// </summary>
public void RecyclePath()
{
InternalChild = path = new SliderPath
{
Position = path.Position,
PathRadius = path.PathRadius,
AccentColour = path.AccentColour,
BorderColour = path.BorderColour,
BorderSize = path.BorderSize,
Vertices = path.Vertices
};
}
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => path.ReceivePositionalInputAt(screenSpacePos);
/// <summary>

View File

@ -12,7 +12,7 @@ namespace osu.Game.Rulesets.Osu.Objects
{
public abstract class OsuHitObject : HitObject, IHasComboInformation, IHasPosition
{
public const double OBJECT_RADIUS = 64;
public const float OBJECT_RADIUS = 64;
public double TimePreempt = 600;
public double TimeFadeIn = 400;

View File

@ -0,0 +1,28 @@
osu file format v14
[Difficulty]
HPDrainRate:3
CircleSize:3
OverallDifficulty:3
ApproachRate:4.5
SliderMultiplier:0.799999999999999
SliderTickRate:1
[TimingPoints]
800,260.869565217391,3,2,10,60,1,0
[HitObjects]
// Linear
78,193,2365,2,0,L|330:193,1,0
78,193,3669,2,0,L|330:193,1,0
78,193,4973,2,0,L|330:193,1,0
// Perfect-curve
151,206,6278,2,0,P|293:75|345:204,1,0
151,206,8104,2,0,P|293:75|345:204,1,0
151,206,9930,2,0,P|293:75|345:204,1,0
// Bezier
76,191,11756,2,0,B|176:59|358:340|438:190,1,0
76,191,13582,2,0,B|176:59|358:340|438:190,1,0
76,191,15408,2,0,B|176:59|358:340|438:190,1,0

View File

@ -162,7 +162,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
private readonly TrailPart[] parts = new TrailPart[max_sprites];
private Vector2 size;
private readonly VertexBatch<TexturedTrailVertex> vertexBatch = new QuadBatch<TexturedTrailVertex>(max_sprites, 1);
private readonly TrailBatch vertexBatch = new TrailBatch(max_sprites, 1);
public TrailDrawNode(CursorTrail source)
: base(source)
@ -196,21 +196,16 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
for (int i = 0; i < parts.Length; ++i)
{
vertexBatch.DrawTime = parts[i].Time;
Vector2 pos = parts[i].Position;
float localTime = parts[i].Time;
DrawQuad(
texture,
new Quad(pos.X - size.X / 2, pos.Y - size.Y / 2, size.X, size.Y),
DrawColourInfo.Colour,
null,
v => vertexBatch.Add(new TexturedTrailVertex
{
Position = v.Position,
TexturePosition = v.TexturePosition,
Time = localTime + 1,
Colour = v.Colour,
}));
vertexBatch.AddAction);
}
shader.Unbind();
@ -222,6 +217,25 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
vertexBatch.Dispose();
}
// Todo: This shouldn't exist, but is currently used to reduce allocations by caching variable-capturing closures.
private class TrailBatch : QuadBatch<TexturedTrailVertex>
{
public new readonly Action<TexturedVertex2D> AddAction;
public float DrawTime;
public TrailBatch(int size, int maxBuffers)
: base(size, maxBuffers)
{
AddAction = v => Add(new TexturedTrailVertex
{
Position = v.Position,
TexturePosition = v.TexturePosition,
Time = DrawTime + 1,
Colour = v.Colour,
});
}
}
}
[StructLayout(LayoutKind.Sequential)]

View File

@ -12,6 +12,7 @@ using osu.Game.Rulesets.UI;
using System.Linq;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Osu.UI.Cursor;
using osu.Game.Skinning;
namespace osu.Game.Rulesets.Osu.UI
{
@ -39,7 +40,13 @@ namespace osu.Game.Rulesets.Osu.UI
RelativeSizeAxes = Axes.Both,
Depth = 1,
},
HitObjectContainer,
// Todo: This should not exist, but currently helps to reduce LOH allocations due to unbinding skin source events on judgement disposal
// Todo: Remove when hitobjects are properly pooled
new LocalSkinOverrideContainer(null)
{
RelativeSizeAxes = Axes.Both,
Child = HitObjectContainer,
},
approachCircles = new ApproachCircleProxyContainer
{
RelativeSizeAxes = Axes.Both,

View File

@ -10,6 +10,7 @@ using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Input.Events;
using osu.Framework.Input.States;
using osu.Framework.Platform;
@ -36,7 +37,7 @@ using osuTK.Graphics;
namespace osu.Game.Tests.Visual.Background
{
[TestFixture]
public class TestSceneBackgroundScreenBeatmap : ManualInputManagerTestScene
public class TestSceneUserDimContainer : ManualInputManagerTestScene
{
public override IReadOnlyList<Type> RequiredTypes => new[]
{
@ -137,14 +138,14 @@ namespace osu.Game.Tests.Visual.Background
player.StoryboardEnabled.Value = true;
});
waitForDim();
AddAssert("Background is invisible, storyboard is visible", () => songSelect.IsBackgroundInvisible() && player.IsStoryboardVisible());
AddAssert("Background is invisible, storyboard is visible", () => songSelect.IsBackgroundInvisible() && player.IsStoryboardVisible);
AddStep("Storyboard Disabled", () =>
{
player.ReplacesBackground.Value = false;
player.StoryboardEnabled.Value = false;
});
waitForDim();
AddAssert("Background is visible, storyboard is invisible", () => songSelect.IsBackgroundVisible() && player.IsStoryboardInvisible());
AddAssert("Background is visible, storyboard is invisible", () => songSelect.IsBackgroundVisible() && !player.IsStoryboardVisible);
}
/// <summary>
@ -241,14 +242,15 @@ namespace osu.Game.Tests.Visual.Background
{
player.StoryboardEnabled.Value = false;
player.ReplacesBackground.Value = false;
player.CurrentStoryboardContainer.Add(new OsuSpriteText
player.DimmableStoryboard.Add(new OsuSpriteText
{
Size = new Vector2(250, 50),
Size = new Vector2(500, 50),
Alpha = 1,
Colour = Color4.Tomato,
Colour = Color4.White,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Text = "THIS IS A STORYBOARD",
Font = new FontUsage(size: 50)
});
});
@ -300,7 +302,7 @@ namespace osu.Game.Tests.Visual.Background
public bool IsBackgroundUndimmed() => ((FadeAccessibleBackground)Background).CurrentColour == Color4.White;
public bool IsUserBlurApplied() => ((FadeAccessibleBackground)Background).CurrentBlur == new Vector2((float)BlurLevel.Value * 25);
public bool IsUserBlurApplied() => ((FadeAccessibleBackground)Background).CurrentBlur == new Vector2((float)BlurLevel.Value * BackgroundScreenBeatmap.USER_BLUR_FACTOR);
public bool IsUserBlurDisabled() => ((FadeAccessibleBackground)Background).CurrentBlur == new Vector2(0);
@ -333,17 +335,7 @@ namespace osu.Game.Tests.Visual.Background
{
protected override BackgroundScreen CreateBackground() => new FadeAccessibleBackground(Beatmap.Value);
protected override UserDimContainer CreateStoryboardContainer()
{
return new TestUserDimContainer(true)
{
RelativeSizeAxes = Axes.Both,
Alpha = 1,
EnableUserDim = { Value = true }
};
}
public UserDimContainer CurrentStoryboardContainer => StoryboardContainer;
public new DimmableStoryboard DimmableStoryboard => base.DimmableStoryboard;
// Whether or not the player should be allowed to load.
public bool BlockLoad;
@ -357,9 +349,7 @@ namespace osu.Game.Tests.Visual.Background
{
}
public bool IsStoryboardVisible() => ((TestUserDimContainer)CurrentStoryboardContainer).CurrentAlpha == 1;
public bool IsStoryboardInvisible() => ((TestUserDimContainer)CurrentStoryboardContainer).CurrentAlpha <= 1;
public bool IsStoryboardVisible => DimmableStoryboard.ContentDisplayed;
[BackgroundDependencyLoader]
private void load(OsuConfigManager config, CancellationToken token)
@ -392,15 +382,15 @@ namespace osu.Game.Tests.Visual.Background
private class FadeAccessibleBackground : BackgroundScreenBeatmap
{
protected override UserDimContainer CreateFadeContainer() => fadeContainer = new TestUserDimContainer { RelativeSizeAxes = Axes.Both };
protected override DimmableBackground CreateFadeContainer() => dimmable = new TestDimmableBackground { RelativeSizeAxes = Axes.Both };
public Color4 CurrentColour => fadeContainer.CurrentColour;
public Color4 CurrentColour => dimmable.CurrentColour;
public float CurrentAlpha => fadeContainer.CurrentAlpha;
public float CurrentAlpha => dimmable.CurrentAlpha;
public Vector2 CurrentBlur => Background.BlurSigma;
private TestUserDimContainer fadeContainer;
private TestDimmableBackground dimmable;
public FadeAccessibleBackground(WorkingBeatmap beatmap)
: base(beatmap)
@ -408,15 +398,10 @@ namespace osu.Game.Tests.Visual.Background
}
}
private class TestUserDimContainer : UserDimContainer
private class TestDimmableBackground : BackgroundScreenBeatmap.DimmableBackground
{
public Color4 CurrentColour => DimContainer.Colour;
public float CurrentAlpha => DimContainer.Alpha;
public TestUserDimContainer(bool isStoryboard = false)
: base(isStoryboard)
{
}
public Color4 CurrentColour => Content.Colour;
public float CurrentAlpha => Content.Alpha;
}
}
}

View File

@ -1,19 +1,88 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System.Linq;
using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Timing;
using osu.Game.Screens.Play;
using osuTK;
using osuTK.Input;
namespace osu.Game.Tests.Visual.Gameplay
{
[TestFixture]
public class TestSceneSkipOverlay : OsuTestScene
public class TestSceneSkipOverlay : ManualInputManagerTestScene
{
protected override void LoadComplete()
{
base.LoadComplete();
private SkipOverlay skip;
private int requestCount;
Add(new SkipOverlay(Clock.CurrentTime + 5000));
[SetUp]
public void SetUp() => Schedule(() =>
{
requestCount = 0;
Child = new Container
{
RelativeSizeAxes = Axes.Both,
Clock = new FramedOffsetClock(Clock)
{
Offset = -Clock.CurrentTime,
},
Children = new Drawable[]
{
skip = new SkipOverlay(6000)
{
RequestSeek = _ => requestCount++
}
},
};
});
[Test]
public void TestFadeOnIdle()
{
AddStep("move mouse", () => InputManager.MoveMouseTo(Vector2.Zero));
AddUntilStep("fully visible", () => skip.Children.First().Alpha == 1);
AddUntilStep("wait for fade", () => skip.Children.First().Alpha < 1);
AddStep("move mouse", () => InputManager.MoveMouseTo(skip.ScreenSpaceDrawQuad.Centre));
AddUntilStep("fully visible", () => skip.Children.First().Alpha == 1);
AddUntilStep("wait for fade", () => skip.Children.First().Alpha < 1);
}
[Test]
public void TestClickableAfterFade()
{
AddStep("move mouse", () => InputManager.MoveMouseTo(skip.ScreenSpaceDrawQuad.Centre));
AddUntilStep("wait for fade", () => skip.Children.First().Alpha == 0);
AddStep("click", () => InputManager.Click(MouseButton.Left));
checkRequestCount(1);
}
[Test]
public void TestClickOnlyActuatesOnce()
{
AddStep("move mouse", () => InputManager.MoveMouseTo(skip.ScreenSpaceDrawQuad.Centre));
AddStep("click", () => InputManager.Click(MouseButton.Left));
AddStep("click", () => InputManager.Click(MouseButton.Left));
AddStep("click", () => InputManager.Click(MouseButton.Left));
AddStep("click", () => InputManager.Click(MouseButton.Left));
checkRequestCount(1);
}
[Test]
public void TestDoesntFadeOnMouseDown()
{
AddStep("move mouse", () => InputManager.MoveMouseTo(skip.ScreenSpaceDrawQuad.Centre));
AddStep("button down", () => InputManager.PressButton(MouseButton.Left));
AddUntilStep("wait for overlay disapper", () => !skip.IsAlive);
AddAssert("ensure button didn't disappear", () => skip.Children.First().Alpha > 0);
AddStep("button up", () => InputManager.ReleaseButton(MouseButton.Left));
checkRequestCount(0);
}
private void checkRequestCount(int expected) =>
AddAssert($"request count is {expected}", () => requestCount == expected);
}
}

View File

@ -10,7 +10,7 @@ namespace osu.Game.Tournament.Screens.Showcase
[BackgroundDependencyLoader]
private void load()
{
AddInternal(new TournamentLogo());
AddInternal(new TournamentLogo(false));
}
}
}

View File

@ -45,7 +45,7 @@ namespace osu.Game.Tournament.Screens.TeamWin
RelativeSizeAxes = Axes.Both,
Loop = true,
},
new TournamentLogo
new TournamentLogo(false)
{
Y = 40,
},

View File

@ -66,6 +66,11 @@ namespace osu.Game.Beatmaps
/// </summary>
public int FavouriteCount { get; set; }
/// <summary>
/// Whether this beatmap set has been favourited by the current user.
/// </summary>
public bool HasFavourited { get; set; }
/// <summary>
/// The availability of this beatmap set.
/// </summary>

View File

@ -247,7 +247,7 @@ namespace osu.Game.Beatmaps
// cancelling the beatmap load is safe for now since the retrieval is a synchronous
// operation. if we add an async retrieval method this may need to be reconsidered.
beatmapCancellation.Cancel();
beatmapCancellation?.Cancel();
total_count.Value--;
}

View File

@ -16,7 +16,7 @@ namespace osu.Game.Graphics.Backgrounds
/// </summary>
public class Background : CompositeDrawable
{
public Sprite Sprite;
public readonly Sprite Sprite;
private readonly string textureName;
@ -51,7 +51,7 @@ namespace osu.Game.Graphics.Backgrounds
/// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns>
public void BlurTo(Vector2 newBlurSigma, double duration = 0, Easing easing = Easing.None)
{
if (bufferedContainer == null)
if (bufferedContainer == null && newBlurSigma != Vector2.Zero)
{
RemoveInternal(Sprite);
@ -63,7 +63,7 @@ namespace osu.Game.Graphics.Backgrounds
});
}
bufferedContainer.BlurTo(newBlurSigma, duration, easing);
bufferedContainer?.BlurTo(newBlurSigma, duration, easing);
}
}
}

View File

@ -8,7 +8,6 @@ using osuTK.Graphics;
using System;
using osu.Framework.Graphics.Shaders;
using osu.Framework.Graphics.Textures;
using osuTK.Graphics.ES30;
using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Primitives;
using osu.Framework.Allocation;
@ -137,11 +136,13 @@ namespace osu.Game.Graphics.Backgrounds
}
}
protected int AimCount;
private void addTriangles(bool randomY)
{
int aimTriangleCount = (int)(DrawWidth * DrawHeight * 0.002f / (triangleScale * triangleScale) * SpawnRatio);
AimCount = (int)(DrawWidth * DrawHeight * 0.002f / (triangleScale * triangleScale) * SpawnRatio);
for (int i = 0; i < aimTriangleCount - parts.Count; i++)
for (int i = 0; i < AimCount - parts.Count; i++)
parts.Add(createTriangle(randomY));
}
@ -190,7 +191,7 @@ namespace osu.Game.Graphics.Backgrounds
private readonly List<TriangleParticle> parts = new List<TriangleParticle>();
private Vector2 size;
private readonly LinearBatch<TexturedVertex2D> vertexBatch = new LinearBatch<TexturedVertex2D>(100 * 3, 10, PrimitiveType.Triangles);
private TriangleBatch<TexturedVertex2D> vertexBatch;
public TrianglesDrawNode(Triangles source)
: base(source)
@ -213,6 +214,12 @@ namespace osu.Game.Graphics.Backgrounds
{
base.Draw(vertexAction);
if (Source.AimCount > 0 && (vertexBatch == null || vertexBatch.Size != Source.AimCount))
{
vertexBatch?.Dispose();
vertexBatch = new TriangleBatch<TexturedVertex2D>(Source.AimCount, 1);
}
shader.Bind();
Vector2 localInflationAmount = edge_smoothness * DrawInfo.MatrixInverse.ExtractScale().Xy;
@ -246,7 +253,7 @@ namespace osu.Game.Graphics.Backgrounds
{
base.Dispose(isDisposing);
vertexBatch.Dispose();
vertexBatch?.Dispose();
}
}

View File

@ -1,31 +1,26 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Configuration;
using osu.Game.Graphics.Backgrounds;
using osu.Game.Screens.Play;
using osuTK;
using osuTK.Graphics;
namespace osu.Game.Graphics.Containers
{
/// <summary>
/// A container that applies user-configured visual settings to its contents.
/// This container specifies behavior that applies to both Storyboards and Backgrounds.
/// </summary>
public class UserDimContainer : Container
public abstract class UserDimContainer : Container
{
private const float background_fade_duration = 800;
protected const float BACKGROUND_FADE_DURATION = 800;
/// <summary>
/// Whether or not user-configured dim levels should be applied to the container.
/// </summary>
public readonly Bindable<bool> EnableUserDim = new Bindable<bool>();
public readonly Bindable<bool> EnableUserDim = new Bindable<bool>(true);
/// <summary>
/// Whether or not the storyboard loaded should completely hide the background behind it.
@ -33,103 +28,58 @@ namespace osu.Game.Graphics.Containers
public readonly Bindable<bool> StoryboardReplacesBackground = new Bindable<bool>();
/// <summary>
/// The amount of blur to be applied to the background in addition to user-specified blur.
/// Whether the content of this container is currently being displayed.
/// </summary>
/// <remarks>
/// Used in contexts where there can potentially be both user and screen-specified blurring occuring at the same time, such as in <see cref="PlayerLoader"/>
/// </remarks>
public readonly Bindable<float> BlurAmount = new Bindable<float>();
public bool ContentDisplayed { get; private set; }
private Bindable<double> userDimLevel { get; set; }
protected Bindable<double> UserDimLevel { get; private set; }
private Bindable<double> userBlurLevel { get; set; }
protected Bindable<bool> ShowStoryboard { get; private set; }
private Bindable<bool> showStoryboard { get; set; }
protected override Container<Drawable> Content => dimContent;
protected Container DimContainer { get; }
protected override Container<Drawable> Content => DimContainer;
private readonly bool isStoryboard;
/// <summary>
/// As an optimisation, we add the two blur portions to be applied rather than actually applying two separate blurs.
/// </summary>
private Vector2 blurTarget => EnableUserDim.Value
? new Vector2(BlurAmount.Value + (float)userBlurLevel.Value * 25)
: new Vector2(BlurAmount.Value);
private Container dimContent { get; }
/// <summary>
/// Creates a new <see cref="UserDimContainer"/>.
/// </summary>
/// <param name="isStoryboard"> Whether or not this instance contains a storyboard.
/// <remarks>
/// While both backgrounds and storyboards allow user dim levels to be applied, storyboards can be toggled via <see cref="showStoryboard"/>
/// and can cause backgrounds to become hidden via <see cref="StoryboardReplacesBackground"/>. Storyboards are also currently unable to be blurred.
/// </remarks>
/// </param>
public UserDimContainer(bool isStoryboard = false)
protected UserDimContainer()
{
this.isStoryboard = isStoryboard;
AddInternal(DimContainer = new Container { RelativeSizeAxes = Axes.Both });
}
private Background background;
public Background Background
{
get => background;
set
{
base.Add(background = value);
background.BlurTo(blurTarget, 0, Easing.OutQuint);
}
}
public override void Add(Drawable drawable)
{
if (drawable is Background)
throw new InvalidOperationException($"Use {nameof(Background)} to set a background.");
base.Add(drawable);
AddInternal(dimContent = new Container { RelativeSizeAxes = Axes.Both });
}
[BackgroundDependencyLoader]
private void load(OsuConfigManager config)
{
userDimLevel = config.GetBindable<double>(OsuSetting.DimLevel);
userBlurLevel = config.GetBindable<double>(OsuSetting.BlurLevel);
showStoryboard = config.GetBindable<bool>(OsuSetting.ShowStoryboard);
UserDimLevel = config.GetBindable<double>(OsuSetting.DimLevel);
ShowStoryboard = config.GetBindable<bool>(OsuSetting.ShowStoryboard);
EnableUserDim.ValueChanged += _ => updateVisuals();
userDimLevel.ValueChanged += _ => updateVisuals();
userBlurLevel.ValueChanged += _ => updateVisuals();
showStoryboard.ValueChanged += _ => updateVisuals();
StoryboardReplacesBackground.ValueChanged += _ => updateVisuals();
BlurAmount.ValueChanged += _ => updateVisuals();
EnableUserDim.ValueChanged += _ => UpdateVisuals();
UserDimLevel.ValueChanged += _ => UpdateVisuals();
ShowStoryboard.ValueChanged += _ => UpdateVisuals();
StoryboardReplacesBackground.ValueChanged += _ => UpdateVisuals();
}
protected override void LoadComplete()
{
base.LoadComplete();
updateVisuals();
UpdateVisuals();
}
private void updateVisuals()
/// <summary>
/// Whether the content of this container should currently be visible.
/// </summary>
protected virtual bool ShowDimContent => true;
/// <summary>
/// Should be invoked when any dependent dim level or user setting is changed and bring the visual state up-to-date.
/// </summary>
protected virtual void UpdateVisuals()
{
if (isStoryboard)
{
DimContainer.FadeTo(!showStoryboard.Value || userDimLevel.Value == 1 ? 0 : 1, background_fade_duration, Easing.OutQuint);
}
else
{
// The background needs to be hidden in the case of it being replaced by the storyboard
DimContainer.FadeTo(showStoryboard.Value && StoryboardReplacesBackground.Value ? 0 : 1, background_fade_duration, Easing.OutQuint);
ContentDisplayed = ShowDimContent;
Background?.BlurTo(blurTarget, background_fade_duration, Easing.OutQuint);
}
DimContainer.FadeColour(EnableUserDim.Value ? OsuColour.Gray(1 - (float)userDimLevel.Value) : Color4.White, background_fade_duration, Easing.OutQuint);
dimContent.FadeTo((ContentDisplayed) ? 1 : 0, BACKGROUND_FADE_DURATION, Easing.OutQuint);
dimContent.FadeColour(EnableUserDim.Value ? OsuColour.Gray(1 - (float)UserDimLevel.Value) : Color4.White, BACKGROUND_FADE_DURATION, Easing.OutQuint);
}
}
}

View File

@ -7,21 +7,20 @@ using osu.Game.Online.API.Requests.Responses;
namespace osu.Game.Online.API.Requests
{
public class GetUserBeatmapsRequest : APIRequest<List<APIBeatmapSet>>
public class GetUserBeatmapsRequest : PaginatedAPIRequest<List<APIBeatmapSet>>
{
private readonly long userId;
private readonly int offset;
private readonly BeatmapSetType type;
public GetUserBeatmapsRequest(long userId, BeatmapSetType type, int offset = 0)
public GetUserBeatmapsRequest(long userId, BeatmapSetType type, int page = 0, int itemsPerPage = 6)
: base(page, itemsPerPage)
{
this.userId = userId;
this.offset = offset;
this.type = type;
}
// ReSharper disable once ImpureMethodCallOnReadonlyValueField
protected override string Target => $@"users/{userId}/beatmapsets/{type.ToString().Underscore()}?offset={offset}";
protected override string Target => $@"users/{userId}/beatmapsets/{type.ToString().Underscore()}";
}
public enum BeatmapSetType

View File

@ -6,17 +6,16 @@ using osu.Game.Online.API.Requests.Responses;
namespace osu.Game.Online.API.Requests
{
public class GetUserMostPlayedBeatmapsRequest : APIRequest<List<APIUserMostPlayedBeatmap>>
public class GetUserMostPlayedBeatmapsRequest : PaginatedAPIRequest<List<APIUserMostPlayedBeatmap>>
{
private readonly long userId;
private readonly int offset;
public GetUserMostPlayedBeatmapsRequest(long userId, int offset = 0)
public GetUserMostPlayedBeatmapsRequest(long userId, int page = 0, int itemsPerPage = 5)
: base(page, itemsPerPage)
{
this.userId = userId;
this.offset = offset;
}
protected override string Target => $@"users/{userId}/beatmapsets/most_played?offset={offset}";
protected override string Target => $@"users/{userId}/beatmapsets/most_played";
}
}

View File

@ -6,18 +6,17 @@ using osu.Game.Online.API.Requests.Responses;
namespace osu.Game.Online.API.Requests
{
public class GetUserRecentActivitiesRequest : APIRequest<List<APIRecentActivity>>
public class GetUserRecentActivitiesRequest : PaginatedAPIRequest<List<APIRecentActivity>>
{
private readonly long userId;
private readonly int offset;
public GetUserRecentActivitiesRequest(long userId, int offset = 0)
public GetUserRecentActivitiesRequest(long userId, int page = 0, int itemsPerPage = 5)
: base(page, itemsPerPage)
{
this.userId = userId;
this.offset = offset;
}
protected override string Target => $"users/{userId}/recent_activity?offset={offset}";
protected override string Target => $"users/{userId}/recent_activity";
}
public enum RecentActivityType

View File

@ -6,21 +6,19 @@ using osu.Game.Online.API.Requests.Responses;
namespace osu.Game.Online.API.Requests
{
public class GetUserScoresRequest : APIRequest<List<APILegacyScoreInfo>>
public class GetUserScoresRequest : PaginatedAPIRequest<List<APILegacyScoreInfo>>
{
private readonly long userId;
private readonly ScoreType type;
private readonly int offset;
public GetUserScoresRequest(long userId, ScoreType type, int offset = 0)
public GetUserScoresRequest(long userId, ScoreType type, int page = 0, int itemsPerPage = 5)
: base(page, itemsPerPage)
{
this.userId = userId;
this.type = type;
this.offset = offset;
}
// ReSharper disable once ImpureMethodCallOnReadonlyValueField
protected override string Target => $@"users/{userId}/scores/{type.ToString().ToLowerInvariant()}?offset={offset}";
protected override string Target => $@"users/{userId}/scores/{type.ToString().ToLowerInvariant()}";
}
public enum ScoreType

View File

@ -0,0 +1,30 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System.Globalization;
using osu.Framework.IO.Network;
namespace osu.Game.Online.API.Requests
{
public abstract class PaginatedAPIRequest<T> : APIRequest<T>
{
private readonly int page;
private readonly int itemsPerPage;
protected PaginatedAPIRequest(int page, int itemsPerPage)
{
this.page = page;
this.itemsPerPage = itemsPerPage;
}
protected override WebRequest CreateWebRequest()
{
var req = base.CreateWebRequest();
req.AddParameter("offset", (page * itemsPerPage).ToString(CultureInfo.InvariantCulture));
req.AddParameter("limit", itemsPerPage.ToString(CultureInfo.InvariantCulture));
return req;
}
}
}

View File

@ -30,6 +30,9 @@ namespace osu.Game.Online.API.Requests.Responses
[JsonProperty(@"preview_url")]
private string preview { get; set; }
[JsonProperty(@"has_favourited")]
private bool hasFavourited { get; set; }
[JsonProperty(@"play_count")]
private int playCount { get; set; }
@ -91,6 +94,7 @@ namespace osu.Game.Online.API.Requests.Responses
Ranked = ranked,
LastUpdated = lastUpdated,
Availability = availability,
HasFavourited = hasFavourited,
},
Beatmaps = beatmaps?.Select(b => b.ToBeatmap(rulesets)).ToList(),
};

View File

@ -51,7 +51,6 @@ namespace osu.Game.Online.Leaderboards
loading.Hide();
// schedule because we may not be loaded yet (LoadComponentAsync complains).
showScoresDelegate?.Cancel();
showScoresCancellationSource?.Cancel();
@ -61,28 +60,22 @@ namespace osu.Game.Online.Leaderboards
// ensure placeholder is hidden when displaying scores
PlaceholderState = PlaceholderState.Successful;
scrollFlow = CreateScoreFlow();
scrollFlow.ChildrenEnumerable = scores.Select((s, index) => CreateDrawableScore(s, index + 1));
var sf = CreateScoreFlow();
sf.ChildrenEnumerable = scores.Select((s, index) => CreateDrawableScore(s, index + 1));
if (!IsLoaded)
showScoresDelegate = Schedule(showScores);
else
showScores();
void showScores() => LoadComponentAsync(scrollFlow, _ =>
// schedule because we may not be loaded yet (LoadComponentAsync complains).
showScoresDelegate = Schedule(() => LoadComponentAsync(sf, _ =>
{
scrollContainer.Add(scrollFlow);
scrollContainer.Add(scrollFlow = sf);
int i = 0;
foreach (var s in scrollFlow.Children)
{
using (s.BeginDelayedSequence(i++ * 50, true))
s.Show();
}
scrollContainer.ScrollTo(0f, false);
}, (showScoresCancellationSource = new CancellationTokenSource()).Token);
}, (showScoresCancellationSource = new CancellationTokenSource()).Token));
}
}
@ -201,13 +194,17 @@ namespace osu.Game.Online.Leaderboards
private APIRequest getScoresRequest;
protected abstract bool IsOnlineScope { get; }
public void APIStateChanged(IAPIProvider api, APIState state)
{
switch (state)
{
case APIState.Online:
case APIState.Offline:
UpdateScores();
if (IsOnlineScope)
UpdateScores();
break;
}
}

View File

@ -249,7 +249,7 @@ namespace osu.Game
}
// Use first beatmap available for current ruleset, else switch ruleset.
var first = databasedSet.Beatmaps.Find(b => b.Ruleset == Ruleset.Value) ?? databasedSet.Beatmaps.First();
var first = databasedSet.Beatmaps.Find(b => b.Ruleset.Equals(Ruleset.Value)) ?? databasedSet.Beatmaps.First();
Ruleset.Value = first.Ruleset;
Beatmap.Value = BeatmapManager.GetWorkingBeatmap(first);

View File

@ -7,6 +7,7 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Game.Beatmaps;
using osu.Game.Graphics;
using osu.Game.Graphics.Backgrounds;
using osuTK;
@ -15,7 +16,9 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons
{
public class FavouriteButton : HeaderButton
{
public readonly Bindable<bool> Favourited = new Bindable<bool>();
public readonly Bindable<BeatmapSetInfo> BeatmapSet = new Bindable<BeatmapSetInfo>();
private readonly Bindable<bool> favourited = new Bindable<bool>();
[BackgroundDependencyLoader]
private void load()
@ -54,7 +57,15 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons
},
});
Favourited.ValueChanged += favourited =>
BeatmapSet.BindValueChanged(setInfo =>
{
if (setInfo.NewValue?.OnlineInfo?.HasFavourited == null)
return;
favourited.Value = setInfo.NewValue.OnlineInfo.HasFavourited;
});
favourited.ValueChanged += favourited =>
{
if (favourited.NewValue)
{
@ -67,8 +78,6 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons
icon.Icon = FontAwesome.Regular.Heart;
}
};
Action = () => Favourited.Value = !Favourited.Value;
}
protected override void UpdateAfterChildren()

View File

@ -161,7 +161,10 @@ namespace osu.Game.Overlays.BeatmapSet
Margin = new MarginPadding { Top = 10 },
Children = new Drawable[]
{
favouriteButton = new FavouriteButton(),
favouriteButton = new FavouriteButton
{
BeatmapSet = { BindTarget = BeatmapSet }
},
downloadButtonsContainer = new FillFlowContainer
{
RelativeSizeAxes = Axes.Both,

View File

@ -19,7 +19,6 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
public class ScoresContainer : CompositeDrawable
{
private const int spacing = 15;
private const int fade_duration = 200;
private readonly Box background;
private readonly ScoreTable scoreTable;
@ -53,8 +52,6 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
{
Schedule(() =>
{
loading = false;
topScoresContainer.Clear();
if (value?.Scores.Any() != true)
@ -128,11 +125,6 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
background.Colour = colours.Gray2;
}
private bool loading
{
set => loadingAnimation.FadeTo(value ? 1 : 0, fade_duration);
}
private void getScores(BeatmapInfo beatmap)
{
getScoresRequest?.Cancel();
@ -141,15 +133,16 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
Scores = null;
if (beatmap?.OnlineBeatmapID.HasValue != true)
{
loading = false;
return;
}
loadingAnimation.Show();
getScoresRequest = new GetScoresRequest(beatmap, beatmap.Ruleset);
getScoresRequest.Success += scores => Scores = scores;
getScoresRequest.Success += scores =>
{
loadingAnimation.Hide();
Scores = scores;
};
api.Queue(getScoresRequest);
loading = true;
}
}
}

View File

@ -62,7 +62,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
},
}
},
avatar = new UpdateableAvatar(hideImmediately: true)
avatar = new UpdateableAvatar
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
@ -99,7 +99,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
Origin = Anchor.CentreLeft,
Font = OsuFont.GetFont(size: 15, weight: FontWeight.Bold)
},
flag = new UpdateableFlag(hideImmediately: true)
flag = new UpdateableFlag
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,

View File

@ -26,8 +26,13 @@ namespace osu.Game.Overlays.Direct
TabContainer.Masking = false;
TabContainer.Spacing = new Vector2(10, 0);
AutoSizeAxes = Axes.Both;
}
Current.DisabledChanged += value => SelectedTab.FadeColour(value ? Color4.DarkGray : Color4.White, 200, Easing.OutQuint);
protected override void LoadComplete()
{
base.LoadComplete();
Current.BindDisabledChanged(value => SelectedTab.FadeColour(value ? Color4.DarkGray : Color4.White, 200, Easing.OutQuint), true);
}
protected override TabItem<RulesetInfo> CreateTabItem(RulesetInfo value) => new DirectRulesetTabItem(value);

View File

@ -29,7 +29,7 @@ namespace osu.Game.Overlays.Profile.Sections.Beatmaps
protected override void ShowMore()
{
request = new GetUserBeatmapsRequest(User.Value.Id, type, VisiblePages++ * ItemsPerPage);
request = new GetUserBeatmapsRequest(User.Value.Id, type, VisiblePages++, ItemsPerPage);
request.Success += sets => Schedule(() =>
{
MoreButton.FadeTo(sets.Count == ItemsPerPage ? 1 : 0);

View File

@ -24,7 +24,7 @@ namespace osu.Game.Overlays.Profile.Sections.Historical
protected override void ShowMore()
{
request = new GetUserMostPlayedBeatmapsRequest(User.Value.Id, VisiblePages++ * ItemsPerPage);
request = new GetUserMostPlayedBeatmapsRequest(User.Value.Id, VisiblePages++, ItemsPerPage);
request.Success += beatmaps => Schedule(() =>
{
MoreButton.FadeTo(beatmaps.Count == ItemsPerPage ? 1 : 0);

View File

@ -31,7 +31,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks
protected override void ShowMore()
{
request = new GetUserScoresRequest(User.Value.Id, type, VisiblePages++ * ItemsPerPage);
request = new GetUserScoresRequest(User.Value.Id, type, VisiblePages++, ItemsPerPage);
request.Success += scores => Schedule(() =>
{
foreach (var s in scores)

View File

@ -22,7 +22,7 @@ namespace osu.Game.Overlays.Profile.Sections.Recent
protected override void ShowMore()
{
request = new GetUserRecentActivitiesRequest(User.Value.Id, VisiblePages++ * ItemsPerPage);
request = new GetUserRecentActivitiesRequest(User.Value.Id, VisiblePages++, ItemsPerPage);
request.Success += activities => Schedule(() =>
{
MoreButton.FadeTo(activities.Count == ItemsPerPage ? 1 : 0);

View File

@ -73,7 +73,7 @@ namespace osu.Game.Overlays.Toolbar
{
foreach (var tabItem in TabContainer)
{
if (tabItem.Value == Current.Value)
if (tabItem.Value.Equals(Current.Value))
{
ModeButtonLine.MoveToX(tabItem.DrawPosition.X, !hasInitialPosition ? 0 : 200, Easing.OutQuint);
break;

View File

@ -7,7 +7,6 @@ using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Extensions.TypeExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Primitives;
using osu.Game.Audio;
using osu.Game.Graphics;
@ -179,6 +178,39 @@ namespace osu.Game.Rulesets.Objects.Drawables
UpdateResult(false);
}
private double? lifetimeStart;
public override double LifetimeStart
{
get => lifetimeStart ?? (HitObject.StartTime - InitialLifetimeOffset);
set
{
base.LifetimeStart = value;
lifetimeStart = value;
}
}
/// <summary>
/// A safe offset prior to the start time of <see cref="HitObject"/> at which this <see cref="DrawableHitObject"/> may begin displaying contents.
/// By default, <see cref="DrawableHitObject"/>s are assumed to display their contents within 10 seconds prior to the start time of <see cref="HitObject"/>.
/// </summary>
/// <remarks>
/// This is only used as an optimisation to delay the initial update of this <see cref="DrawableHitObject"/> and may be tuned more aggressively if required.
/// A more accurate <see cref="LifetimeStart"/> should be set inside <see cref="UpdateState"/> for an <see cref="ArmedState.Idle"/> state.
/// </remarks>
protected virtual double InitialLifetimeOffset => 10000;
/// <summary>
/// Will be called at least once after this <see cref="DrawableHitObject"/> has become not alive.
/// </summary>
public virtual void OnKilled()
{
foreach (var nested in NestedHitObjects)
nested.OnKilled();
UpdateResult(false);
}
protected virtual void AddNested(DrawableHitObject h)
{
h.OnNewResult += (d, r) => OnNewResult?.Invoke(d, r);
@ -223,16 +255,6 @@ namespace osu.Game.Rulesets.Objects.Drawables
OnNewResult?.Invoke(this, Result);
}
/// <summary>
/// Will called at least once after the <see cref="Drawable.LifetimeEnd"/> of this <see cref="DrawableHitObject"/> has been passed.
/// </summary>
internal void OnLifetimeEnd()
{
foreach (var nested in NestedHitObjects)
nested.OnLifetimeEnd();
UpdateResult(false);
}
/// <summary>
/// Processes this <see cref="DrawableHitObject"/>, checking if a scoring result has occurred.
/// </summary>

View File

@ -37,7 +37,8 @@ namespace osu.Game.Rulesets.Objects.Legacy.Catch
};
}
protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double length, PathType pathType, int repeatCount, List<List<HitSampleInfo>> nodeSamples)
protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double? length, PathType pathType, int repeatCount,
List<List<HitSampleInfo>> nodeSamples)
{
newCombo |= forceNewCombo;
comboOffset += extraComboOffset;

View File

@ -72,7 +72,7 @@ namespace osu.Game.Rulesets.Objects.Legacy
else if (type.HasFlag(ConvertHitObjectType.Slider))
{
PathType pathType = PathType.Catmull;
double length = 0;
double? length = null;
string[] pointSplit = split[5].Split('|');
@ -130,7 +130,11 @@ namespace osu.Game.Rulesets.Objects.Legacy
repeatCount = Math.Max(0, repeatCount - 1);
if (split.Length > 7)
{
length = Math.Max(0, Parsing.ParseDouble(split[7]));
if (length == 0)
length = null;
}
if (split.Length > 10)
readCustomSampleBanks(split[10], bankInfo);
@ -291,7 +295,8 @@ namespace osu.Game.Rulesets.Objects.Legacy
/// <param name="repeatCount">The slider repeat count.</param>
/// <param name="nodeSamples">The samples to be played when the slider nodes are hit. This includes the head and tail of the slider.</param>
/// <returns>The hit object.</returns>
protected abstract HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double length, PathType pathType, int repeatCount, List<List<HitSampleInfo>> nodeSamples);
protected abstract HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double? length, PathType pathType, int repeatCount,
List<List<HitSampleInfo>> nodeSamples);
/// <summary>
/// Creates a legacy Spinner-type hit object.

View File

@ -26,7 +26,8 @@ namespace osu.Game.Rulesets.Objects.Legacy.Mania
};
}
protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double length, PathType pathType, int repeatCount, List<List<HitSampleInfo>> nodeSamples)
protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double? length, PathType pathType, int repeatCount,
List<List<HitSampleInfo>> nodeSamples)
{
return new ConvertSlider
{

View File

@ -1,7 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System;
using osuTK;
using osu.Game.Rulesets.Objects.Types;
using System.Collections.Generic;
@ -38,7 +37,8 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu
};
}
protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double length, PathType pathType, int repeatCount, List<List<HitSampleInfo>> nodeSamples)
protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double? length, PathType pathType, int repeatCount,
List<List<HitSampleInfo>> nodeSamples)
{
newCombo |= forceNewCombo;
comboOffset += extraComboOffset;
@ -51,7 +51,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu
Position = position,
NewCombo = FirstObject || newCombo,
ComboOffset = comboOffset,
Path = new SliderPath(pathType, controlPoints, Math.Max(0, length)),
Path = new SliderPath(pathType, controlPoints, length),
NodeSamples = nodeSamples,
RepeatCount = repeatCount
};

View File

@ -23,7 +23,8 @@ namespace osu.Game.Rulesets.Objects.Legacy.Taiko
return new ConvertHit();
}
protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double length, PathType pathType, int repeatCount, List<List<HitSampleInfo>> nodeSamples)
protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double? length, PathType pathType, int repeatCount,
List<List<HitSampleInfo>> nodeSamples)
{
return new ConvertSlider
{

View File

@ -2,6 +2,7 @@
// See the LICENCE file in the repository root for full licence text.
using System;
using System.Diagnostics.CodeAnalysis;
using Newtonsoft.Json;
namespace osu.Game.Rulesets
@ -23,6 +24,21 @@ namespace osu.Game.Rulesets
public bool Equals(RulesetInfo other) => other != null && ID == other.ID && Available == other.Available && Name == other.Name && InstantiationInfo == other.InstantiationInfo;
public override bool Equals(object obj) => obj is RulesetInfo rulesetInfo && Equals(rulesetInfo);
[SuppressMessage("ReSharper", "NonReadonlyMemberInGetHashCode")]
public override int GetHashCode()
{
unchecked
{
var hashCode = ID.HasValue ? ID.GetHashCode() : 0;
hashCode = (hashCode * 397) ^ (InstantiationInfo != null ? InstantiationInfo.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ (Name != null ? Name.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ Available.GetHashCode();
return hashCode;
}
}
public override string ToString() => $"{Name} ({ShortName}) ID: {ID}";
}
}

View File

@ -32,7 +32,7 @@ namespace osu.Game.Rulesets
public RulesetStore(IDatabaseContextFactory factory)
: base(factory)
{
AddMissingRulesets();
addMissingRulesets();
}
/// <summary>
@ -52,13 +52,13 @@ namespace osu.Game.Rulesets
/// <summary>
/// All available rulesets.
/// </summary>
public IEnumerable<RulesetInfo> AvailableRulesets;
public IEnumerable<RulesetInfo> AvailableRulesets { get; private set; }
private static Assembly currentDomain_AssemblyResolve(object sender, ResolveEventArgs args) => loaded_assemblies.Keys.FirstOrDefault(a => a.FullName == args.Name);
private const string ruleset_library_prefix = "osu.Game.Rulesets";
protected void AddMissingRulesets()
private void addMissingRulesets()
{
using (var usage = ContextFactory.GetForWrite())
{

View File

@ -34,8 +34,14 @@ namespace osu.Game.Rulesets.UI
protected override void OnChildLifetimeBoundaryCrossed(LifetimeBoundaryCrossedEvent e)
{
if (e.Kind == LifetimeBoundaryKind.End && e.Direction == LifetimeBoundaryCrossingDirection.Forward && e.Child is DrawableHitObject hitObject)
hitObject.OnLifetimeEnd();
if (!(e.Child is DrawableHitObject hitObject))
return;
if ((e.Kind == LifetimeBoundaryKind.End && e.Direction == LifetimeBoundaryCrossingDirection.Forward)
|| (e.Kind == LifetimeBoundaryKind.Start && e.Direction == LifetimeBoundaryCrossingDirection.Backward))
{
hitObject.OnKilled();
}
}
}
}

View File

@ -1,19 +1,28 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System;
using System.Threading;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Textures;
using osu.Game.Beatmaps;
using osu.Game.Configuration;
using osu.Game.Graphics.Backgrounds;
using osu.Game.Graphics.Containers;
using osu.Game.Screens.Play;
using osuTK;
namespace osu.Game.Screens.Backgrounds
{
public class BackgroundScreenBeatmap : BackgroundScreen
{
/// <summary>
/// The amount of blur to apply when full user blur is requested.
/// </summary>
public const float USER_BLUR_FACTOR = 25;
protected Background Background;
private WorkingBeatmap beatmap;
@ -30,16 +39,17 @@ namespace osu.Game.Screens.Backgrounds
/// </summary>
public readonly Bindable<float> BlurAmount = new Bindable<float>();
private readonly UserDimContainer fadeContainer;
private readonly DimmableBackground dimmable;
protected virtual UserDimContainer CreateFadeContainer() => new UserDimContainer { RelativeSizeAxes = Axes.Both };
protected virtual DimmableBackground CreateFadeContainer() => new DimmableBackground { RelativeSizeAxes = Axes.Both };
public BackgroundScreenBeatmap(WorkingBeatmap beatmap = null)
{
Beatmap = beatmap;
InternalChild = fadeContainer = CreateFadeContainer();
fadeContainer.EnableUserDim.BindTo(EnableUserDim);
fadeContainer.BlurAmount.BindTo(BlurAmount);
InternalChild = dimmable = CreateFadeContainer();
dimmable.EnableUserDim.BindTo(EnableUserDim);
dimmable.BlurAmount.BindTo(BlurAmount);
}
[BackgroundDependencyLoader]
@ -86,8 +96,8 @@ namespace osu.Game.Screens.Backgrounds
}
b.Depth = newDepth;
fadeContainer.Background = Background = b;
StoryboardReplacesBackground.BindTo(fadeContainer.StoryboardReplacesBackground);
dimmable.Background = Background = b;
StoryboardReplacesBackground.BindTo(dimmable.StoryboardReplacesBackground);
}
public override bool Equals(BackgroundScreen other)
@ -112,5 +122,70 @@ namespace osu.Game.Screens.Backgrounds
Sprite.Texture = Beatmap?.Background ?? textures.Get(@"Backgrounds/bg1");
}
}
public class DimmableBackground : UserDimContainer
{
/// <summary>
/// The amount of blur to be applied to the background in addition to user-specified blur.
/// </summary>
/// <remarks>
/// Used in contexts where there can potentially be both user and screen-specified blurring occuring at the same time, such as in <see cref="PlayerLoader"/>
/// </remarks>
public readonly Bindable<float> BlurAmount = new Bindable<float>();
public Background Background
{
get => background;
set
{
background?.Expire();
base.Add(background = value);
background.BlurTo(blurTarget, 0, Easing.OutQuint);
}
}
private Bindable<double> userBlurLevel { get; set; }
private Background background;
public override void Add(Drawable drawable)
{
if (drawable is Background)
throw new InvalidOperationException($"Use {nameof(Background)} to set a background.");
base.Add(drawable);
}
/// <summary>
/// As an optimisation, we add the two blur portions to be applied rather than actually applying two separate blurs.
/// </summary>
private Vector2 blurTarget => EnableUserDim.Value
? new Vector2(BlurAmount.Value + (float)userBlurLevel.Value * USER_BLUR_FACTOR)
: new Vector2(BlurAmount.Value);
[BackgroundDependencyLoader]
private void load(OsuConfigManager config)
{
userBlurLevel = config.GetBindable<double>(OsuSetting.BlurLevel);
}
protected override void LoadComplete()
{
base.LoadComplete();
userBlurLevel.ValueChanged += _ => UpdateVisuals();
BlurAmount.ValueChanged += _ => UpdateVisuals();
}
protected override bool ShowDimContent => !ShowStoryboard.Value || !StoryboardReplacesBackground.Value; // The background needs to be hidden in the case of it being replaced by the storyboard
protected override void UpdateVisuals()
{
base.UpdateVisuals();
Background?.BlurTo(blurTarget, BACKGROUND_FADE_DURATION, Easing.OutQuint);
}
}
}
}

View File

@ -33,6 +33,8 @@ namespace osu.Game.Screens.Multi.Match.Components
}, true);
}
protected override bool IsOnlineScope => true;
protected override APIRequest FetchScores(Action<IEnumerable<APIRoomScoreInfo>> scoresCallback)
{
if (roomId.Value == null)

View File

@ -0,0 +1,55 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Allocation;
using osu.Game.Graphics.Containers;
using osu.Game.Storyboards;
using osu.Game.Storyboards.Drawables;
namespace osu.Game.Screens.Play
{
/// <summary>
/// A container that handles <see cref="Storyboard"/> loading, as well as applies user-specified visual settings to it.
/// </summary>
public class DimmableStoryboard : UserDimContainer
{
private readonly Storyboard storyboard;
private DrawableStoryboard drawableStoryboard;
public DimmableStoryboard(Storyboard storyboard)
{
this.storyboard = storyboard;
}
[BackgroundDependencyLoader]
private void load()
{
initializeStoryboard(false);
}
protected override void LoadComplete()
{
ShowStoryboard.BindValueChanged(_ => initializeStoryboard(true), true);
base.LoadComplete();
}
protected override bool ShowDimContent => ShowStoryboard.Value && UserDimLevel.Value < 1;
private void initializeStoryboard(bool async)
{
if (drawableStoryboard != null)
return;
if (!ShowStoryboard.Value)
return;
drawableStoryboard = storyboard.CreateDrawable();
drawableStoryboard.Masking = true;
if (async)
LoadComponentAsync(drawableStoryboard, Add);
else
Add(drawableStoryboard);
}
}
}

View File

@ -26,7 +26,6 @@ using osu.Game.Rulesets.UI;
using osu.Game.Scoring;
using osu.Game.Screens.Ranking;
using osu.Game.Skinning;
using osu.Game.Storyboards.Drawables;
using osu.Game.Users;
namespace osu.Game.Screens.Play
@ -76,6 +75,8 @@ namespace osu.Game.Screens.Play
protected GameplayClockContainer GameplayClockContainer { get; private set; }
protected DimmableStoryboard DimmableStoryboard { get; private set; }
[Cached]
[Cached(Type = typeof(IBindable<IReadOnlyList<Mod>>))]
protected new readonly Bindable<IReadOnlyList<Mod>> Mods = new Bindable<IReadOnlyList<Mod>>(Array.Empty<Mod>());
@ -109,7 +110,6 @@ namespace osu.Game.Screens.Play
sampleRestart = audio.Samples.Get(@"Gameplay/restart");
mouseWheelDisabled = config.GetBindable<bool>(OsuSetting.MouseDisableWheel);
showStoryboard = config.GetBindable<bool>(OsuSetting.ShowStoryboard);
ScoreProcessor = DrawableRuleset.CreateScoreProcessor();
ScoreProcessor.Mods.BindTo(Mods);
@ -121,7 +121,7 @@ namespace osu.Game.Screens.Play
GameplayClockContainer.Children = new[]
{
StoryboardContainer = CreateStoryboardContainer(),
DimmableStoryboard = new DimmableStoryboard(Beatmap.Value.Storyboard) { RelativeSizeAxes = Axes.Both },
new ScalingContainer(ScalingMode.Gameplay)
{
Child = new LocalSkinOverrideContainer(working.Skin)
@ -199,9 +199,6 @@ namespace osu.Game.Screens.Play
// bind clock into components that require it
DrawableRuleset.IsPaused.BindTo(GameplayClockContainer.IsPaused);
// load storyboard as part of player's load if we can
initializeStoryboard(false);
// Bind ScoreProcessor to ourselves
ScoreProcessor.AllJudged += onCompletion;
ScoreProcessor.Failed += onFail;
@ -334,41 +331,6 @@ namespace osu.Game.Screens.Play
protected virtual Results CreateResults(ScoreInfo score) => new SoloResults(score);
#region Storyboard
private DrawableStoryboard storyboard;
protected UserDimContainer StoryboardContainer { get; private set; }
protected virtual UserDimContainer CreateStoryboardContainer() => new UserDimContainer(true)
{
RelativeSizeAxes = Axes.Both,
Alpha = 1,
EnableUserDim = { Value = true }
};
private Bindable<bool> showStoryboard;
private void initializeStoryboard(bool asyncLoad)
{
if (StoryboardContainer == null || storyboard != null)
return;
if (!showStoryboard.Value)
return;
var beatmap = Beatmap.Value;
storyboard = beatmap.Storyboard.CreateDrawable();
storyboard.Masking = true;
if (asyncLoad)
LoadComponentAsync(storyboard, StoryboardContainer.Add);
else
StoryboardContainer.Add(storyboard);
}
#endregion
#region Fail Logic
protected FailOverlay FailOverlay { get; private set; }
@ -486,13 +448,11 @@ namespace osu.Game.Screens.Play
.Delay(250)
.FadeIn(250);
showStoryboard.ValueChanged += _ => initializeStoryboard(true);
Background.EnableUserDim.Value = true;
Background.BlurAmount.Value = 0;
Background.StoryboardReplacesBackground.BindTo(storyboardReplacesBackground);
StoryboardContainer.StoryboardReplacesBackground.BindTo(storyboardReplacesBackground);
DimmableStoryboard.StoryboardReplacesBackground.BindTo(storyboardReplacesBackground);
storyboardReplacesBackground.Value = Beatmap.Value.Storyboard.ReplacesBackground && Beatmap.Value.Storyboard.HasDrawable;

View File

@ -161,6 +161,8 @@ namespace osu.Game.Screens.Play
private Visibility state;
private ScheduledDelegate scheduledHide;
public override bool IsPresent => true;
public Visibility State
{
get => state;
@ -201,14 +203,15 @@ namespace osu.Game.Screens.Play
protected override bool OnMouseDown(MouseDownEvent e)
{
Show();
scheduledHide?.Cancel();
return base.OnMouseDown(e);
return true;
}
protected override bool OnMouseUp(MouseUpEvent e)
{
Show();
return base.OnMouseUp(e);
return true;
}
public override void Hide() => State = Visibility.Hidden;

View File

@ -256,9 +256,12 @@ namespace osu.Game.Screens.Ranking
}
};
foreach (var t in CreateResultPages())
modeChangeButtons.AddItem(t);
modeChangeButtons.Current.Value = modeChangeButtons.Items.FirstOrDefault();
var pages = CreateResultPages();
foreach (var p in pages)
modeChangeButtons.AddItem(p);
modeChangeButtons.Current.Value = pages.FirstOrDefault();
modeChangeButtons.Current.BindValueChanged(page =>
{

View File

@ -120,7 +120,8 @@ namespace osu.Game.Screens.Select
RelativeSizeAxes = Axes.X,
Height = 24,
Width = 0.5f,
AutoSort = true
AutoSort = true,
Current = { Value = GroupMode.Title }
},
//spriteText = new OsuSpriteText
//{
@ -139,6 +140,7 @@ namespace osu.Game.Screens.Select
Width = 0.5f,
Height = 24,
AutoSort = true,
Current = { Value = SortMode.Title }
}
}
},

View File

@ -9,18 +9,25 @@ using osu.Game.Rulesets.Mods;
using System.Collections.Generic;
using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics.UserInterface;
using osu.Game.Graphics;
using osuTK;
using osuTK.Input;
namespace osu.Game.Screens.Select
{
public class FooterButtonMods : FooterButton
public class FooterButtonMods : FooterButton, IHasCurrentValue<IReadOnlyList<Mod>>
{
public FooterButtonMods(Bindable<IReadOnlyList<Mod>> mods)
public Bindable<IReadOnlyList<Mod>> Current
{
FooterModDisplay modDisplay;
get => modDisplay.Current;
set => modDisplay.Current = value;
}
private readonly FooterModDisplay modDisplay;
public FooterButtonMods()
{
Add(new Container
{
Anchor = Anchor.CentreLeft,
@ -33,9 +40,6 @@ namespace osu.Game.Screens.Select
AutoSizeAxes = Axes.Both,
Margin = new MarginPadding { Left = 70 }
});
if (mods != null)
modDisplay.Current = mods;
}
[BackgroundDependencyLoader]

View File

@ -79,6 +79,8 @@ namespace osu.Game.Screens.Select.Leaderboards
};
}
protected override bool IsOnlineScope => Scope != BeatmapLeaderboardScope.Local;
protected override APIRequest FetchScores(Action<IEnumerable<ScoreInfo>> scoresCallback)
{
if (Scope == BeatmapLeaderboardScope.Local)

View File

@ -221,11 +221,9 @@ namespace osu.Game.Screens.Select
[BackgroundDependencyLoader(true)]
private void load(BeatmapManager beatmaps, AudioManager audio, DialogOverlay dialog, OsuColour colours, SkinManager skins, ScoreManager scores)
{
mods.BindTo(Mods);
if (Footer != null)
{
Footer.AddButton(new FooterButtonMods(mods), ModSelect);
Footer.AddButton(new FooterButtonMods { Current = mods }, ModSelect);
Footer.AddButton(new FooterButtonRandom { Action = triggerRandom });
Footer.AddButton(new FooterButtonOptions(), BeatmapOptions);
@ -253,7 +251,7 @@ namespace osu.Game.Screens.Select
Schedule(() =>
{
// if we have no beatmaps but osu-stable is found, let's prompt the user to import.
if (!beatmaps.GetAllUsableBeatmapSets().Any() && beatmaps.StableInstallationAvailable)
if (!beatmaps.GetAllUsableBeatmapSetsEnumerable().Any() && beatmaps.StableInstallationAvailable)
dialogOverlay.Push(new ImportFromStablePopup(() =>
{
Task.Run(beatmaps.ImportFromStableAsync).ContinueWith(_ => scores.ImportFromStableAsync(), TaskContinuationOptions.OnlyOnRanToCompletion);
@ -263,6 +261,13 @@ namespace osu.Game.Screens.Select
}
}
protected override void LoadComplete()
{
base.LoadComplete();
mods.BindTo(Mods);
}
private DependencyContainer dependencies;
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
@ -329,7 +334,7 @@ namespace osu.Game.Screens.Select
if (this.IsCurrentScreen() && !Carousel.SelectBeatmap(e.NewValue?.BeatmapInfo, false))
// If selecting new beatmap without bypassing filters failed, there's possibly a ruleset mismatch
if (e.NewValue?.BeatmapInfo?.Ruleset != null && e.NewValue.BeatmapInfo.Ruleset != decoupledRuleset.Value)
if (e.NewValue?.BeatmapInfo?.Ruleset != null && !e.NewValue.BeatmapInfo.Ruleset.Equals(decoupledRuleset.Value))
{
Ruleset.Value = e.NewValue.BeatmapInfo.Ruleset;
Carousel.SelectBeatmap(e.NewValue.BeatmapInfo);

View File

@ -34,7 +34,7 @@ namespace osu.Game.Skinning
public Drawable GetDrawableComponent(string componentName)
{
Drawable sourceDrawable;
if (beatmapSkins.Value && (sourceDrawable = skin.GetDrawableComponent(componentName)) != null)
if (beatmapSkins.Value && (sourceDrawable = skin?.GetDrawableComponent(componentName)) != null)
return sourceDrawable;
return fallbackSource?.GetDrawableComponent(componentName);
@ -43,7 +43,7 @@ namespace osu.Game.Skinning
public Texture GetTexture(string componentName)
{
Texture sourceTexture;
if (beatmapSkins.Value && (sourceTexture = skin.GetTexture(componentName)) != null)
if (beatmapSkins.Value && (sourceTexture = skin?.GetTexture(componentName)) != null)
return sourceTexture;
return fallbackSource.GetTexture(componentName);
@ -52,7 +52,7 @@ namespace osu.Game.Skinning
public SampleChannel GetSample(string sampleName)
{
SampleChannel sourceChannel;
if (beatmapHitsounds.Value && (sourceChannel = skin.GetSample(sampleName)) != null)
if (beatmapHitsounds.Value && (sourceChannel = skin?.GetSample(sampleName)) != null)
return sourceChannel;
return fallbackSource?.GetSample(sampleName);

View File

@ -5,7 +5,6 @@ using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Transforms;
namespace osu.Game.Users.Drawables
{
@ -38,8 +37,6 @@ namespace osu.Game.Users.Drawables
set => base.EdgeEffect = value;
}
protected override bool TransformImmediately { get; }
/// <summary>
/// Whether to show a default guest representation on null user (as opposed to nothing).
/// </summary>
@ -50,14 +47,11 @@ namespace osu.Game.Users.Drawables
/// </summary>
public readonly BindableBool OpenOnClick = new BindableBool(true);
public UpdateableAvatar(User user = null, bool hideImmediately = false)
public UpdateableAvatar(User user = null)
{
TransformImmediately = hideImmediately;
User = user;
}
protected override TransformSequence<Drawable> ApplyHideTransforms(Drawable drawable) => TransformImmediately ? drawable?.FadeOut() : base.ApplyHideTransforms(drawable);
protected override Drawable CreateDrawable(User user)
{
if (user == null && !ShowGuestOnNull)

View File

@ -3,7 +3,6 @@
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Transforms;
namespace osu.Game.Users.Drawables
{
@ -15,21 +14,16 @@ namespace osu.Game.Users.Drawables
set => Model = value;
}
protected override bool TransformImmediately { get; }
/// <summary>
/// Whether to show a place holder on null country.
/// </summary>
public bool ShowPlaceholderOnNull = true;
public UpdateableFlag(Country country = null, bool hideImmediately = false)
public UpdateableFlag(Country country = null)
{
TransformImmediately = hideImmediately;
Country = country;
}
protected override TransformSequence<Drawable> ApplyHideTransforms(Drawable drawable) => TransformImmediately ? drawable?.FadeOut() : base.ApplyHideTransforms(drawable);
protected override Drawable CreateDrawable(Country country)
{
if (country == null && !ShowPlaceholderOnNull)

View File

@ -15,7 +15,7 @@
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.4" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
<PackageReference Include="ppy.osu.Game.Resources" Version="2019.702.0" />
<PackageReference Include="ppy.osu.Framework" Version="2019.711.0" />
<PackageReference Include="ppy.osu.Framework" Version="2019.719.0" />
<PackageReference Include="SharpCompress" Version="0.23.0" />
<PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="SharpRaven" Version="2.4.0" />

View File

@ -105,8 +105,8 @@
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.1" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.1" />
<PackageReference Include="ppy.osu.Game.Resources" Version="2019.702.0" />
<PackageReference Include="ppy.osu.Framework" Version="2019.711.0" />
<PackageReference Include="ppy.osu.Framework.iOS" Version="2019.711.0" />
<PackageReference Include="ppy.osu.Framework" Version="2019.719.0" />
<PackageReference Include="ppy.osu.Framework.iOS" Version="2019.719.0" />
<PackageReference Include="SharpCompress" Version="0.22.0" />
<PackageReference Include="NUnit" Version="3.11.0" />
<PackageReference Include="SharpRaven" Version="2.4.0" />

View File

@ -1,249 +1 @@
{
"images": [
{
"filename": "Icon-App-20x20@2x.png",
"size": "20x20",
"scale": "2x",
"idiom": "iphone"
},
{
"filename": "Icon-App-20x20@3x.png",
"size": "20x20",
"scale": "3x",
"idiom": "iphone"
},
{
"filename": "Icon-App-29x29@2x.png",
"size": "29x29",
"scale": "2x",
"idiom": "iphone"
},
{
"filename": "Icon-App-29x29@3x.png",
"size": "29x29",
"scale": "3x",
"idiom": "iphone"
},
{
"filename": "Icon-App-40x40@2x.png",
"size": "40x40",
"scale": "2x",
"idiom": "iphone"
},
{
"filename": "Icon-App-40x40@3x.png",
"size": "40x40",
"scale": "3x",
"idiom": "iphone"
},
{
"filename": "Icon-App-60x60@2x.png",
"size": "60x60",
"scale": "2x",
"idiom": "iphone"
},
{
"filename": "Icon-App-60x60@3x.png",
"size": "60x60",
"scale": "3x",
"idiom": "iphone"
},
{
"filename": "Icon-App-20x20@1x.png",
"size": "20x20",
"scale": "1x",
"idiom": "ipad"
},
{
"filename": "Icon-App-20x20@2x.png",
"size": "20x20",
"scale": "2x",
"idiom": "ipad"
},
{
"filename": "Icon-App-29x29@1x.png",
"size": "29x29",
"scale": "1x",
"idiom": "ipad"
},
{
"filename": "Icon-App-29x29@2x.png",
"size": "29x29",
"scale": "2x",
"idiom": "ipad"
},
{
"filename": "Icon-App-40x40@1x.png",
"size": "40x40",
"scale": "1x",
"idiom": "ipad"
},
{
"filename": "Icon-App-40x40@2x.png",
"size": "40x40",
"scale": "2x",
"idiom": "ipad"
},
{
"filename": "Icon-App-83.5x83.5@2x.png",
"size": "83.5x83.5",
"scale": "2x",
"idiom": "ipad"
},
{
"filename": "Icon-App-76x76@1x.png",
"size": "76x76",
"scale": "1x",
"idiom": "ipad"
},
{
"filename": "Icon-App-76x76@2x.png",
"size": "76x76",
"scale": "2x",
"idiom": "ipad"
},
{
"filename": "ItunesArtwork@2x.png",
"size": "1024x1024",
"scale": "1x",
"idiom": "ios-marketing"
},
{
"size": "60x60",
"scale": "2x",
"idiom": "car"
},
{
"size": "60x60",
"scale": "3x",
"idiom": "car"
},
{
"role": "notificationCenter",
"size": "24x24",
"subtype": "38mm",
"scale": "2x",
"idiom": "watch"
},
{
"role": "notificationCenter",
"size": "27.5x27.5",
"subtype": "42mm",
"scale": "2x",
"idiom": "watch"
},
{
"role": "companionSettings",
"size": "29x29",
"scale": "2x",
"idiom": "watch"
},
{
"role": "companionSettings",
"size": "29x29",
"scale": "3x",
"idiom": "watch"
},
{
"role": "appLauncher",
"size": "40x40",
"subtype": "38mm",
"scale": "2x",
"idiom": "watch"
},
{
"role": "appLauncher",
"size": "44x44",
"subtype": "40mm",
"scale": "2x",
"idiom": "watch"
},
{
"role": "appLauncher",
"size": "50x50",
"subtype": "44mm",
"scale": "2x",
"idiom": "watch"
},
{
"role": "quickLook",
"size": "86x86",
"subtype": "38mm",
"scale": "2x",
"idiom": "watch"
},
{
"role": "quickLook",
"size": "98x98",
"subtype": "42mm",
"scale": "2x",
"idiom": "watch"
},
{
"role": "quickLook",
"size": "108x108",
"subtype": "44mm",
"scale": "2x",
"idiom": "watch"
},
{
"size": "1024x1024",
"scale": "1x",
"idiom": "watch-marketing"
},
{
"size": "16x16",
"scale": "1x",
"idiom": "mac"
},
{
"size": "16x16",
"scale": "2x",
"idiom": "mac"
},
{
"size": "32x32",
"scale": "1x",
"idiom": "mac"
},
{
"size": "32x32",
"scale": "2x",
"idiom": "mac"
},
{
"size": "128x128",
"scale": "1x",
"idiom": "mac"
},
{
"size": "128x128",
"scale": "2x",
"idiom": "mac"
},
{
"size": "256x256",
"scale": "1x",
"idiom": "mac"
},
{
"size": "256x256",
"scale": "2x",
"idiom": "mac"
},
{
"size": "512x512",
"scale": "1x",
"idiom": "mac"
},
{
"size": "512x512",
"scale": "2x",
"idiom": "mac"
}
],
"info": {
"version": 1,
"author": "xcode"
}
}
{"images":[{"size":"20x20","idiom":"iphone","filename":"iPhoneNotification2x.png","scale":"2x"},{"size":"20x20","idiom":"iphone","filename":"iPhoneNotification3x.png","scale":"3x"},{"size":"29x29","idiom":"iphone","filename":"iPhoneSettings2x.png","scale":"2x"},{"size":"29x29","idiom":"iphone","filename":"iPhoneSettings3x.png","scale":"3x"},{"size":"40x40","idiom":"iphone","filename":"iPhoneSpotlight2x.png","scale":"2x"},{"size":"40x40","idiom":"iphone","filename":"iPhoneSpotlight3x.png","scale":"3x"},{"size":"60x60","idiom":"iphone","filename":"iPhoneApp2x.png","scale":"2x"},{"size":"60x60","idiom":"iphone","filename":"iPhoneApp3x.png","scale":"3x"},{"size":"20x20","idiom":"ipad","filename":"iPadNotification1x.png","scale":"1x"},{"size":"20x20","idiom":"ipad","filename":"iPadNotification2x.png","scale":"2x"},{"size":"29x29","idiom":"ipad","filename":"iPadSettings1x.png","scale":"1x"},{"size":"29x29","idiom":"ipad","filename":"iPadSettings2x.png","scale":"2x"},{"size":"40x40","idiom":"ipad","filename":"iPadSpotlight1x.png","scale":"1x"},{"size":"40x40","idiom":"ipad","filename":"iPadSpotlight2x.png","scale":"2x"},{"size":"76x76","idiom":"ipad","filename":"iPadApp1x.png","scale":"1x"},{"size":"76x76","idiom":"ipad","filename":"iPadApp2x.png","scale":"2x"},{"size":"83.5x83.5","idiom":"ipad","filename":"iPadProApp2x.png","scale":"2x"},{"size":"1024x1024","idiom":"ios-marketing","filename":"iOSAppStore.png","scale":"1x"}],"info":{"version":1,"author":"xcode"}}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 245 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 342 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Some files were not shown because too many files have changed in this diff Show More