mirror of
https://github.com/ppy/osu.git
synced 2025-01-28 05:22:54 +08:00
Merge branch 'master' into fix-playlists-cross-ruleset-entry
This commit is contained in:
commit
44b3e3bfac
@ -51,7 +51,7 @@
|
|||||||
<Reference Include="Java.Interop" />
|
<Reference Include="Java.Interop" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.810.0" />
|
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.813.0" />
|
||||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2021.813.0" />
|
<PackageReference Include="ppy.osu.Framework.Android" Version="2021.813.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup Label="Transitive Dependencies">
|
<ItemGroup Label="Transitive Dependencies">
|
||||||
|
@ -40,6 +40,7 @@ namespace osu.Game.Rulesets.Catch.Tests
|
|||||||
{
|
{
|
||||||
AddSliderStep<float>("circle size", 0, 8, 5, createCatcher);
|
AddSliderStep<float>("circle size", 0, 8, 5, createCatcher);
|
||||||
AddToggleStep("hyper dash", t => this.ChildrenOfType<TestCatcherArea>().ForEach(area => area.ToggleHyperDash(t)));
|
AddToggleStep("hyper dash", t => this.ChildrenOfType<TestCatcherArea>().ForEach(area => area.ToggleHyperDash(t)));
|
||||||
|
AddToggleStep("toggle hit lighting", lighting => config.SetValue(OsuSetting.HitLighting, lighting));
|
||||||
|
|
||||||
AddStep("catch centered fruit", () => attemptCatch(new Fruit()));
|
AddStep("catch centered fruit", () => attemptCatch(new Fruit()));
|
||||||
AddStep("catch many random fruit", () =>
|
AddStep("catch many random fruit", () =>
|
||||||
|
@ -9,6 +9,7 @@ namespace osu.Game.Rulesets.Catch
|
|||||||
Banana,
|
Banana,
|
||||||
Droplet,
|
Droplet,
|
||||||
Catcher,
|
Catcher,
|
||||||
CatchComboCounter
|
CatchComboCounter,
|
||||||
|
HitExplosion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
129
osu.Game.Rulesets.Catch/Skinning/Default/DefaultHitExplosion.cs
Normal file
129
osu.Game.Rulesets.Catch/Skinning/Default/DefaultHitExplosion.cs
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
// 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.Framework.Extensions.Color4Extensions;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Effects;
|
||||||
|
using osu.Framework.Utils;
|
||||||
|
using osu.Game.Rulesets.Catch.UI;
|
||||||
|
using osu.Game.Utils;
|
||||||
|
using osuTK;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Catch.Skinning.Default
|
||||||
|
{
|
||||||
|
public class DefaultHitExplosion : CompositeDrawable, IHitExplosion
|
||||||
|
{
|
||||||
|
private CircularContainer largeFaint;
|
||||||
|
private CircularContainer smallFaint;
|
||||||
|
private CircularContainer directionalGlow1;
|
||||||
|
private CircularContainer directionalGlow2;
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
Size = new Vector2(20);
|
||||||
|
Anchor = Anchor.BottomCentre;
|
||||||
|
Origin = Anchor.BottomCentre;
|
||||||
|
|
||||||
|
// scale roughly in-line with visual appearance of notes
|
||||||
|
const float initial_height = 10;
|
||||||
|
|
||||||
|
InternalChildren = new Drawable[]
|
||||||
|
{
|
||||||
|
largeFaint = new CircularContainer
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Masking = true,
|
||||||
|
Blending = BlendingParameters.Additive,
|
||||||
|
},
|
||||||
|
smallFaint = new CircularContainer
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Masking = true,
|
||||||
|
Blending = BlendingParameters.Additive,
|
||||||
|
},
|
||||||
|
directionalGlow1 = new CircularContainer
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Masking = true,
|
||||||
|
Size = new Vector2(0.01f, initial_height),
|
||||||
|
Blending = BlendingParameters.Additive,
|
||||||
|
},
|
||||||
|
directionalGlow2 = new CircularContainer
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Masking = true,
|
||||||
|
Size = new Vector2(0.01f, initial_height),
|
||||||
|
Blending = BlendingParameters.Additive,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Animate(HitExplosionEntry entry)
|
||||||
|
{
|
||||||
|
X = entry.Position;
|
||||||
|
Scale = new Vector2(entry.HitObject.Scale);
|
||||||
|
setColour(entry.ObjectColour);
|
||||||
|
|
||||||
|
using (BeginAbsoluteSequence(entry.LifetimeStart))
|
||||||
|
applyTransforms(entry.HitObject.RandomSeed);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void applyTransforms(int randomSeed)
|
||||||
|
{
|
||||||
|
const double duration = 400;
|
||||||
|
|
||||||
|
// we want our size to be very small so the glow dominates it.
|
||||||
|
largeFaint.Size = new Vector2(0.8f);
|
||||||
|
largeFaint
|
||||||
|
.ResizeTo(largeFaint.Size * new Vector2(5, 1), duration, Easing.OutQuint)
|
||||||
|
.FadeOut(duration * 2);
|
||||||
|
|
||||||
|
const float angle_variangle = 15; // should be less than 45
|
||||||
|
directionalGlow1.Rotation = StatelessRNG.NextSingle(-angle_variangle, angle_variangle, randomSeed, 4);
|
||||||
|
directionalGlow2.Rotation = StatelessRNG.NextSingle(-angle_variangle, angle_variangle, randomSeed, 5);
|
||||||
|
|
||||||
|
this.FadeInFromZero(50).Then().FadeOut(duration, Easing.Out);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setColour(Color4 objectColour)
|
||||||
|
{
|
||||||
|
const float roundness = 100;
|
||||||
|
|
||||||
|
largeFaint.EdgeEffect = new EdgeEffectParameters
|
||||||
|
{
|
||||||
|
Type = EdgeEffectType.Glow,
|
||||||
|
Colour = Interpolation.ValueAt(0.1f, objectColour, Color4.White, 0, 1).Opacity(0.3f),
|
||||||
|
Roundness = 160,
|
||||||
|
Radius = 200,
|
||||||
|
};
|
||||||
|
|
||||||
|
smallFaint.EdgeEffect = new EdgeEffectParameters
|
||||||
|
{
|
||||||
|
Type = EdgeEffectType.Glow,
|
||||||
|
Colour = Interpolation.ValueAt(0.6f, objectColour, Color4.White, 0, 1),
|
||||||
|
Roundness = 20,
|
||||||
|
Radius = 50,
|
||||||
|
};
|
||||||
|
|
||||||
|
directionalGlow1.EdgeEffect = directionalGlow2.EdgeEffect = new EdgeEffectParameters
|
||||||
|
{
|
||||||
|
Type = EdgeEffectType.Glow,
|
||||||
|
Colour = Interpolation.ValueAt(0.4f, objectColour, Color4.White, 0, 1),
|
||||||
|
Roundness = roundness,
|
||||||
|
Radius = 40,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -70,13 +70,11 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy
|
|||||||
|
|
||||||
if (version < 2.3m)
|
if (version < 2.3m)
|
||||||
{
|
{
|
||||||
if (GetTexture(@"fruit-ryuuta") != null ||
|
if (hasOldStyleCatcherSprite())
|
||||||
GetTexture(@"fruit-ryuuta-0") != null)
|
|
||||||
return new LegacyCatcherOld();
|
return new LegacyCatcherOld();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GetTexture(@"fruit-catcher-idle") != null ||
|
if (hasNewStyleCatcherSprite())
|
||||||
GetTexture(@"fruit-catcher-idle-0") != null)
|
|
||||||
return new LegacyCatcherNew();
|
return new LegacyCatcherNew();
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
@ -86,12 +84,26 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy
|
|||||||
return new LegacyCatchComboCounter(Skin);
|
return new LegacyCatchComboCounter(Skin);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
|
case CatchSkinComponents.HitExplosion:
|
||||||
|
if (hasOldStyleCatcherSprite() || hasNewStyleCatcherSprite())
|
||||||
|
return new LegacyHitExplosion();
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return base.GetDrawableComponent(component);
|
return base.GetDrawableComponent(component);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool hasOldStyleCatcherSprite() =>
|
||||||
|
GetTexture(@"fruit-ryuuta") != null
|
||||||
|
|| GetTexture(@"fruit-ryuuta-0") != null;
|
||||||
|
|
||||||
|
private bool hasNewStyleCatcherSprite() =>
|
||||||
|
GetTexture(@"fruit-catcher-idle") != null
|
||||||
|
|| GetTexture(@"fruit-catcher-idle-0") != null;
|
||||||
|
|
||||||
public override IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup)
|
public override IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup)
|
||||||
{
|
{
|
||||||
switch (lookup)
|
switch (lookup)
|
||||||
|
@ -0,0 +1,94 @@
|
|||||||
|
// 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.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Game.Rulesets.Catch.Objects;
|
||||||
|
using osu.Game.Rulesets.Catch.UI;
|
||||||
|
using osu.Game.Skinning;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Catch.Skinning.Legacy
|
||||||
|
{
|
||||||
|
public class LegacyHitExplosion : CompositeDrawable, IHitExplosion
|
||||||
|
{
|
||||||
|
[Resolved]
|
||||||
|
private Catcher catcher { get; set; }
|
||||||
|
|
||||||
|
private const float catch_margin = (1 - Catcher.ALLOWED_CATCH_RANGE) / 2;
|
||||||
|
|
||||||
|
private readonly Sprite explosion1;
|
||||||
|
private readonly Sprite explosion2;
|
||||||
|
|
||||||
|
public LegacyHitExplosion()
|
||||||
|
{
|
||||||
|
Anchor = Anchor.BottomCentre;
|
||||||
|
Origin = Anchor.BottomCentre;
|
||||||
|
RelativeSizeAxes = Axes.Both;
|
||||||
|
Scale = new Vector2(0.5f);
|
||||||
|
|
||||||
|
InternalChildren = new[]
|
||||||
|
{
|
||||||
|
explosion1 = new Sprite
|
||||||
|
{
|
||||||
|
Anchor = Anchor.BottomCentre,
|
||||||
|
Origin = Anchor.CentreLeft,
|
||||||
|
Alpha = 0,
|
||||||
|
Blending = BlendingParameters.Additive,
|
||||||
|
Rotation = -90
|
||||||
|
},
|
||||||
|
explosion2 = new Sprite
|
||||||
|
{
|
||||||
|
Anchor = Anchor.BottomCentre,
|
||||||
|
Origin = Anchor.CentreLeft,
|
||||||
|
Alpha = 0,
|
||||||
|
Blending = BlendingParameters.Additive,
|
||||||
|
Rotation = -90
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(SkinManager skins)
|
||||||
|
{
|
||||||
|
var defaultLegacySkin = skins.DefaultLegacySkin;
|
||||||
|
|
||||||
|
// sprite names intentionally swapped to match stable member naming / ease of cross-referencing
|
||||||
|
explosion1.Texture = defaultLegacySkin.GetTexture("scoreboard-explosion-2");
|
||||||
|
explosion2.Texture = defaultLegacySkin.GetTexture("scoreboard-explosion-1");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Animate(HitExplosionEntry entry)
|
||||||
|
{
|
||||||
|
Colour = entry.ObjectColour;
|
||||||
|
|
||||||
|
using (BeginAbsoluteSequence(entry.LifetimeStart))
|
||||||
|
{
|
||||||
|
float halfCatchWidth = catcher.CatchWidth / 2;
|
||||||
|
float explosionOffset = Math.Clamp(entry.Position, -halfCatchWidth + catch_margin * 3, halfCatchWidth - catch_margin * 3);
|
||||||
|
|
||||||
|
if (!(entry.HitObject is Droplet))
|
||||||
|
{
|
||||||
|
float scale = Math.Clamp(entry.JudgementResult.ComboAtJudgement / 200f, 0.35f, 1.125f);
|
||||||
|
|
||||||
|
explosion1.Scale = new Vector2(1, 0.9f);
|
||||||
|
explosion1.Position = new Vector2(explosionOffset, 0);
|
||||||
|
|
||||||
|
explosion1.FadeOutFromOne(300);
|
||||||
|
explosion1.ScaleTo(new Vector2(16 * scale, 1.1f), 160, Easing.Out);
|
||||||
|
}
|
||||||
|
|
||||||
|
explosion2.Scale = new Vector2(0.9f, 1);
|
||||||
|
explosion2.Position = new Vector2(explosionOffset, 0);
|
||||||
|
|
||||||
|
explosion2.FadeOutFromOne(700);
|
||||||
|
explosion2.ScaleTo(new Vector2(0.9f, 1.3f), 500, Easing.Out);
|
||||||
|
|
||||||
|
this.Delay(700).FadeOutFromOne();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -23,6 +23,7 @@ using osuTK.Graphics;
|
|||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.UI
|
namespace osu.Game.Rulesets.Catch.UI
|
||||||
{
|
{
|
||||||
|
[Cached]
|
||||||
public class Catcher : SkinReloadableDrawable
|
public class Catcher : SkinReloadableDrawable
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -106,7 +107,7 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Width of the area that can be used to attempt catches during gameplay.
|
/// Width of the area that can be used to attempt catches during gameplay.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly float catchWidth;
|
public readonly float CatchWidth;
|
||||||
|
|
||||||
private readonly SkinnableCatcher body;
|
private readonly SkinnableCatcher body;
|
||||||
|
|
||||||
@ -133,7 +134,7 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
if (difficulty != null)
|
if (difficulty != null)
|
||||||
Scale = calculateScale(difficulty);
|
Scale = calculateScale(difficulty);
|
||||||
|
|
||||||
catchWidth = CalculateCatchWidth(Scale);
|
CatchWidth = CalculateCatchWidth(Scale);
|
||||||
|
|
||||||
InternalChildren = new Drawable[]
|
InternalChildren = new Drawable[]
|
||||||
{
|
{
|
||||||
@ -193,7 +194,7 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
if (!(hitObject is PalpableCatchHitObject fruit))
|
if (!(hitObject is PalpableCatchHitObject fruit))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
float halfCatchWidth = catchWidth * 0.5f;
|
float halfCatchWidth = CatchWidth * 0.5f;
|
||||||
return fruit.EffectiveX >= X - halfCatchWidth &&
|
return fruit.EffectiveX >= X - halfCatchWidth &&
|
||||||
fruit.EffectiveX <= X + halfCatchWidth;
|
fruit.EffectiveX <= X + halfCatchWidth;
|
||||||
}
|
}
|
||||||
@ -216,7 +217,7 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
placeCaughtObject(palpableObject, positionInStack);
|
placeCaughtObject(palpableObject, positionInStack);
|
||||||
|
|
||||||
if (hitLighting.Value)
|
if (hitLighting.Value)
|
||||||
addLighting(hitObject, positionInStack.X, drawableObject.AccentColour.Value);
|
addLighting(result, drawableObject.AccentColour.Value, positionInStack.X);
|
||||||
}
|
}
|
||||||
|
|
||||||
// droplet doesn't affect the catcher state
|
// droplet doesn't affect the catcher state
|
||||||
@ -365,8 +366,8 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
return position;
|
return position;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addLighting(CatchHitObject hitObject, float x, Color4 colour) =>
|
private void addLighting(JudgementResult judgementResult, Color4 colour, float x) =>
|
||||||
hitExplosionContainer.Add(new HitExplosionEntry(Time.Current, x, hitObject.Scale, colour, hitObject.RandomSeed));
|
hitExplosionContainer.Add(new HitExplosionEntry(Time.Current, judgementResult, colour, x));
|
||||||
|
|
||||||
private CaughtObject getCaughtObject(PalpableCatchHitObject source)
|
private CaughtObject getCaughtObject(PalpableCatchHitObject source)
|
||||||
{
|
{
|
||||||
|
@ -1,129 +1,56 @@
|
|||||||
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using osu.Framework.Extensions.Color4Extensions;
|
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Game.Rulesets.Catch.Skinning.Default;
|
||||||
using osu.Framework.Graphics.Effects;
|
|
||||||
using osu.Framework.Utils;
|
|
||||||
using osu.Game.Rulesets.Objects.Pooling;
|
using osu.Game.Rulesets.Objects.Pooling;
|
||||||
using osu.Game.Utils;
|
using osu.Game.Skinning;
|
||||||
using osuTK;
|
|
||||||
using osuTK.Graphics;
|
#nullable enable
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.UI
|
namespace osu.Game.Rulesets.Catch.UI
|
||||||
{
|
{
|
||||||
public class HitExplosion : PoolableDrawableWithLifetime<HitExplosionEntry>
|
public class HitExplosion : PoolableDrawableWithLifetime<HitExplosionEntry>
|
||||||
{
|
{
|
||||||
private readonly CircularContainer largeFaint;
|
private readonly SkinnableDrawable skinnableExplosion;
|
||||||
private readonly CircularContainer smallFaint;
|
|
||||||
private readonly CircularContainer directionalGlow1;
|
|
||||||
private readonly CircularContainer directionalGlow2;
|
|
||||||
|
|
||||||
public HitExplosion()
|
public HitExplosion()
|
||||||
{
|
{
|
||||||
Size = new Vector2(20);
|
RelativeSizeAxes = Axes.Both;
|
||||||
Anchor = Anchor.TopCentre;
|
Anchor = Anchor.BottomCentre;
|
||||||
Origin = Anchor.BottomCentre;
|
Origin = Anchor.BottomCentre;
|
||||||
|
|
||||||
// scale roughly in-line with visual appearance of notes
|
InternalChild = skinnableExplosion = new SkinnableDrawable(new CatchSkinComponent(CatchSkinComponents.HitExplosion), _ => new DefaultHitExplosion())
|
||||||
const float initial_height = 10;
|
|
||||||
|
|
||||||
InternalChildren = new Drawable[]
|
|
||||||
{
|
{
|
||||||
largeFaint = new CircularContainer
|
CentreComponent = false,
|
||||||
{
|
Anchor = Anchor.BottomCentre,
|
||||||
Anchor = Anchor.Centre,
|
Origin = Anchor.BottomCentre
|
||||||
Origin = Anchor.Centre,
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Masking = true,
|
|
||||||
Blending = BlendingParameters.Additive,
|
|
||||||
},
|
|
||||||
smallFaint = new CircularContainer
|
|
||||||
{
|
|
||||||
Anchor = Anchor.Centre,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Masking = true,
|
|
||||||
Blending = BlendingParameters.Additive,
|
|
||||||
},
|
|
||||||
directionalGlow1 = new CircularContainer
|
|
||||||
{
|
|
||||||
Anchor = Anchor.Centre,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Masking = true,
|
|
||||||
Size = new Vector2(0.01f, initial_height),
|
|
||||||
Blending = BlendingParameters.Additive,
|
|
||||||
},
|
|
||||||
directionalGlow2 = new CircularContainer
|
|
||||||
{
|
|
||||||
Anchor = Anchor.Centre,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Masking = true,
|
|
||||||
Size = new Vector2(0.01f, initial_height),
|
|
||||||
Blending = BlendingParameters.Additive,
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnApply(HitExplosionEntry entry)
|
protected override void OnApply(HitExplosionEntry entry)
|
||||||
{
|
{
|
||||||
X = entry.Position;
|
base.OnApply(entry);
|
||||||
Scale = new Vector2(entry.Scale);
|
if (IsLoaded)
|
||||||
setColour(entry.ObjectColour);
|
apply(entry);
|
||||||
|
|
||||||
using (BeginAbsoluteSequence(entry.LifetimeStart))
|
|
||||||
applyTransforms(entry.RNGSeed);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void applyTransforms(int randomSeed)
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
apply(Entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void apply(HitExplosionEntry? entry)
|
||||||
|
{
|
||||||
|
if (entry == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ApplyTransformsAt(double.MinValue, true);
|
||||||
ClearTransforms(true);
|
ClearTransforms(true);
|
||||||
|
|
||||||
const double duration = 400;
|
(skinnableExplosion.Drawable as IHitExplosion)?.Animate(entry);
|
||||||
|
LifetimeEnd = skinnableExplosion.Drawable.LatestTransformEndTime;
|
||||||
// we want our size to be very small so the glow dominates it.
|
|
||||||
largeFaint.Size = new Vector2(0.8f);
|
|
||||||
largeFaint
|
|
||||||
.ResizeTo(largeFaint.Size * new Vector2(5, 1), duration, Easing.OutQuint)
|
|
||||||
.FadeOut(duration * 2);
|
|
||||||
|
|
||||||
const float angle_variangle = 15; // should be less than 45
|
|
||||||
directionalGlow1.Rotation = StatelessRNG.NextSingle(-angle_variangle, angle_variangle, randomSeed, 4);
|
|
||||||
directionalGlow2.Rotation = StatelessRNG.NextSingle(-angle_variangle, angle_variangle, randomSeed, 5);
|
|
||||||
|
|
||||||
this.FadeInFromZero(50).Then().FadeOut(duration, Easing.Out).Expire();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setColour(Color4 objectColour)
|
|
||||||
{
|
|
||||||
const float roundness = 100;
|
|
||||||
|
|
||||||
largeFaint.EdgeEffect = new EdgeEffectParameters
|
|
||||||
{
|
|
||||||
Type = EdgeEffectType.Glow,
|
|
||||||
Colour = Interpolation.ValueAt(0.1f, objectColour, Color4.White, 0, 1).Opacity(0.3f),
|
|
||||||
Roundness = 160,
|
|
||||||
Radius = 200,
|
|
||||||
};
|
|
||||||
|
|
||||||
smallFaint.EdgeEffect = new EdgeEffectParameters
|
|
||||||
{
|
|
||||||
Type = EdgeEffectType.Glow,
|
|
||||||
Colour = Interpolation.ValueAt(0.6f, objectColour, Color4.White, 0, 1),
|
|
||||||
Roundness = 20,
|
|
||||||
Radius = 50,
|
|
||||||
};
|
|
||||||
|
|
||||||
directionalGlow1.EdgeEffect = directionalGlow2.EdgeEffect = new EdgeEffectParameters
|
|
||||||
{
|
|
||||||
Type = EdgeEffectType.Glow,
|
|
||||||
Colour = Interpolation.ValueAt(0.4f, objectColour, Color4.White, 0, 1),
|
|
||||||
Roundness = roundness,
|
|
||||||
Radius = 40,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Pooling;
|
using osu.Framework.Graphics.Pooling;
|
||||||
using osu.Game.Rulesets.Objects.Pooling;
|
using osu.Game.Rulesets.Objects.Pooling;
|
||||||
|
|
||||||
@ -14,6 +15,8 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
|
|
||||||
public HitExplosionContainer()
|
public HitExplosionContainer()
|
||||||
{
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both;
|
||||||
|
|
||||||
AddInternal(pool = new DrawablePool<HitExplosion>(10));
|
AddInternal(pool = new DrawablePool<HitExplosion>(10));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,24 +2,42 @@
|
|||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using osu.Framework.Graphics.Performance;
|
using osu.Framework.Graphics.Performance;
|
||||||
|
using osu.Game.Rulesets.Catch.Objects;
|
||||||
|
using osu.Game.Rulesets.Judgements;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.UI
|
namespace osu.Game.Rulesets.Catch.UI
|
||||||
{
|
{
|
||||||
public class HitExplosionEntry : LifetimeEntry
|
public class HitExplosionEntry : LifetimeEntry
|
||||||
{
|
{
|
||||||
public readonly float Position;
|
/// <summary>
|
||||||
public readonly float Scale;
|
/// The judgement result that triggered this explosion.
|
||||||
public readonly Color4 ObjectColour;
|
/// </summary>
|
||||||
public readonly int RNGSeed;
|
public JudgementResult JudgementResult { get; }
|
||||||
|
|
||||||
public HitExplosionEntry(double startTime, float position, float scale, Color4 objectColour, int rngSeed)
|
/// <summary>
|
||||||
|
/// The hitobject which triggered this explosion.
|
||||||
|
/// </summary>
|
||||||
|
public CatchHitObject HitObject => (CatchHitObject)JudgementResult.HitObject;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The accent colour of the object caught.
|
||||||
|
/// </summary>
|
||||||
|
public Color4 ObjectColour { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The position at which the object was caught.
|
||||||
|
/// </summary>
|
||||||
|
public float Position { get; }
|
||||||
|
|
||||||
|
public HitExplosionEntry(double startTime, JudgementResult judgementResult, Color4 objectColour, float position)
|
||||||
{
|
{
|
||||||
LifetimeStart = startTime;
|
LifetimeStart = startTime;
|
||||||
Position = position;
|
Position = position;
|
||||||
Scale = scale;
|
JudgementResult = judgementResult;
|
||||||
ObjectColour = objectColour;
|
ObjectColour = objectColour;
|
||||||
RNGSeed = rngSeed;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
18
osu.Game.Rulesets.Catch/UI/IHitExplosion.cs
Normal file
18
osu.Game.Rulesets.Catch/UI/IHitExplosion.cs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Catch.UI
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Common interface for all hit explosion skinnables.
|
||||||
|
/// </summary>
|
||||||
|
public interface IHitExplosion
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Begins animating this <see cref="IHitExplosion"/>.
|
||||||
|
/// </summary>
|
||||||
|
void Animate(HitExplosionEntry entry);
|
||||||
|
}
|
||||||
|
}
|
@ -8,6 +8,7 @@ using osu.Framework.Graphics.Containers;
|
|||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
|
using osu.Framework.Utils;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
@ -32,7 +33,7 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
|
|
||||||
public void ApplyToDrawableRuleset(DrawableRuleset<OsuHitObject> drawableRuleset)
|
public void ApplyToDrawableRuleset(DrawableRuleset<OsuHitObject> drawableRuleset)
|
||||||
{
|
{
|
||||||
drawableRuleset.Overlays.Add(blinds = new DrawableOsuBlinds(drawableRuleset.Playfield.HitObjectContainer, drawableRuleset.Beatmap));
|
drawableRuleset.Overlays.Add(blinds = new DrawableOsuBlinds(drawableRuleset.Playfield, drawableRuleset.Beatmap));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ApplyToHealthProcessor(HealthProcessor healthProcessor)
|
public void ApplyToHealthProcessor(HealthProcessor healthProcessor)
|
||||||
@ -128,8 +129,21 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
|
|
||||||
protected override void Update()
|
protected override void Update()
|
||||||
{
|
{
|
||||||
float start = Parent.ToLocalSpace(restrictTo.ScreenSpaceDrawQuad.TopLeft).X;
|
float start, end;
|
||||||
float end = Parent.ToLocalSpace(restrictTo.ScreenSpaceDrawQuad.TopRight).X;
|
|
||||||
|
if (Precision.AlmostEquals(restrictTo.Rotation, 0))
|
||||||
|
{
|
||||||
|
start = Parent.ToLocalSpace(restrictTo.ScreenSpaceDrawQuad.TopLeft).X;
|
||||||
|
end = Parent.ToLocalSpace(restrictTo.ScreenSpaceDrawQuad.TopRight).X;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
float center = restrictTo.ToSpaceOfOtherDrawable(restrictTo.OriginPosition, Parent).X;
|
||||||
|
float halfDiagonal = (restrictTo.DrawSize / 2).LengthFast;
|
||||||
|
|
||||||
|
start = center - halfDiagonal;
|
||||||
|
end = center + halfDiagonal;
|
||||||
|
}
|
||||||
|
|
||||||
float rawWidth = end - start;
|
float rawWidth = end - start;
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@ using osu.Framework.Input.Events;
|
|||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
using osu.Game.Rulesets.Osu.UI.Cursor;
|
using osu.Game.Rulesets.Osu.UI.Cursor;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
||||||
{
|
{
|
||||||
@ -21,6 +22,8 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
|||||||
private double lastTrailTime;
|
private double lastTrailTime;
|
||||||
private IBindable<float> cursorSize;
|
private IBindable<float> cursorSize;
|
||||||
|
|
||||||
|
private Vector2? currentPosition;
|
||||||
|
|
||||||
public LegacyCursorTrail(ISkin skin)
|
public LegacyCursorTrail(ISkin skin)
|
||||||
{
|
{
|
||||||
this.skin = skin;
|
this.skin = skin;
|
||||||
@ -54,22 +57,34 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected override double FadeDuration => disjointTrail ? 150 : 500;
|
protected override double FadeDuration => disjointTrail ? 150 : 500;
|
||||||
|
protected override float FadeExponent => 1;
|
||||||
|
|
||||||
protected override bool InterpolateMovements => !disjointTrail;
|
protected override bool InterpolateMovements => !disjointTrail;
|
||||||
|
|
||||||
protected override float IntervalMultiplier => 1 / Math.Max(cursorSize.Value, 1);
|
protected override float IntervalMultiplier => 1 / Math.Max(cursorSize.Value, 1);
|
||||||
|
|
||||||
|
protected override void Update()
|
||||||
|
{
|
||||||
|
base.Update();
|
||||||
|
|
||||||
|
if (!disjointTrail || !currentPosition.HasValue)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (Time.Current - lastTrailTime >= disjoint_trail_time_separation)
|
||||||
|
{
|
||||||
|
lastTrailTime = Time.Current;
|
||||||
|
AddTrail(currentPosition.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected override bool OnMouseMove(MouseMoveEvent e)
|
protected override bool OnMouseMove(MouseMoveEvent e)
|
||||||
{
|
{
|
||||||
if (!disjointTrail)
|
if (!disjointTrail)
|
||||||
return base.OnMouseMove(e);
|
return base.OnMouseMove(e);
|
||||||
|
|
||||||
if (Time.Current - lastTrailTime >= disjoint_trail_time_separation)
|
currentPosition = e.ScreenSpaceMousePosition;
|
||||||
{
|
|
||||||
lastTrailTime = Time.Current;
|
|
||||||
return base.OnMouseMove(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// Intentionally block the base call as we're adding the trails ourselves.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,11 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
|
|||||||
{
|
{
|
||||||
private const int max_sprites = 2048;
|
private const int max_sprites = 2048;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// An exponentiating factor to ease the trail fade.
|
||||||
|
/// </summary>
|
||||||
|
protected virtual float FadeExponent => 1.7f;
|
||||||
|
|
||||||
private readonly TrailPart[] parts = new TrailPart[max_sprites];
|
private readonly TrailPart[] parts = new TrailPart[max_sprites];
|
||||||
private int currentIndex;
|
private int currentIndex;
|
||||||
private IShader shader;
|
private IShader shader;
|
||||||
@ -141,22 +146,25 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
|
|||||||
|
|
||||||
protected override bool OnMouseMove(MouseMoveEvent e)
|
protected override bool OnMouseMove(MouseMoveEvent e)
|
||||||
{
|
{
|
||||||
Vector2 pos = e.ScreenSpaceMousePosition;
|
AddTrail(e.ScreenSpaceMousePosition);
|
||||||
|
return base.OnMouseMove(e);
|
||||||
|
}
|
||||||
|
|
||||||
if (lastPosition == null)
|
protected void AddTrail(Vector2 position)
|
||||||
|
{
|
||||||
|
if (InterpolateMovements)
|
||||||
{
|
{
|
||||||
lastPosition = pos;
|
if (!lastPosition.HasValue)
|
||||||
resampler.AddPosition(lastPosition.Value);
|
|
||||||
return base.OnMouseMove(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (Vector2 pos2 in resampler.AddPosition(pos))
|
|
||||||
{
|
|
||||||
Trace.Assert(lastPosition.HasValue);
|
|
||||||
|
|
||||||
if (InterpolateMovements)
|
|
||||||
{
|
{
|
||||||
// ReSharper disable once PossibleInvalidOperationException
|
lastPosition = position;
|
||||||
|
resampler.AddPosition(lastPosition.Value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (Vector2 pos2 in resampler.AddPosition(position))
|
||||||
|
{
|
||||||
|
Trace.Assert(lastPosition.HasValue);
|
||||||
|
|
||||||
Vector2 pos1 = lastPosition.Value;
|
Vector2 pos1 = lastPosition.Value;
|
||||||
Vector2 diff = pos2 - pos1;
|
Vector2 diff = pos2 - pos1;
|
||||||
float distance = diff.Length;
|
float distance = diff.Length;
|
||||||
@ -170,14 +178,12 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
|
|||||||
addPart(lastPosition.Value);
|
addPart(lastPosition.Value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
lastPosition = pos2;
|
|
||||||
addPart(lastPosition.Value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
return base.OnMouseMove(e);
|
{
|
||||||
|
lastPosition = position;
|
||||||
|
addPart(lastPosition.Value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addPart(Vector2 screenSpacePosition)
|
private void addPart(Vector2 screenSpacePosition)
|
||||||
@ -206,10 +212,10 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
|
|||||||
private Texture texture;
|
private Texture texture;
|
||||||
|
|
||||||
private float time;
|
private float time;
|
||||||
|
private float fadeExponent;
|
||||||
|
|
||||||
private readonly TrailPart[] parts = new TrailPart[max_sprites];
|
private readonly TrailPart[] parts = new TrailPart[max_sprites];
|
||||||
private Vector2 size;
|
private Vector2 size;
|
||||||
|
|
||||||
private Vector2 originPosition;
|
private Vector2 originPosition;
|
||||||
|
|
||||||
private readonly QuadBatch<TexturedTrailVertex> vertexBatch = new QuadBatch<TexturedTrailVertex>(max_sprites, 1);
|
private readonly QuadBatch<TexturedTrailVertex> vertexBatch = new QuadBatch<TexturedTrailVertex>(max_sprites, 1);
|
||||||
@ -227,6 +233,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
|
|||||||
texture = Source.texture;
|
texture = Source.texture;
|
||||||
size = Source.partSize;
|
size = Source.partSize;
|
||||||
time = Source.time;
|
time = Source.time;
|
||||||
|
fadeExponent = Source.FadeExponent;
|
||||||
|
|
||||||
originPosition = Vector2.Zero;
|
originPosition = Vector2.Zero;
|
||||||
|
|
||||||
@ -249,6 +256,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
|
|||||||
|
|
||||||
shader.Bind();
|
shader.Bind();
|
||||||
shader.GetUniform<float>("g_FadeClock").UpdateValue(ref time);
|
shader.GetUniform<float>("g_FadeClock").UpdateValue(ref time);
|
||||||
|
shader.GetUniform<float>("g_FadeExponent").UpdateValue(ref fadeExponent);
|
||||||
|
|
||||||
texture.TextureGL.Bind();
|
texture.TextureGL.Bind();
|
||||||
|
|
||||||
|
42
osu.Game.Tests/Visual/Menus/TestSceneSideOverlays.cs
Normal file
42
osu.Game.Tests/Visual/Menus/TestSceneSideOverlays.cs
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
// 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 NUnit.Framework;
|
||||||
|
using osu.Framework.Testing;
|
||||||
|
using osu.Game.Overlays;
|
||||||
|
using osu.Game.Tests.Visual.Navigation;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.Visual.Menus
|
||||||
|
{
|
||||||
|
public class TestSceneSideOverlays : OsuGameTestScene
|
||||||
|
{
|
||||||
|
[SetUpSteps]
|
||||||
|
public override void SetUpSteps()
|
||||||
|
{
|
||||||
|
base.SetUpSteps();
|
||||||
|
|
||||||
|
AddAssert("no screen offset applied", () => Game.ScreenOffsetContainer.X == 0f);
|
||||||
|
AddUntilStep("wait for overlays", () => Game.Settings.IsLoaded && Game.Notifications.IsLoaded);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestScreenOffsettingOnSettingsOverlay()
|
||||||
|
{
|
||||||
|
AddStep("open settings", () => Game.Settings.Show());
|
||||||
|
AddUntilStep("right screen offset applied", () => Game.ScreenOffsetContainer.X == SettingsPanel.WIDTH * TestOsuGame.SIDE_OVERLAY_OFFSET_RATIO);
|
||||||
|
|
||||||
|
AddStep("hide settings", () => Game.Settings.Hide());
|
||||||
|
AddUntilStep("screen offset removed", () => Game.ScreenOffsetContainer.X == 0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestScreenOffsettingOnNotificationOverlay()
|
||||||
|
{
|
||||||
|
AddStep("open notifications", () => Game.Notifications.Show());
|
||||||
|
AddUntilStep("right screen offset applied", () => Game.ScreenOffsetContainer.X == -NotificationOverlay.WIDTH * TestOsuGame.SIDE_OVERLAY_OFFSET_RATIO);
|
||||||
|
|
||||||
|
AddStep("hide notifications", () => Game.Notifications.Hide());
|
||||||
|
AddUntilStep("screen offset removed", () => Game.ScreenOffsetContainer.X == 0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -87,6 +87,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
public void TestEmpty()
|
public void TestEmpty()
|
||||||
{
|
{
|
||||||
// used to test the flow of multiplayer from visual tests.
|
// used to test the flow of multiplayer from visual tests.
|
||||||
|
AddStep("empty step", () => { });
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@ -408,8 +409,6 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
|
|
||||||
AddAssert("dialog overlay is hidden", () => DialogOverlay.State.Value == Visibility.Hidden);
|
AddAssert("dialog overlay is hidden", () => DialogOverlay.State.Value == Visibility.Hidden);
|
||||||
|
|
||||||
testLeave("lounge tab item", () => this.ChildrenOfType<BreadcrumbControl<IScreen>.BreadcrumbTabItem>().First().TriggerClick());
|
|
||||||
|
|
||||||
testLeave("back button", () => multiplayerScreen.OnBackButton());
|
testLeave("back button", () => multiplayerScreen.OnBackButton());
|
||||||
|
|
||||||
// mimics home button and OS window close
|
// mimics home button and OS window close
|
||||||
|
@ -6,6 +6,7 @@ using System.Collections.Generic;
|
|||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Platform;
|
using osu.Framework.Platform;
|
||||||
using osu.Framework.Screens;
|
using osu.Framework.Screens;
|
||||||
@ -95,6 +96,8 @@ namespace osu.Game.Tests.Visual.Navigation
|
|||||||
|
|
||||||
public class TestOsuGame : OsuGame
|
public class TestOsuGame : OsuGame
|
||||||
{
|
{
|
||||||
|
public new const float SIDE_OVERLAY_OFFSET_RATIO = OsuGame.SIDE_OVERLAY_OFFSET_RATIO;
|
||||||
|
|
||||||
public new ScreenStack ScreenStack => base.ScreenStack;
|
public new ScreenStack ScreenStack => base.ScreenStack;
|
||||||
|
|
||||||
public new BackButton BackButton => base.BackButton;
|
public new BackButton BackButton => base.BackButton;
|
||||||
@ -103,7 +106,11 @@ namespace osu.Game.Tests.Visual.Navigation
|
|||||||
|
|
||||||
public new ScoreManager ScoreManager => base.ScoreManager;
|
public new ScoreManager ScoreManager => base.ScoreManager;
|
||||||
|
|
||||||
public new SettingsPanel Settings => base.Settings;
|
public new Container ScreenOffsetContainer => base.ScreenOffsetContainer;
|
||||||
|
|
||||||
|
public new SettingsOverlay Settings => base.Settings;
|
||||||
|
|
||||||
|
public new NotificationOverlay Notifications => base.Notifications;
|
||||||
|
|
||||||
public new MusicController MusicController => base.MusicController;
|
public new MusicController MusicController => base.MusicController;
|
||||||
|
|
||||||
|
@ -1,23 +0,0 @@
|
|||||||
// 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;
|
|
||||||
using osu.Game.Screens.OnlinePlay.Lounge.Components;
|
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual.Playlists
|
|
||||||
{
|
|
||||||
public class TestScenePlaylistsFilterControl : OsuTestScene
|
|
||||||
{
|
|
||||||
public TestScenePlaylistsFilterControl()
|
|
||||||
{
|
|
||||||
Child = new PlaylistsFilterControl
|
|
||||||
{
|
|
||||||
Anchor = Anchor.Centre,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
RelativeSizeAxes = Axes.X,
|
|
||||||
Width = 0.7f,
|
|
||||||
Height = 80,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -27,7 +27,7 @@ namespace osu.Game.Tests.Visual.Settings
|
|||||||
new TabletSettings(tabletHandler)
|
new TabletSettings(tabletHandler)
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.None,
|
RelativeSizeAxes = Axes.None,
|
||||||
Width = SettingsPanel.WIDTH,
|
Width = SettingsPanel.PANEL_WIDTH,
|
||||||
Anchor = Anchor.TopCentre,
|
Anchor = Anchor.TopCentre,
|
||||||
Origin = Anchor.TopCentre,
|
Origin = Anchor.TopCentre,
|
||||||
}
|
}
|
||||||
|
@ -64,6 +64,11 @@ namespace osu.Game
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class OsuGame : OsuGameBase, IKeyBindingHandler<GlobalAction>
|
public class OsuGame : OsuGameBase, IKeyBindingHandler<GlobalAction>
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The amount of global offset to apply when a left/right anchored overlay is displayed (ie. settings or notifications).
|
||||||
|
/// </summary>
|
||||||
|
protected const float SIDE_OVERLAY_OFFSET_RATIO = 0.05f;
|
||||||
|
|
||||||
public Toolbar Toolbar;
|
public Toolbar Toolbar;
|
||||||
|
|
||||||
private ChatOverlay chatOverlay;
|
private ChatOverlay chatOverlay;
|
||||||
@ -71,7 +76,7 @@ namespace osu.Game
|
|||||||
private ChannelManager channelManager;
|
private ChannelManager channelManager;
|
||||||
|
|
||||||
[NotNull]
|
[NotNull]
|
||||||
private readonly NotificationOverlay notifications = new NotificationOverlay();
|
protected readonly NotificationOverlay Notifications = new NotificationOverlay();
|
||||||
|
|
||||||
private BeatmapListingOverlay beatmapListing;
|
private BeatmapListingOverlay beatmapListing;
|
||||||
|
|
||||||
@ -97,7 +102,7 @@ namespace osu.Game
|
|||||||
|
|
||||||
private ScalingContainer screenContainer;
|
private ScalingContainer screenContainer;
|
||||||
|
|
||||||
private Container screenOffsetContainer;
|
protected Container ScreenOffsetContainer { get; private set; }
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private FrameworkConfigManager frameworkConfig { get; set; }
|
private FrameworkConfigManager frameworkConfig { get; set; }
|
||||||
@ -312,7 +317,7 @@ namespace osu.Game
|
|||||||
case LinkAction.OpenEditorTimestamp:
|
case LinkAction.OpenEditorTimestamp:
|
||||||
case LinkAction.JoinMultiplayerMatch:
|
case LinkAction.JoinMultiplayerMatch:
|
||||||
case LinkAction.Spectate:
|
case LinkAction.Spectate:
|
||||||
waitForReady(() => notifications, _ => notifications.Post(new SimpleNotification
|
waitForReady(() => Notifications, _ => Notifications.Post(new SimpleNotification
|
||||||
{
|
{
|
||||||
Text = @"This link type is not yet supported!",
|
Text = @"This link type is not yet supported!",
|
||||||
Icon = FontAwesome.Solid.LifeRing,
|
Icon = FontAwesome.Solid.LifeRing,
|
||||||
@ -611,12 +616,12 @@ namespace osu.Game
|
|||||||
MenuCursorContainer.CanShowCursor = menuScreen?.CursorVisible ?? false;
|
MenuCursorContainer.CanShowCursor = menuScreen?.CursorVisible ?? false;
|
||||||
|
|
||||||
// todo: all archive managers should be able to be looped here.
|
// todo: all archive managers should be able to be looped here.
|
||||||
SkinManager.PostNotification = n => notifications.Post(n);
|
SkinManager.PostNotification = n => Notifications.Post(n);
|
||||||
|
|
||||||
BeatmapManager.PostNotification = n => notifications.Post(n);
|
BeatmapManager.PostNotification = n => Notifications.Post(n);
|
||||||
BeatmapManager.PresentImport = items => PresentBeatmap(items.First());
|
BeatmapManager.PresentImport = items => PresentBeatmap(items.First());
|
||||||
|
|
||||||
ScoreManager.PostNotification = n => notifications.Post(n);
|
ScoreManager.PostNotification = n => Notifications.Post(n);
|
||||||
ScoreManager.PresentImport = items => PresentScore(items.First());
|
ScoreManager.PresentImport = items => PresentScore(items.First());
|
||||||
|
|
||||||
// make config aware of how to lookup skins for on-screen display purposes.
|
// make config aware of how to lookup skins for on-screen display purposes.
|
||||||
@ -655,7 +660,7 @@ namespace osu.Game
|
|||||||
ActionRequested = action => volume.Adjust(action),
|
ActionRequested = action => volume.Adjust(action),
|
||||||
ScrollActionRequested = (action, amount, isPrecise) => volume.Adjust(action, amount, isPrecise),
|
ScrollActionRequested = (action, amount, isPrecise) => volume.Adjust(action, amount, isPrecise),
|
||||||
},
|
},
|
||||||
screenOffsetContainer = new Container
|
ScreenOffsetContainer = new Container
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
@ -724,7 +729,7 @@ namespace osu.Game
|
|||||||
|
|
||||||
loadComponentSingleFile(onScreenDisplay, Add, true);
|
loadComponentSingleFile(onScreenDisplay, Add, true);
|
||||||
|
|
||||||
loadComponentSingleFile(notifications.With(d =>
|
loadComponentSingleFile(Notifications.With(d =>
|
||||||
{
|
{
|
||||||
d.GetToolbarHeight = () => ToolbarOffset;
|
d.GetToolbarHeight = () => ToolbarOffset;
|
||||||
d.Anchor = Anchor.TopRight;
|
d.Anchor = Anchor.TopRight;
|
||||||
@ -733,7 +738,7 @@ namespace osu.Game
|
|||||||
|
|
||||||
loadComponentSingleFile(new CollectionManager(Storage)
|
loadComponentSingleFile(new CollectionManager(Storage)
|
||||||
{
|
{
|
||||||
PostNotification = n => notifications.Post(n),
|
PostNotification = n => Notifications.Post(n),
|
||||||
}, Add, true);
|
}, Add, true);
|
||||||
|
|
||||||
loadComponentSingleFile(stableImportManager, Add);
|
loadComponentSingleFile(stableImportManager, Add);
|
||||||
@ -785,7 +790,7 @@ namespace osu.Game
|
|||||||
Add(new MusicKeyBindingHandler());
|
Add(new MusicKeyBindingHandler());
|
||||||
|
|
||||||
// side overlays which cancel each other.
|
// side overlays which cancel each other.
|
||||||
var singleDisplaySideOverlays = new OverlayContainer[] { Settings, notifications };
|
var singleDisplaySideOverlays = new OverlayContainer[] { Settings, Notifications };
|
||||||
|
|
||||||
foreach (var overlay in singleDisplaySideOverlays)
|
foreach (var overlay in singleDisplaySideOverlays)
|
||||||
{
|
{
|
||||||
@ -828,21 +833,6 @@ namespace osu.Game
|
|||||||
{
|
{
|
||||||
if (mode.NewValue != OverlayActivation.All) CloseAllOverlays();
|
if (mode.NewValue != OverlayActivation.All) CloseAllOverlays();
|
||||||
};
|
};
|
||||||
|
|
||||||
void updateScreenOffset()
|
|
||||||
{
|
|
||||||
float offset = 0;
|
|
||||||
|
|
||||||
if (Settings.State.Value == Visibility.Visible)
|
|
||||||
offset += Toolbar.HEIGHT / 2;
|
|
||||||
if (notifications.State.Value == Visibility.Visible)
|
|
||||||
offset -= Toolbar.HEIGHT / 2;
|
|
||||||
|
|
||||||
screenOffsetContainer.MoveToX(offset, SettingsPanel.TRANSITION_LENGTH, Easing.OutQuint);
|
|
||||||
}
|
|
||||||
|
|
||||||
Settings.State.ValueChanged += _ => updateScreenOffset();
|
|
||||||
notifications.State.ValueChanged += _ => updateScreenOffset();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showOverlayAboveOthers(OverlayContainer overlay, OverlayContainer[] otherOverlays)
|
private void showOverlayAboveOthers(OverlayContainer overlay, OverlayContainer[] otherOverlays)
|
||||||
@ -874,7 +864,7 @@ namespace osu.Game
|
|||||||
|
|
||||||
if (recentLogCount < short_term_display_limit)
|
if (recentLogCount < short_term_display_limit)
|
||||||
{
|
{
|
||||||
Schedule(() => notifications.Post(new SimpleErrorNotification
|
Schedule(() => Notifications.Post(new SimpleErrorNotification
|
||||||
{
|
{
|
||||||
Icon = entry.Level == LogLevel.Important ? FontAwesome.Solid.ExclamationCircle : FontAwesome.Solid.Bomb,
|
Icon = entry.Level == LogLevel.Important ? FontAwesome.Solid.ExclamationCircle : FontAwesome.Solid.Bomb,
|
||||||
Text = entry.Message.Truncate(256) + (entry.Exception != null && IsDeployedBuild ? "\n\nThis error has been automatically reported to the devs." : string.Empty),
|
Text = entry.Message.Truncate(256) + (entry.Exception != null && IsDeployedBuild ? "\n\nThis error has been automatically reported to the devs." : string.Empty),
|
||||||
@ -882,7 +872,7 @@ namespace osu.Game
|
|||||||
}
|
}
|
||||||
else if (recentLogCount == short_term_display_limit)
|
else if (recentLogCount == short_term_display_limit)
|
||||||
{
|
{
|
||||||
Schedule(() => notifications.Post(new SimpleNotification
|
Schedule(() => Notifications.Post(new SimpleNotification
|
||||||
{
|
{
|
||||||
Icon = FontAwesome.Solid.EllipsisH,
|
Icon = FontAwesome.Solid.EllipsisH,
|
||||||
Text = "Subsequent messages have been logged. Click to view log files.",
|
Text = "Subsequent messages have been logged. Click to view log files.",
|
||||||
@ -1023,9 +1013,18 @@ namespace osu.Game
|
|||||||
{
|
{
|
||||||
base.UpdateAfterChildren();
|
base.UpdateAfterChildren();
|
||||||
|
|
||||||
screenOffsetContainer.Padding = new MarginPadding { Top = ToolbarOffset };
|
ScreenOffsetContainer.Padding = new MarginPadding { Top = ToolbarOffset };
|
||||||
overlayContent.Padding = new MarginPadding { Top = ToolbarOffset };
|
overlayContent.Padding = new MarginPadding { Top = ToolbarOffset };
|
||||||
|
|
||||||
|
var horizontalOffset = 0f;
|
||||||
|
|
||||||
|
if (Settings.IsLoaded && Settings.IsPresent)
|
||||||
|
horizontalOffset += ToLocalSpace(Settings.ScreenSpaceDrawQuad.TopRight).X * SIDE_OVERLAY_OFFSET_RATIO;
|
||||||
|
if (Notifications.IsLoaded && Notifications.IsPresent)
|
||||||
|
horizontalOffset += (ToLocalSpace(Notifications.ScreenSpaceDrawQuad.TopLeft).X - DrawWidth) * SIDE_OVERLAY_OFFSET_RATIO;
|
||||||
|
|
||||||
|
ScreenOffsetContainer.X = horizontalOffset;
|
||||||
|
|
||||||
MenuCursorContainer.CanShowCursor = (ScreenStack.CurrentScreen as IOsuScreen)?.CursorVisible ?? false;
|
MenuCursorContainer.CanShowCursor = (ScreenStack.CurrentScreen as IOsuScreen)?.CursorVisible ?? false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ namespace osu.Game.Overlays
|
|||||||
public LocalisableString Title => NotificationsStrings.HeaderTitle;
|
public LocalisableString Title => NotificationsStrings.HeaderTitle;
|
||||||
public LocalisableString Description => NotificationsStrings.HeaderDescription;
|
public LocalisableString Description => NotificationsStrings.HeaderDescription;
|
||||||
|
|
||||||
private const float width = 320;
|
public const float WIDTH = 320;
|
||||||
|
|
||||||
public const float TRANSITION_LENGTH = 600;
|
public const float TRANSITION_LENGTH = 600;
|
||||||
|
|
||||||
@ -38,7 +38,8 @@ namespace osu.Game.Overlays
|
|||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
{
|
{
|
||||||
Width = width;
|
X = WIDTH;
|
||||||
|
Width = WIDTH;
|
||||||
RelativeSizeAxes = Axes.Y;
|
RelativeSizeAxes = Axes.Y;
|
||||||
|
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
@ -152,7 +153,7 @@ namespace osu.Game.Overlays
|
|||||||
|
|
||||||
markAllRead();
|
markAllRead();
|
||||||
|
|
||||||
this.MoveToX(width, TRANSITION_LENGTH, Easing.OutQuint);
|
this.MoveToX(WIDTH, TRANSITION_LENGTH, Easing.OutQuint);
|
||||||
this.FadeTo(0, TRANSITION_LENGTH, Easing.OutQuint);
|
this.FadeTo(0, TRANSITION_LENGTH, Easing.OutQuint);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,7 +9,6 @@ using osu.Game.Overlays.Settings.Sections;
|
|||||||
using osu.Game.Overlays.Settings.Sections.Input;
|
using osu.Game.Overlays.Settings.Sections.Input;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Localisation;
|
using osu.Framework.Localisation;
|
||||||
using osu.Game.Localisation;
|
using osu.Game.Localisation;
|
||||||
@ -38,6 +37,8 @@ namespace osu.Game.Overlays
|
|||||||
|
|
||||||
private readonly List<SettingsSubPanel> subPanels = new List<SettingsSubPanel>();
|
private readonly List<SettingsSubPanel> subPanels = new List<SettingsSubPanel>();
|
||||||
|
|
||||||
|
private SettingsSubPanel lastOpenedSubPanel;
|
||||||
|
|
||||||
protected override Drawable CreateHeader() => new SettingsHeader(Title, Description);
|
protected override Drawable CreateHeader() => new SettingsHeader(Title, Description);
|
||||||
protected override Drawable CreateFooter() => new SettingsFooter();
|
protected override Drawable CreateFooter() => new SettingsFooter();
|
||||||
|
|
||||||
@ -46,21 +47,21 @@ namespace osu.Game.Overlays
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool AcceptsFocus => subPanels.All(s => s.State.Value != Visibility.Visible);
|
public override bool AcceptsFocus => lastOpenedSubPanel == null || lastOpenedSubPanel.State.Value == Visibility.Hidden;
|
||||||
|
|
||||||
private T createSubPanel<T>(T subPanel)
|
private T createSubPanel<T>(T subPanel)
|
||||||
where T : SettingsSubPanel
|
where T : SettingsSubPanel
|
||||||
{
|
{
|
||||||
subPanel.Depth = 1;
|
subPanel.Depth = 1;
|
||||||
subPanel.Anchor = Anchor.TopRight;
|
subPanel.Anchor = Anchor.TopRight;
|
||||||
subPanel.State.ValueChanged += subPanelStateChanged;
|
subPanel.State.ValueChanged += e => subPanelStateChanged(subPanel, e);
|
||||||
|
|
||||||
subPanels.Add(subPanel);
|
subPanels.Add(subPanel);
|
||||||
|
|
||||||
return subPanel;
|
return subPanel;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void subPanelStateChanged(ValueChangedEvent<Visibility> state)
|
private void subPanelStateChanged(SettingsSubPanel panel, ValueChangedEvent<Visibility> state)
|
||||||
{
|
{
|
||||||
switch (state.NewValue)
|
switch (state.NewValue)
|
||||||
{
|
{
|
||||||
@ -68,7 +69,9 @@ namespace osu.Game.Overlays
|
|||||||
Sidebar?.FadeColour(Color4.DarkGray, 300, Easing.OutQuint);
|
Sidebar?.FadeColour(Color4.DarkGray, 300, Easing.OutQuint);
|
||||||
|
|
||||||
SectionsContainer.FadeOut(300, Easing.OutQuint);
|
SectionsContainer.FadeOut(300, Easing.OutQuint);
|
||||||
ContentContainer.MoveToX(-WIDTH, 500, Easing.OutQuint);
|
ContentContainer.MoveToX(-PANEL_WIDTH, 500, Easing.OutQuint);
|
||||||
|
|
||||||
|
lastOpenedSubPanel = panel;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Visibility.Hidden:
|
case Visibility.Hidden:
|
||||||
@ -80,7 +83,7 @@ namespace osu.Game.Overlays
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override float ExpandedPosition => subPanels.Any(s => s.State.Value == Visibility.Visible) ? -WIDTH : base.ExpandedPosition;
|
protected override float ExpandedPosition => lastOpenedSubPanel?.State.Value == Visibility.Visible ? -PANEL_WIDTH : base.ExpandedPosition;
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
|
@ -28,7 +28,15 @@ namespace osu.Game.Overlays
|
|||||||
|
|
||||||
private const float sidebar_width = Sidebar.DEFAULT_WIDTH;
|
private const float sidebar_width = Sidebar.DEFAULT_WIDTH;
|
||||||
|
|
||||||
public const float WIDTH = 400;
|
/// <summary>
|
||||||
|
/// The width of the settings panel content, excluding the sidebar.
|
||||||
|
/// </summary>
|
||||||
|
public const float PANEL_WIDTH = 400;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The full width of the settings panel, including the sidebar.
|
||||||
|
/// </summary>
|
||||||
|
public const float WIDTH = sidebar_width + PANEL_WIDTH;
|
||||||
|
|
||||||
protected Container<Drawable> ContentContainer;
|
protected Container<Drawable> ContentContainer;
|
||||||
|
|
||||||
@ -64,7 +72,8 @@ namespace osu.Game.Overlays
|
|||||||
{
|
{
|
||||||
InternalChild = ContentContainer = new NonMaskedContent
|
InternalChild = ContentContainer = new NonMaskedContent
|
||||||
{
|
{
|
||||||
Width = WIDTH,
|
X = -WIDTH + ExpandedPosition,
|
||||||
|
Width = PANEL_WIDTH,
|
||||||
RelativeSizeAxes = Axes.Y,
|
RelativeSizeAxes = Axes.Y,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
|
@ -2,19 +2,15 @@
|
|||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using Humanizer;
|
using Humanizer;
|
||||||
|
using JetBrains.Annotations;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Extensions.Color4Extensions;
|
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Shapes;
|
|
||||||
using osu.Framework.Graphics.UserInterface;
|
|
||||||
using osu.Framework.Screens;
|
using osu.Framework.Screens;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
using osu.Game.Graphics.UserInterface;
|
|
||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osuTK.Graphics;
|
|
||||||
|
|
||||||
namespace osu.Game.Screens.OnlinePlay
|
namespace osu.Game.Screens.OnlinePlay
|
||||||
{
|
{
|
||||||
@ -22,52 +18,30 @@ namespace osu.Game.Screens.OnlinePlay
|
|||||||
{
|
{
|
||||||
public const float HEIGHT = 80;
|
public const float HEIGHT = 80;
|
||||||
|
|
||||||
|
private readonly ScreenStack stack;
|
||||||
|
private readonly MultiHeaderTitle title;
|
||||||
|
|
||||||
public Header(string mainTitle, ScreenStack stack)
|
public Header(string mainTitle, ScreenStack stack)
|
||||||
{
|
{
|
||||||
|
this.stack = stack;
|
||||||
|
|
||||||
RelativeSizeAxes = Axes.X;
|
RelativeSizeAxes = Axes.X;
|
||||||
Height = HEIGHT;
|
Height = HEIGHT;
|
||||||
|
Padding = new MarginPadding { Left = WaveOverlayContainer.WIDTH_PADDING };
|
||||||
|
|
||||||
HeaderBreadcrumbControl breadcrumbs;
|
Child = title = new MultiHeaderTitle(mainTitle)
|
||||||
MultiHeaderTitle title;
|
|
||||||
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
{
|
||||||
new Box
|
Anchor = Anchor.CentreLeft,
|
||||||
{
|
Origin = Anchor.CentreLeft,
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Colour = Color4Extensions.FromHex(@"#1f1921"),
|
|
||||||
},
|
|
||||||
new Container
|
|
||||||
{
|
|
||||||
Anchor = Anchor.CentreLeft,
|
|
||||||
Origin = Anchor.CentreLeft,
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Padding = new MarginPadding { Left = WaveOverlayContainer.WIDTH_PADDING + OsuScreen.HORIZONTAL_OVERFLOW_PADDING },
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
title = new MultiHeaderTitle(mainTitle)
|
|
||||||
{
|
|
||||||
Anchor = Anchor.CentreLeft,
|
|
||||||
Origin = Anchor.BottomLeft,
|
|
||||||
},
|
|
||||||
breadcrumbs = new HeaderBreadcrumbControl(stack)
|
|
||||||
{
|
|
||||||
Anchor = Anchor.BottomLeft,
|
|
||||||
Origin = Anchor.BottomLeft
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
breadcrumbs.Current.ValueChanged += screen =>
|
// unnecessary to unbind these as this header has the same lifetime as the screen stack we are attaching to.
|
||||||
{
|
stack.ScreenPushed += (_, __) => updateSubScreenTitle();
|
||||||
if (screen.NewValue is IOnlinePlaySubScreen onlineSubScreen)
|
stack.ScreenExited += (_, __) => updateSubScreenTitle();
|
||||||
title.Screen = onlineSubScreen;
|
|
||||||
};
|
|
||||||
|
|
||||||
breadcrumbs.Current.TriggerChange();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateSubScreenTitle() => title.Screen = stack.CurrentScreen as IOnlinePlaySubScreen;
|
||||||
|
|
||||||
private class MultiHeaderTitle : CompositeDrawable
|
private class MultiHeaderTitle : CompositeDrawable
|
||||||
{
|
{
|
||||||
private const float spacing = 6;
|
private const float spacing = 6;
|
||||||
@ -75,9 +49,10 @@ namespace osu.Game.Screens.OnlinePlay
|
|||||||
private readonly OsuSpriteText dot;
|
private readonly OsuSpriteText dot;
|
||||||
private readonly OsuSpriteText pageTitle;
|
private readonly OsuSpriteText pageTitle;
|
||||||
|
|
||||||
|
[CanBeNull]
|
||||||
public IOnlinePlaySubScreen Screen
|
public IOnlinePlaySubScreen Screen
|
||||||
{
|
{
|
||||||
set => pageTitle.Text = value.ShortTitle.Titleize();
|
set => pageTitle.Text = value?.ShortTitle.Titleize() ?? string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MultiHeaderTitle(string mainTitle)
|
public MultiHeaderTitle(string mainTitle)
|
||||||
@ -125,35 +100,5 @@ namespace osu.Game.Screens.OnlinePlay
|
|||||||
pageTitle.Colour = dot.Colour = colours.Yellow;
|
pageTitle.Colour = dot.Colour = colours.Yellow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class HeaderBreadcrumbControl : ScreenBreadcrumbControl
|
|
||||||
{
|
|
||||||
public HeaderBreadcrumbControl(ScreenStack stack)
|
|
||||||
: base(stack)
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.X;
|
|
||||||
StripColour = Color4.Transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void LoadComplete()
|
|
||||||
{
|
|
||||||
base.LoadComplete();
|
|
||||||
AccentColour = Color4Extensions.FromHex("#e35c99");
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override TabItem<IScreen> CreateTabItem(IScreen value) => new HeaderBreadcrumbTabItem(value)
|
|
||||||
{
|
|
||||||
AccentColour = AccentColour
|
|
||||||
};
|
|
||||||
|
|
||||||
private class HeaderBreadcrumbTabItem : BreadcrumbTabItem
|
|
||||||
{
|
|
||||||
public HeaderBreadcrumbTabItem(IScreen value)
|
|
||||||
: base(value)
|
|
||||||
{
|
|
||||||
Bar.Colour = Color4.Transparent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,125 +0,0 @@
|
|||||||
// 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.Framework.Bindables;
|
|
||||||
using osu.Framework.Graphics;
|
|
||||||
using osu.Framework.Graphics.Containers;
|
|
||||||
using osu.Framework.Graphics.UserInterface;
|
|
||||||
using osu.Framework.Threading;
|
|
||||||
using osu.Game.Graphics;
|
|
||||||
using osu.Game.Graphics.UserInterface;
|
|
||||||
using osu.Game.Rulesets;
|
|
||||||
using osuTK;
|
|
||||||
|
|
||||||
namespace osu.Game.Screens.OnlinePlay.Lounge.Components
|
|
||||||
{
|
|
||||||
public abstract class FilterControl : CompositeDrawable
|
|
||||||
{
|
|
||||||
protected readonly FillFlowContainer Filters;
|
|
||||||
|
|
||||||
[Resolved(CanBeNull = true)]
|
|
||||||
private Bindable<FilterCriteria> filter { get; set; }
|
|
||||||
|
|
||||||
[Resolved]
|
|
||||||
private IBindable<RulesetInfo> ruleset { get; set; }
|
|
||||||
|
|
||||||
private readonly SearchTextBox search;
|
|
||||||
private readonly Dropdown<RoomStatusFilter> statusDropdown;
|
|
||||||
|
|
||||||
protected FilterControl()
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.X;
|
|
||||||
Height = 70;
|
|
||||||
|
|
||||||
InternalChild = new FillFlowContainer
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Direction = FillDirection.Vertical,
|
|
||||||
Spacing = new Vector2(10),
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
search = new FilterSearchTextBox
|
|
||||||
{
|
|
||||||
Anchor = Anchor.TopRight,
|
|
||||||
Origin = Anchor.TopRight,
|
|
||||||
RelativeSizeAxes = Axes.X,
|
|
||||||
Width = 0.6f,
|
|
||||||
},
|
|
||||||
Filters = new FillFlowContainer
|
|
||||||
{
|
|
||||||
Anchor = Anchor.TopRight,
|
|
||||||
Origin = Anchor.TopRight,
|
|
||||||
AutoSizeAxes = Axes.Both,
|
|
||||||
Direction = FillDirection.Horizontal,
|
|
||||||
Spacing = new Vector2(10),
|
|
||||||
Child = statusDropdown = new SlimEnumDropdown<RoomStatusFilter>
|
|
||||||
{
|
|
||||||
Anchor = Anchor.TopRight,
|
|
||||||
Origin = Anchor.TopRight,
|
|
||||||
RelativeSizeAxes = Axes.None,
|
|
||||||
Width = 160,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
|
||||||
private void load(OsuColour colours)
|
|
||||||
{
|
|
||||||
filter ??= new Bindable<FilterCriteria>();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void LoadComplete()
|
|
||||||
{
|
|
||||||
base.LoadComplete();
|
|
||||||
|
|
||||||
search.Current.BindValueChanged(_ => updateFilterDebounced());
|
|
||||||
ruleset.BindValueChanged(_ => UpdateFilter());
|
|
||||||
statusDropdown.Current.BindValueChanged(_ => UpdateFilter(), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private ScheduledDelegate scheduledFilterUpdate;
|
|
||||||
|
|
||||||
private void updateFilterDebounced()
|
|
||||||
{
|
|
||||||
scheduledFilterUpdate?.Cancel();
|
|
||||||
scheduledFilterUpdate = Scheduler.AddDelayed(UpdateFilter, 200);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void UpdateFilter() => Scheduler.AddOnce(updateFilter);
|
|
||||||
|
|
||||||
private void updateFilter()
|
|
||||||
{
|
|
||||||
scheduledFilterUpdate?.Cancel();
|
|
||||||
|
|
||||||
var criteria = CreateCriteria();
|
|
||||||
criteria.SearchString = search.Current.Value;
|
|
||||||
criteria.Status = statusDropdown.Current.Value;
|
|
||||||
criteria.Ruleset = ruleset.Value;
|
|
||||||
|
|
||||||
filter.Value = criteria;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual FilterCriteria CreateCriteria() => new FilterCriteria();
|
|
||||||
|
|
||||||
public bool HoldFocus
|
|
||||||
{
|
|
||||||
get => search.HoldFocus;
|
|
||||||
set => search.HoldFocus = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void TakeFocus() => search.TakeFocus();
|
|
||||||
|
|
||||||
private class FilterSearchTextBox : SearchTextBox
|
|
||||||
{
|
|
||||||
[BackgroundDependencyLoader]
|
|
||||||
private void load()
|
|
||||||
{
|
|
||||||
BackgroundUnfocused = OsuColour.Gray(0.06f);
|
|
||||||
BackgroundFocused = OsuColour.Gray(0.12f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,57 +0,0 @@
|
|||||||
// 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;
|
|
||||||
using osu.Framework.Graphics.UserInterface;
|
|
||||||
using osu.Game.Graphics.UserInterface;
|
|
||||||
|
|
||||||
namespace osu.Game.Screens.OnlinePlay.Lounge.Components
|
|
||||||
{
|
|
||||||
public class PlaylistsFilterControl : FilterControl
|
|
||||||
{
|
|
||||||
private readonly Dropdown<PlaylistsCategory> categoryDropdown;
|
|
||||||
|
|
||||||
public PlaylistsFilterControl()
|
|
||||||
{
|
|
||||||
Filters.Add(categoryDropdown = new SlimEnumDropdown<PlaylistsCategory>
|
|
||||||
{
|
|
||||||
Anchor = Anchor.TopRight,
|
|
||||||
Origin = Anchor.TopRight,
|
|
||||||
RelativeSizeAxes = Axes.None,
|
|
||||||
Width = 160,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void LoadComplete()
|
|
||||||
{
|
|
||||||
base.LoadComplete();
|
|
||||||
|
|
||||||
categoryDropdown.Current.BindValueChanged(_ => UpdateFilter());
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override FilterCriteria CreateCriteria()
|
|
||||||
{
|
|
||||||
var criteria = base.CreateCriteria();
|
|
||||||
|
|
||||||
switch (categoryDropdown.Current.Value)
|
|
||||||
{
|
|
||||||
case PlaylistsCategory.Normal:
|
|
||||||
criteria.Category = "normal";
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PlaylistsCategory.Spotlight:
|
|
||||||
criteria.Category = "spotlight";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return criteria;
|
|
||||||
}
|
|
||||||
|
|
||||||
private enum PlaylistsCategory
|
|
||||||
{
|
|
||||||
Any,
|
|
||||||
Normal,
|
|
||||||
Spotlight
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
@ -10,18 +11,20 @@ using osu.Framework.Bindables;
|
|||||||
using osu.Framework.Extensions;
|
using osu.Framework.Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.UserInterface;
|
||||||
using osu.Framework.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
using osu.Framework.Screens;
|
using osu.Framework.Screens;
|
||||||
|
using osu.Framework.Threading;
|
||||||
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Graphics.Containers;
|
using osu.Game.Graphics.Containers;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
using osu.Game.Online.Rooms;
|
using osu.Game.Online.Rooms;
|
||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Screens.OnlinePlay.Lounge.Components;
|
using osu.Game.Screens.OnlinePlay.Lounge.Components;
|
||||||
using osu.Game.Screens.OnlinePlay.Match;
|
using osu.Game.Screens.OnlinePlay.Match;
|
||||||
using osu.Game.Users;
|
using osu.Game.Users;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osuTK.Graphics;
|
|
||||||
|
|
||||||
namespace osu.Game.Screens.OnlinePlay.Lounge
|
namespace osu.Game.Screens.OnlinePlay.Lounge
|
||||||
{
|
{
|
||||||
@ -42,7 +45,6 @@ namespace osu.Game.Screens.OnlinePlay.Lounge
|
|||||||
private readonly IBindable<bool> initialRoomsReceived = new Bindable<bool>();
|
private readonly IBindable<bool> initialRoomsReceived = new Bindable<bool>();
|
||||||
private readonly IBindable<bool> operationInProgress = new Bindable<bool>();
|
private readonly IBindable<bool> operationInProgress = new Bindable<bool>();
|
||||||
|
|
||||||
private FilterControl filter;
|
|
||||||
private LoadingLayer loadingLayer;
|
private LoadingLayer loadingLayer;
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
@ -54,10 +56,18 @@ namespace osu.Game.Screens.OnlinePlay.Lounge
|
|||||||
[Resolved(CanBeNull = true)]
|
[Resolved(CanBeNull = true)]
|
||||||
private OngoingOperationTracker ongoingOperationTracker { get; set; }
|
private OngoingOperationTracker ongoingOperationTracker { get; set; }
|
||||||
|
|
||||||
|
[Resolved(CanBeNull = true)]
|
||||||
|
private Bindable<FilterCriteria> filter { get; set; }
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private IBindable<RulesetInfo> ruleset { get; set; }
|
||||||
|
|
||||||
[CanBeNull]
|
[CanBeNull]
|
||||||
private IDisposable joiningRoomOperation { get; set; }
|
private IDisposable joiningRoomOperation { get; set; }
|
||||||
|
|
||||||
private RoomsContainer roomsContainer;
|
private RoomsContainer roomsContainer;
|
||||||
|
private SearchTextBox searchTextBox;
|
||||||
|
private Dropdown<RoomStatusFilter> statusDropdown;
|
||||||
|
|
||||||
[CanBeNull]
|
[CanBeNull]
|
||||||
private LeasedBindable<Room> selectionLease;
|
private LeasedBindable<Room> selectionLease;
|
||||||
@ -65,23 +75,18 @@ namespace osu.Game.Screens.OnlinePlay.Lounge
|
|||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
{
|
{
|
||||||
|
filter ??= new Bindable<FilterCriteria>(new FilterCriteria());
|
||||||
|
|
||||||
OsuScrollContainer scrollContainer;
|
OsuScrollContainer scrollContainer;
|
||||||
|
|
||||||
InternalChildren = new Drawable[]
|
InternalChildren = new[]
|
||||||
{
|
{
|
||||||
new Box
|
loadingLayer = new LoadingLayer(true),
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.X,
|
|
||||||
Height = 100,
|
|
||||||
Colour = Color4.Black,
|
|
||||||
Alpha = 0.5f,
|
|
||||||
},
|
|
||||||
new Container
|
new Container
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Padding = new MarginPadding
|
Padding = new MarginPadding
|
||||||
{
|
{
|
||||||
Top = 20,
|
|
||||||
Left = WaveOverlayContainer.WIDTH_PADDING,
|
Left = WaveOverlayContainer.WIDTH_PADDING,
|
||||||
Right = WaveOverlayContainer.WIDTH_PADDING,
|
Right = WaveOverlayContainer.WIDTH_PADDING,
|
||||||
},
|
},
|
||||||
@ -90,26 +95,50 @@ namespace osu.Game.Screens.OnlinePlay.Lounge
|
|||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
RowDimensions = new[]
|
RowDimensions = new[]
|
||||||
{
|
{
|
||||||
new Dimension(GridSizeMode.AutoSize),
|
new Dimension(GridSizeMode.Absolute, Header.HEIGHT),
|
||||||
|
new Dimension(GridSizeMode.Absolute, 25),
|
||||||
new Dimension(GridSizeMode.Absolute, 20)
|
new Dimension(GridSizeMode.Absolute, 20)
|
||||||
},
|
},
|
||||||
Content = new[]
|
Content = new[]
|
||||||
{
|
{
|
||||||
|
new Drawable[]
|
||||||
|
{
|
||||||
|
searchTextBox = new LoungeSearchTextBox
|
||||||
|
{
|
||||||
|
Anchor = Anchor.CentreRight,
|
||||||
|
Origin = Anchor.CentreRight,
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
Width = 0.6f,
|
||||||
|
},
|
||||||
|
},
|
||||||
new Drawable[]
|
new Drawable[]
|
||||||
{
|
{
|
||||||
new Container
|
new Container
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Height = 70,
|
Depth = float.MinValue, // Contained filters should appear over the top of rooms.
|
||||||
Depth = -1,
|
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
filter = CreateFilterControl(),
|
|
||||||
Buttons.WithChild(CreateNewRoomButton().With(d =>
|
Buttons.WithChild(CreateNewRoomButton().With(d =>
|
||||||
{
|
{
|
||||||
d.Size = new Vector2(150, 25);
|
d.Anchor = Anchor.BottomLeft;
|
||||||
|
d.Origin = Anchor.BottomLeft;
|
||||||
|
d.Size = new Vector2(150, 37.5f);
|
||||||
d.Action = () => Open();
|
d.Action = () => Open();
|
||||||
}))
|
})),
|
||||||
|
new FillFlowContainer
|
||||||
|
{
|
||||||
|
Anchor = Anchor.TopRight,
|
||||||
|
Origin = Anchor.TopRight,
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
Direction = FillDirection.Horizontal,
|
||||||
|
Spacing = new Vector2(10),
|
||||||
|
ChildrenEnumerable = CreateFilterControls().Select(f => f.With(d =>
|
||||||
|
{
|
||||||
|
d.Anchor = Anchor.TopRight;
|
||||||
|
d.Origin = Anchor.TopRight;
|
||||||
|
}))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -127,13 +156,12 @@ namespace osu.Game.Screens.OnlinePlay.Lounge
|
|||||||
ScrollbarOverlapsContent = false,
|
ScrollbarOverlapsContent = false,
|
||||||
Child = roomsContainer = new RoomsContainer()
|
Child = roomsContainer = new RoomsContainer()
|
||||||
},
|
},
|
||||||
loadingLayer = new LoadingLayer(true),
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// scroll selected room into view on selection.
|
// scroll selected room into view on selection.
|
||||||
@ -149,6 +177,9 @@ namespace osu.Game.Screens.OnlinePlay.Lounge
|
|||||||
{
|
{
|
||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
|
|
||||||
|
searchTextBox.Current.BindValueChanged(_ => updateFilterDebounced());
|
||||||
|
ruleset.BindValueChanged(_ => UpdateFilter());
|
||||||
|
|
||||||
initialRoomsReceived.BindTo(RoomManager.InitialRoomsReceived);
|
initialRoomsReceived.BindTo(RoomManager.InitialRoomsReceived);
|
||||||
initialRoomsReceived.BindValueChanged(_ => updateLoadingLayer());
|
initialRoomsReceived.BindValueChanged(_ => updateLoadingLayer());
|
||||||
|
|
||||||
@ -157,13 +188,50 @@ namespace osu.Game.Screens.OnlinePlay.Lounge
|
|||||||
operationInProgress.BindTo(ongoingOperationTracker.InProgress);
|
operationInProgress.BindTo(ongoingOperationTracker.InProgress);
|
||||||
operationInProgress.BindValueChanged(_ => updateLoadingLayer(), true);
|
operationInProgress.BindValueChanged(_ => updateLoadingLayer(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateFilter();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnFocus(FocusEvent e)
|
#region Filtering
|
||||||
|
|
||||||
|
protected void UpdateFilter() => Scheduler.AddOnce(updateFilter);
|
||||||
|
|
||||||
|
private ScheduledDelegate scheduledFilterUpdate;
|
||||||
|
|
||||||
|
private void updateFilterDebounced()
|
||||||
{
|
{
|
||||||
filter.TakeFocus();
|
scheduledFilterUpdate?.Cancel();
|
||||||
|
scheduledFilterUpdate = Scheduler.AddDelayed(UpdateFilter, 200);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateFilter()
|
||||||
|
{
|
||||||
|
scheduledFilterUpdate?.Cancel();
|
||||||
|
filter.Value = CreateFilterCriteria();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual FilterCriteria CreateFilterCriteria() => new FilterCriteria
|
||||||
|
{
|
||||||
|
SearchString = searchTextBox.Current.Value,
|
||||||
|
Ruleset = ruleset.Value,
|
||||||
|
Status = statusDropdown.Current.Value
|
||||||
|
};
|
||||||
|
|
||||||
|
protected virtual IEnumerable<Drawable> CreateFilterControls()
|
||||||
|
{
|
||||||
|
statusDropdown = new SlimEnumDropdown<RoomStatusFilter>
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.None,
|
||||||
|
Width = 160,
|
||||||
|
};
|
||||||
|
|
||||||
|
statusDropdown.Current.BindValueChanged(_ => UpdateFilter());
|
||||||
|
|
||||||
|
yield return statusDropdown;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
public override void OnEntering(IScreen last)
|
public override void OnEntering(IScreen last)
|
||||||
{
|
{
|
||||||
base.OnEntering(last);
|
base.OnEntering(last);
|
||||||
@ -200,14 +268,19 @@ namespace osu.Game.Screens.OnlinePlay.Lounge
|
|||||||
base.OnSuspending(next);
|
base.OnSuspending(next);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void OnFocus(FocusEvent e)
|
||||||
|
{
|
||||||
|
searchTextBox.TakeFocus();
|
||||||
|
}
|
||||||
|
|
||||||
private void onReturning()
|
private void onReturning()
|
||||||
{
|
{
|
||||||
filter.HoldFocus = true;
|
searchTextBox.HoldFocus = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onLeaving()
|
private void onLeaving()
|
||||||
{
|
{
|
||||||
filter.HoldFocus = false;
|
searchTextBox.HoldFocus = false;
|
||||||
|
|
||||||
// ensure any password prompt is dismissed.
|
// ensure any password prompt is dismissed.
|
||||||
this.HidePopover();
|
this.HidePopover();
|
||||||
@ -254,8 +327,6 @@ namespace osu.Game.Screens.OnlinePlay.Lounge
|
|||||||
this.Push(CreateRoomSubScreen(room));
|
this.Push(CreateRoomSubScreen(room));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract FilterControl CreateFilterControl();
|
|
||||||
|
|
||||||
protected abstract OsuButton CreateNewRoomButton();
|
protected abstract OsuButton CreateNewRoomButton();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -273,5 +344,15 @@ namespace osu.Game.Screens.OnlinePlay.Lounge
|
|||||||
else
|
else
|
||||||
loadingLayer.Hide();
|
loadingLayer.Hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class LoungeSearchTextBox : SearchTextBox
|
||||||
|
{
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
BackgroundUnfocused = OsuColour.Gray(0.06f);
|
||||||
|
BackgroundFocused = OsuColour.Gray(0.12f);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,8 +8,10 @@ using osu.Framework.Allocation;
|
|||||||
using osu.Framework.Audio;
|
using osu.Framework.Audio;
|
||||||
using osu.Framework.Audio.Sample;
|
using osu.Framework.Audio.Sample;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Screens;
|
using osu.Framework.Screens;
|
||||||
using osu.Game.Audio;
|
using osu.Game.Audio;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
@ -62,8 +64,15 @@ namespace osu.Game.Screens.OnlinePlay.Match
|
|||||||
|
|
||||||
protected RoomSubScreen()
|
protected RoomSubScreen()
|
||||||
{
|
{
|
||||||
|
Padding = new MarginPadding { Top = Header.HEIGHT };
|
||||||
|
|
||||||
AddRangeInternal(new Drawable[]
|
AddRangeInternal(new Drawable[]
|
||||||
{
|
{
|
||||||
|
new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Colour = Color4Extensions.FromHex(@"3e3a44") // This is super temporary.
|
||||||
|
},
|
||||||
BeatmapAvailabilityTracker = new OnlinePlayBeatmapAvailabilityTracker
|
BeatmapAvailabilityTracker = new OnlinePlayBeatmapAvailabilityTracker
|
||||||
{
|
{
|
||||||
SelectedItem = { BindTarget = SelectedItem }
|
SelectedItem = { BindTarget = SelectedItem }
|
||||||
|
@ -1,17 +0,0 @@
|
|||||||
// 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.Game.Screens.OnlinePlay.Lounge.Components;
|
|
||||||
|
|
||||||
namespace osu.Game.Screens.OnlinePlay.Multiplayer
|
|
||||||
{
|
|
||||||
public class MultiplayerFilterControl : FilterControl
|
|
||||||
{
|
|
||||||
protected override FilterCriteria CreateCriteria()
|
|
||||||
{
|
|
||||||
var criteria = base.CreateCriteria();
|
|
||||||
criteria.Category = "realtime";
|
|
||||||
return criteria;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -21,7 +21,12 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
|
|||||||
[Resolved]
|
[Resolved]
|
||||||
private MultiplayerClient client { get; set; }
|
private MultiplayerClient client { get; set; }
|
||||||
|
|
||||||
protected override FilterControl CreateFilterControl() => new MultiplayerFilterControl();
|
protected override FilterCriteria CreateFilterCriteria()
|
||||||
|
{
|
||||||
|
var criteria = base.CreateFilterCriteria();
|
||||||
|
criteria.Category = @"realtime";
|
||||||
|
return criteria;
|
||||||
|
}
|
||||||
|
|
||||||
protected override OsuButton CreateNewRoomButton() => new CreateMultiplayerMatchButton();
|
protected override OsuButton CreateNewRoomButton() => new CreateMultiplayerMatchButton();
|
||||||
|
|
||||||
|
@ -21,8 +21,9 @@ using osu.Game.Screens.Menu;
|
|||||||
using osu.Game.Screens.OnlinePlay.Components;
|
using osu.Game.Screens.OnlinePlay.Components;
|
||||||
using osu.Game.Screens.OnlinePlay.Lounge;
|
using osu.Game.Screens.OnlinePlay.Lounge;
|
||||||
using osu.Game.Screens.OnlinePlay.Lounge.Components;
|
using osu.Game.Screens.OnlinePlay.Lounge.Components;
|
||||||
using osu.Game.Screens.OnlinePlay.Match;
|
|
||||||
using osu.Game.Users;
|
using osu.Game.Users;
|
||||||
|
using osuTK;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Game.Screens.OnlinePlay
|
namespace osu.Game.Screens.OnlinePlay
|
||||||
{
|
{
|
||||||
@ -71,9 +72,6 @@ namespace osu.Game.Screens.OnlinePlay
|
|||||||
[Resolved(CanBeNull = true)]
|
[Resolved(CanBeNull = true)]
|
||||||
private OsuLogo logo { get; set; }
|
private OsuLogo logo { get; set; }
|
||||||
|
|
||||||
private Drawable header;
|
|
||||||
private Drawable headerBackground;
|
|
||||||
|
|
||||||
protected OnlinePlayScreen()
|
protected OnlinePlayScreen()
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre;
|
Anchor = Anchor.Centre;
|
||||||
@ -104,42 +102,26 @@ namespace osu.Game.Screens.OnlinePlay
|
|||||||
new Container
|
new Container
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Padding = new MarginPadding { Top = Header.HEIGHT },
|
Children = new Drawable[]
|
||||||
Children = new[]
|
|
||||||
{
|
{
|
||||||
header = new Container
|
new BufferedContainer
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Height = 400,
|
BlurSigma = new Vector2(10),
|
||||||
Children = new[]
|
Child = new BeatmapBackgroundSprite
|
||||||
{
|
{
|
||||||
headerBackground = new Container
|
RelativeSizeAxes = Axes.Both
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Width = 1.25f,
|
|
||||||
Masking = true,
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
new HeaderBackgroundSprite
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.X,
|
|
||||||
Height = 400 // Keep a static height so the header doesn't change as it's resized between subscreens
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
new Container
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Padding = new MarginPadding { Bottom = -1 }, // 1px padding to avoid a 1px gap due to masking
|
|
||||||
Child = new Box
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Colour = ColourInfo.GradientVertical(backgroundColour.Opacity(0.5f), backgroundColour)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
screenStack = new OnlinePlaySubScreenStack { RelativeSizeAxes = Axes.Both }
|
new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Colour = ColourInfo.GradientVertical(Color4.Black.Opacity(0.9f), Color4.Black.Opacity(0.6f))
|
||||||
|
},
|
||||||
|
screenStack = new OnlinePlaySubScreenStack
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
new Header(ScreenTitle, screenStack),
|
new Header(ScreenTitle, screenStack),
|
||||||
@ -292,19 +274,6 @@ namespace osu.Game.Screens.OnlinePlay
|
|||||||
|
|
||||||
private void subScreenChanged(IScreen lastScreen, IScreen newScreen)
|
private void subScreenChanged(IScreen lastScreen, IScreen newScreen)
|
||||||
{
|
{
|
||||||
switch (newScreen)
|
|
||||||
{
|
|
||||||
case LoungeSubScreen _:
|
|
||||||
header.Delay(OnlinePlaySubScreen.RESUME_TRANSITION_DELAY).ResizeHeightTo(400, OnlinePlaySubScreen.APPEAR_DURATION, Easing.OutQuint);
|
|
||||||
headerBackground.MoveToX(0, OnlinePlaySubScreen.X_MOVE_DURATION, Easing.OutQuint);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case RoomSubScreen _:
|
|
||||||
header.ResizeHeightTo(135, OnlinePlaySubScreen.APPEAR_DURATION, Easing.OutQuint);
|
|
||||||
headerBackground.MoveToX(-OnlinePlaySubScreen.X_SHIFT, OnlinePlaySubScreen.X_MOVE_DURATION, Easing.OutQuint);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lastScreen is IOsuScreen lastOsuScreen)
|
if (lastScreen is IOsuScreen lastOsuScreen)
|
||||||
Activity.UnbindFrom(lastOsuScreen.Activity);
|
Activity.UnbindFrom(lastOsuScreen.Activity);
|
||||||
|
|
||||||
@ -335,13 +304,13 @@ namespace osu.Game.Screens.OnlinePlay
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class HeaderBackgroundSprite : OnlinePlayBackgroundSprite
|
private class BeatmapBackgroundSprite : OnlinePlayBackgroundSprite
|
||||||
{
|
{
|
||||||
protected override UpdateableBeatmapBackgroundSprite CreateBackgroundSprite() => new BackgroundSprite { RelativeSizeAxes = Axes.Both };
|
protected override UpdateableBeatmapBackgroundSprite CreateBackgroundSprite() => new BackgroundSprite { RelativeSizeAxes = Axes.Both };
|
||||||
|
|
||||||
private class BackgroundSprite : UpdateableBeatmapBackgroundSprite
|
private class BackgroundSprite : UpdateableBeatmapBackgroundSprite
|
||||||
{
|
{
|
||||||
protected override double TransformDuration => 200;
|
protected override double LoadDelay => 200;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,6 +59,8 @@ namespace osu.Game.Screens.OnlinePlay
|
|||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
{
|
{
|
||||||
|
LeftArea.Padding = new MarginPadding { Top = Header.HEIGHT };
|
||||||
|
|
||||||
initialBeatmap = Beatmap.Value;
|
initialBeatmap = Beatmap.Value;
|
||||||
initialRuleset = Ruleset.Value;
|
initialRuleset = Ruleset.Value;
|
||||||
initialMods = Mods.Value.ToList();
|
initialMods = Mods.Value.ToList();
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.UserInterface;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
using osu.Game.Online.API;
|
using osu.Game.Online.API;
|
||||||
using osu.Game.Online.Rooms;
|
using osu.Game.Online.Rooms;
|
||||||
@ -16,7 +20,38 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
|
|||||||
[Resolved]
|
[Resolved]
|
||||||
private IAPIProvider api { get; set; }
|
private IAPIProvider api { get; set; }
|
||||||
|
|
||||||
protected override FilterControl CreateFilterControl() => new PlaylistsFilterControl();
|
private Dropdown<PlaylistsCategory> categoryDropdown;
|
||||||
|
|
||||||
|
protected override IEnumerable<Drawable> CreateFilterControls()
|
||||||
|
{
|
||||||
|
categoryDropdown = new SlimEnumDropdown<PlaylistsCategory>
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.None,
|
||||||
|
Width = 160,
|
||||||
|
};
|
||||||
|
|
||||||
|
categoryDropdown.Current.BindValueChanged(_ => UpdateFilter());
|
||||||
|
|
||||||
|
return base.CreateFilterControls().Append(categoryDropdown);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override FilterCriteria CreateFilterCriteria()
|
||||||
|
{
|
||||||
|
var criteria = base.CreateFilterCriteria();
|
||||||
|
|
||||||
|
switch (categoryDropdown.Current.Value)
|
||||||
|
{
|
||||||
|
case PlaylistsCategory.Normal:
|
||||||
|
criteria.Category = @"normal";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PlaylistsCategory.Spotlight:
|
||||||
|
criteria.Category = @"spotlight";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return criteria;
|
||||||
|
}
|
||||||
|
|
||||||
protected override OsuButton CreateNewRoomButton() => new CreatePlaylistsRoomButton();
|
protected override OsuButton CreateNewRoomButton() => new CreatePlaylistsRoomButton();
|
||||||
|
|
||||||
@ -30,5 +65,12 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected override RoomSubScreen CreateRoomSubScreen(Room room) => new PlaylistsRoomSubScreen(room);
|
protected override RoomSubScreen CreateRoomSubScreen(Room room) => new PlaylistsRoomSubScreen(room);
|
||||||
|
|
||||||
|
private enum PlaylistsCategory
|
||||||
|
{
|
||||||
|
Any,
|
||||||
|
Normal,
|
||||||
|
Spotlight
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -56,7 +56,7 @@ namespace osu.Game.Screens.Select
|
|||||||
set
|
set
|
||||||
{
|
{
|
||||||
searchText = value;
|
searchText = value;
|
||||||
SearchTerms = searchText.Split(new[] { ',', ' ', '!' }, StringSplitOptions.RemoveEmptyEntries).ToArray();
|
SearchTerms = searchText.Split(' ', StringSplitOptions.RemoveEmptyEntries).ToArray();
|
||||||
|
|
||||||
SearchNumber = null;
|
SearchNumber = null;
|
||||||
|
|
||||||
|
@ -79,6 +79,8 @@ namespace osu.Game.Screens.Select
|
|||||||
|
|
||||||
protected BeatmapCarousel Carousel { get; private set; }
|
protected BeatmapCarousel Carousel { get; private set; }
|
||||||
|
|
||||||
|
protected Container LeftArea { get; private set; }
|
||||||
|
|
||||||
private BeatmapInfoWedge beatmapInfoWedge;
|
private BeatmapInfoWedge beatmapInfoWedge;
|
||||||
private DialogOverlay dialogOverlay;
|
private DialogOverlay dialogOverlay;
|
||||||
|
|
||||||
@ -186,12 +188,12 @@ namespace osu.Game.Screens.Select
|
|||||||
{
|
{
|
||||||
new Drawable[]
|
new Drawable[]
|
||||||
{
|
{
|
||||||
new Container
|
LeftArea = new Container
|
||||||
{
|
{
|
||||||
Origin = Anchor.BottomLeft,
|
Origin = Anchor.BottomLeft,
|
||||||
Anchor = Anchor.BottomLeft,
|
Anchor = Anchor.BottomLeft,
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Padding = new MarginPadding { Top = left_area_padding },
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
beatmapInfoWedge = new BeatmapInfoWedge
|
beatmapInfoWedge = new BeatmapInfoWedge
|
||||||
@ -200,7 +202,6 @@ namespace osu.Game.Screens.Select
|
|||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
Margin = new MarginPadding
|
Margin = new MarginPadding
|
||||||
{
|
{
|
||||||
Top = left_area_padding,
|
|
||||||
Right = left_area_padding,
|
Right = left_area_padding,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -210,7 +211,7 @@ namespace osu.Game.Screens.Select
|
|||||||
Padding = new MarginPadding
|
Padding = new MarginPadding
|
||||||
{
|
{
|
||||||
Bottom = Footer.HEIGHT,
|
Bottom = Footer.HEIGHT,
|
||||||
Top = WEDGE_HEIGHT + left_area_padding,
|
Top = WEDGE_HEIGHT,
|
||||||
Left = left_area_padding,
|
Left = left_area_padding,
|
||||||
Right = left_area_padding * 2,
|
Right = left_area_padding * 2,
|
||||||
},
|
},
|
||||||
|
@ -37,7 +37,7 @@
|
|||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Realm" Version="10.3.0" />
|
<PackageReference Include="Realm" Version="10.3.0" />
|
||||||
<PackageReference Include="ppy.osu.Framework" Version="2021.813.0" />
|
<PackageReference Include="ppy.osu.Framework" Version="2021.813.0" />
|
||||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.810.0" />
|
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.813.0" />
|
||||||
<PackageReference Include="Sentry" Version="3.8.3" />
|
<PackageReference Include="Sentry" Version="3.8.3" />
|
||||||
<PackageReference Include="SharpCompress" Version="0.28.3" />
|
<PackageReference Include="SharpCompress" Version="0.28.3" />
|
||||||
<PackageReference Include="NUnit" Version="3.13.2" />
|
<PackageReference Include="NUnit" Version="3.13.2" />
|
||||||
|
@ -71,7 +71,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup Label="Package References">
|
<ItemGroup Label="Package References">
|
||||||
<PackageReference Include="ppy.osu.Framework.iOS" Version="2021.813.0" />
|
<PackageReference Include="ppy.osu.Framework.iOS" Version="2021.813.0" />
|
||||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.810.0" />
|
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.813.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<!-- See https://github.com/dotnet/runtime/issues/35988 (can be removed after Xamarin uses net5.0 / net6.0) -->
|
<!-- See https://github.com/dotnet/runtime/issues/35988 (can be removed after Xamarin uses net5.0 / net6.0) -->
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
|
Loading…
Reference in New Issue
Block a user