mirror of
https://github.com/ppy/osu.git
synced 2025-01-14 03:15:45 +08:00
Merge branch 'master' into hide-player-settings-overlay
This commit is contained in:
commit
f4b7ee5c7f
@ -51,8 +51,8 @@
|
||||
<Reference Include="Java.Interop" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.810.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2021.811.0" />
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.813.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2021.813.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Label="Transitive Dependencies">
|
||||
<!-- Realm needs to be directly referenced in all Xamarin projects, as it will not pull in its transitive dependencies otherwise. -->
|
||||
|
@ -40,6 +40,7 @@ namespace osu.Game.Rulesets.Catch.Tests
|
||||
{
|
||||
AddSliderStep<float>("circle size", 0, 8, 5, createCatcher);
|
||||
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 many random fruit", () =>
|
||||
|
@ -9,6 +9,7 @@ namespace osu.Game.Rulesets.Catch
|
||||
Banana,
|
||||
Droplet,
|
||||
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 (GetTexture(@"fruit-ryuuta") != null ||
|
||||
GetTexture(@"fruit-ryuuta-0") != null)
|
||||
if (hasOldStyleCatcherSprite())
|
||||
return new LegacyCatcherOld();
|
||||
}
|
||||
|
||||
if (GetTexture(@"fruit-catcher-idle") != null ||
|
||||
GetTexture(@"fruit-catcher-idle-0") != null)
|
||||
if (hasNewStyleCatcherSprite())
|
||||
return new LegacyCatcherNew();
|
||||
|
||||
return null;
|
||||
@ -86,12 +84,26 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy
|
||||
return new LegacyCatchComboCounter(Skin);
|
||||
|
||||
return null;
|
||||
|
||||
case CatchSkinComponents.HitExplosion:
|
||||
if (hasOldStyleCatcherSprite() || hasNewStyleCatcherSprite())
|
||||
return new LegacyHitExplosion();
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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
|
||||
{
|
||||
[Cached]
|
||||
public class Catcher : SkinReloadableDrawable
|
||||
{
|
||||
/// <summary>
|
||||
@ -106,7 +107,7 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
/// <summary>
|
||||
/// Width of the area that can be used to attempt catches during gameplay.
|
||||
/// </summary>
|
||||
private readonly float catchWidth;
|
||||
public readonly float CatchWidth;
|
||||
|
||||
private readonly SkinnableCatcher body;
|
||||
|
||||
@ -133,7 +134,7 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
if (difficulty != null)
|
||||
Scale = calculateScale(difficulty);
|
||||
|
||||
catchWidth = CalculateCatchWidth(Scale);
|
||||
CatchWidth = CalculateCatchWidth(Scale);
|
||||
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
@ -193,7 +194,7 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
if (!(hitObject is PalpableCatchHitObject fruit))
|
||||
return false;
|
||||
|
||||
float halfCatchWidth = catchWidth * 0.5f;
|
||||
float halfCatchWidth = CatchWidth * 0.5f;
|
||||
return fruit.EffectiveX >= X - halfCatchWidth &&
|
||||
fruit.EffectiveX <= X + halfCatchWidth;
|
||||
}
|
||||
@ -216,7 +217,7 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
placeCaughtObject(palpableObject, positionInStack);
|
||||
|
||||
if (hitLighting.Value)
|
||||
addLighting(hitObject, positionInStack.X, drawableObject.AccentColour.Value);
|
||||
addLighting(result, drawableObject.AccentColour.Value, positionInStack.X);
|
||||
}
|
||||
|
||||
// droplet doesn't affect the catcher state
|
||||
@ -365,8 +366,8 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
return position;
|
||||
}
|
||||
|
||||
private void addLighting(CatchHitObject hitObject, float x, Color4 colour) =>
|
||||
hitExplosionContainer.Add(new HitExplosionEntry(Time.Current, x, hitObject.Scale, colour, hitObject.RandomSeed));
|
||||
private void addLighting(JudgementResult judgementResult, Color4 colour, float x) =>
|
||||
hitExplosionContainer.Add(new HitExplosionEntry(Time.Current, judgementResult, colour, x));
|
||||
|
||||
private CaughtObject getCaughtObject(PalpableCatchHitObject source)
|
||||
{
|
||||
|
@ -1,129 +1,56 @@
|
||||
// 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.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.Skinning.Default;
|
||||
using osu.Game.Rulesets.Objects.Pooling;
|
||||
using osu.Game.Utils;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
using osu.Game.Skinning;
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.UI
|
||||
{
|
||||
public class HitExplosion : PoolableDrawableWithLifetime<HitExplosionEntry>
|
||||
{
|
||||
private readonly CircularContainer largeFaint;
|
||||
private readonly CircularContainer smallFaint;
|
||||
private readonly CircularContainer directionalGlow1;
|
||||
private readonly CircularContainer directionalGlow2;
|
||||
private readonly SkinnableDrawable skinnableExplosion;
|
||||
|
||||
public HitExplosion()
|
||||
{
|
||||
Size = new Vector2(20);
|
||||
Anchor = Anchor.TopCentre;
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
Anchor = Anchor.BottomCentre;
|
||||
Origin = Anchor.BottomCentre;
|
||||
|
||||
// scale roughly in-line with visual appearance of notes
|
||||
const float initial_height = 10;
|
||||
|
||||
InternalChildren = new Drawable[]
|
||||
InternalChild = skinnableExplosion = new SkinnableDrawable(new CatchSkinComponent(CatchSkinComponents.HitExplosion), _ => new DefaultHitExplosion())
|
||||
{
|
||||
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,
|
||||
}
|
||||
CentreComponent = false,
|
||||
Anchor = Anchor.BottomCentre,
|
||||
Origin = Anchor.BottomCentre
|
||||
};
|
||||
}
|
||||
|
||||
protected override void OnApply(HitExplosionEntry entry)
|
||||
{
|
||||
X = entry.Position;
|
||||
Scale = new Vector2(entry.Scale);
|
||||
setColour(entry.ObjectColour);
|
||||
|
||||
using (BeginAbsoluteSequence(entry.LifetimeStart))
|
||||
applyTransforms(entry.RNGSeed);
|
||||
base.OnApply(entry);
|
||||
if (IsLoaded)
|
||||
apply(entry);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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).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,
|
||||
};
|
||||
(skinnableExplosion.Drawable as IHitExplosion)?.Animate(entry);
|
||||
LifetimeEnd = skinnableExplosion.Drawable.LatestTransformEndTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
// 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.Pooling;
|
||||
using osu.Game.Rulesets.Objects.Pooling;
|
||||
|
||||
@ -14,6 +15,8 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
|
||||
public HitExplosionContainer()
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
|
||||
AddInternal(pool = new DrawablePool<HitExplosion>(10));
|
||||
}
|
||||
|
||||
|
@ -2,24 +2,42 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Graphics.Performance;
|
||||
using osu.Game.Rulesets.Catch.Objects;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osuTK.Graphics;
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.UI
|
||||
{
|
||||
public class HitExplosionEntry : LifetimeEntry
|
||||
{
|
||||
public readonly float Position;
|
||||
public readonly float Scale;
|
||||
public readonly Color4 ObjectColour;
|
||||
public readonly int RNGSeed;
|
||||
/// <summary>
|
||||
/// The judgement result that triggered this explosion.
|
||||
/// </summary>
|
||||
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;
|
||||
Position = position;
|
||||
Scale = scale;
|
||||
JudgementResult = judgementResult;
|
||||
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.Sprites;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
@ -32,7 +33,7 @@ namespace osu.Game.Rulesets.Osu.Mods
|
||||
|
||||
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)
|
||||
@ -128,8 +129,21 @@ namespace osu.Game.Rulesets.Osu.Mods
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
float start = Parent.ToLocalSpace(restrictTo.ScreenSpaceDrawQuad.TopLeft).X;
|
||||
float end = Parent.ToLocalSpace(restrictTo.ScreenSpaceDrawQuad.TopRight).X;
|
||||
float start, end;
|
||||
|
||||
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;
|
||||
|
||||
|
@ -9,6 +9,7 @@ using osu.Framework.Input.Events;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Rulesets.Osu.UI.Cursor;
|
||||
using osu.Game.Skinning;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
||||
{
|
||||
@ -21,6 +22,8 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
||||
private double lastTrailTime;
|
||||
private IBindable<float> cursorSize;
|
||||
|
||||
private Vector2? currentPosition;
|
||||
|
||||
public LegacyCursorTrail(ISkin skin)
|
||||
{
|
||||
this.skin = skin;
|
||||
@ -54,22 +57,34 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
||||
}
|
||||
|
||||
protected override double FadeDuration => disjointTrail ? 150 : 500;
|
||||
protected override float FadeExponent => 1;
|
||||
|
||||
protected override bool InterpolateMovements => !disjointTrail;
|
||||
|
||||
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)
|
||||
{
|
||||
if (!disjointTrail)
|
||||
return base.OnMouseMove(e);
|
||||
|
||||
if (Time.Current - lastTrailTime >= disjoint_trail_time_separation)
|
||||
{
|
||||
lastTrailTime = Time.Current;
|
||||
return base.OnMouseMove(e);
|
||||
}
|
||||
currentPosition = e.ScreenSpaceMousePosition;
|
||||
|
||||
// Intentionally block the base call as we're adding the trails ourselves.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -26,6 +26,11 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
|
||||
{
|
||||
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 int currentIndex;
|
||||
private IShader shader;
|
||||
@ -141,22 +146,25 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
|
||||
|
||||
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;
|
||||
resampler.AddPosition(lastPosition.Value);
|
||||
return base.OnMouseMove(e);
|
||||
}
|
||||
|
||||
foreach (Vector2 pos2 in resampler.AddPosition(pos))
|
||||
{
|
||||
Trace.Assert(lastPosition.HasValue);
|
||||
|
||||
if (InterpolateMovements)
|
||||
if (!lastPosition.HasValue)
|
||||
{
|
||||
// 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 diff = pos2 - pos1;
|
||||
float distance = diff.Length;
|
||||
@ -170,14 +178,12 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
|
||||
addPart(lastPosition.Value);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
lastPosition = pos2;
|
||||
addPart(lastPosition.Value);
|
||||
}
|
||||
}
|
||||
|
||||
return base.OnMouseMove(e);
|
||||
else
|
||||
{
|
||||
lastPosition = position;
|
||||
addPart(lastPosition.Value);
|
||||
}
|
||||
}
|
||||
|
||||
private void addPart(Vector2 screenSpacePosition)
|
||||
@ -206,10 +212,10 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
|
||||
private Texture texture;
|
||||
|
||||
private float time;
|
||||
private float fadeExponent;
|
||||
|
||||
private readonly TrailPart[] parts = new TrailPart[max_sprites];
|
||||
private Vector2 size;
|
||||
|
||||
private Vector2 originPosition;
|
||||
|
||||
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;
|
||||
size = Source.partSize;
|
||||
time = Source.time;
|
||||
fadeExponent = Source.FadeExponent;
|
||||
|
||||
originPosition = Vector2.Zero;
|
||||
|
||||
@ -249,6 +256,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
|
||||
|
||||
shader.Bind();
|
||||
shader.GetUniform<float>("g_FadeClock").UpdateValue(ref time);
|
||||
shader.GetUniform<float>("g_FadeExponent").UpdateValue(ref fadeExponent);
|
||||
|
||||
texture.TextureGL.Bind();
|
||||
|
||||
|
@ -169,7 +169,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
||||
|
||||
protected override Track GetBeatmapTrack() => throw new NotImplementedException();
|
||||
|
||||
protected override ISkin GetSkin() => throw new NotImplementedException();
|
||||
protected internal override ISkin GetSkin() => throw new NotImplementedException();
|
||||
|
||||
public override Stream GetStream(string storagePath) => throw new NotImplementedException();
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
// 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.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
@ -19,6 +20,7 @@ namespace osu.Game.Tests.Chat
|
||||
{
|
||||
private ChannelManager channelManager;
|
||||
private int currentMessageId;
|
||||
private List<Message> sentMessages;
|
||||
|
||||
[SetUp]
|
||||
public void Setup() => Schedule(() =>
|
||||
@ -34,6 +36,7 @@ namespace osu.Game.Tests.Chat
|
||||
AddStep("register request handling", () =>
|
||||
{
|
||||
currentMessageId = 0;
|
||||
sentMessages = new List<Message>();
|
||||
|
||||
((DummyAPIAccess)API).HandleRequest = req =>
|
||||
{
|
||||
@ -44,16 +47,11 @@ namespace osu.Game.Tests.Chat
|
||||
return true;
|
||||
|
||||
case PostMessageRequest postMessage:
|
||||
postMessage.TriggerSuccess(new Message(++currentMessageId)
|
||||
{
|
||||
IsAction = postMessage.Message.IsAction,
|
||||
ChannelId = postMessage.Message.ChannelId,
|
||||
Content = postMessage.Message.Content,
|
||||
Links = postMessage.Message.Links,
|
||||
Timestamp = postMessage.Message.Timestamp,
|
||||
Sender = postMessage.Message.Sender
|
||||
});
|
||||
handlePostMessageRequest(postMessage);
|
||||
return true;
|
||||
|
||||
case MarkChannelAsReadRequest markRead:
|
||||
handleMarkChannelAsReadRequest(markRead);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -83,12 +81,65 @@ namespace osu.Game.Tests.Chat
|
||||
AddAssert("/np command received by channel 2", () => channel2.Messages.Last().Content.Contains("is listening to"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestMarkAsReadIgnoringLocalMessages()
|
||||
{
|
||||
Channel channel = null;
|
||||
|
||||
AddStep("join channel and select it", () =>
|
||||
{
|
||||
channelManager.JoinChannel(channel = createChannel(1, ChannelType.Public));
|
||||
channelManager.CurrentChannel.Value = channel;
|
||||
});
|
||||
|
||||
AddStep("post message", () => channelManager.PostMessage("Something interesting"));
|
||||
|
||||
AddStep("post /help command", () => channelManager.PostCommand("help", channel));
|
||||
AddStep("post /me command with no action", () => channelManager.PostCommand("me", channel));
|
||||
AddStep("post /join command with no channel", () => channelManager.PostCommand("join", channel));
|
||||
AddStep("post /join command with non-existent channel", () => channelManager.PostCommand("join i-dont-exist", channel));
|
||||
AddStep("post non-existent command", () => channelManager.PostCommand("non-existent-cmd arg", channel));
|
||||
|
||||
AddStep("mark channel as read", () => channelManager.MarkChannelAsRead(channel));
|
||||
AddAssert("channel's last read ID is set to the latest message", () => channel.LastReadId == sentMessages.Last().Id);
|
||||
}
|
||||
|
||||
private void handlePostMessageRequest(PostMessageRequest request)
|
||||
{
|
||||
var message = new Message(++currentMessageId)
|
||||
{
|
||||
IsAction = request.Message.IsAction,
|
||||
ChannelId = request.Message.ChannelId,
|
||||
Content = request.Message.Content,
|
||||
Links = request.Message.Links,
|
||||
Timestamp = request.Message.Timestamp,
|
||||
Sender = request.Message.Sender
|
||||
};
|
||||
|
||||
sentMessages.Add(message);
|
||||
request.TriggerSuccess(message);
|
||||
}
|
||||
|
||||
private void handleMarkChannelAsReadRequest(MarkChannelAsReadRequest request)
|
||||
{
|
||||
// only accept messages that were sent through the API
|
||||
if (sentMessages.Contains(request.Message))
|
||||
{
|
||||
request.TriggerSuccess();
|
||||
}
|
||||
else
|
||||
{
|
||||
request.TriggerFailure(new APIException("unknown message!", null));
|
||||
}
|
||||
}
|
||||
|
||||
private Channel createChannel(int id, ChannelType type) => new Channel(new User())
|
||||
{
|
||||
Id = id,
|
||||
Name = $"Channel {id}",
|
||||
Topic = $"Topic of channel {id} with type {type}",
|
||||
Type = type,
|
||||
LastMessageId = 0,
|
||||
};
|
||||
|
||||
private class ChannelManagerContainer : CompositeDrawable
|
||||
|
@ -204,7 +204,7 @@ namespace osu.Game.Tests.Gameplay
|
||||
this.resources = resources;
|
||||
}
|
||||
|
||||
protected override ISkin GetSkin() => new TestSkin("test-sample", resources);
|
||||
protected internal override ISkin GetSkin() => new TestSkin("test-sample", resources);
|
||||
}
|
||||
|
||||
private class TestDrawableStoryboardSample : DrawableStoryboardSample
|
||||
|
@ -133,11 +133,12 @@ namespace osu.Game.Tests.Skins
|
||||
[Test]
|
||||
public void TestEmptyComboColoursNoFallback()
|
||||
{
|
||||
AddStep("Add custom combo colours to user skin", () => userSource.Configuration.AddComboColours(
|
||||
AddStep("Add custom combo colours to user skin", () => userSource.Configuration.CustomComboColours = new List<Color4>
|
||||
{
|
||||
new Color4(100, 150, 200, 255),
|
||||
new Color4(55, 110, 166, 255),
|
||||
new Color4(75, 125, 175, 255)
|
||||
));
|
||||
});
|
||||
|
||||
AddStep("Disallow default colours fallback in beatmap skin", () => beatmapSource.Configuration.AllowDefaultComboColoursFallback = false);
|
||||
|
||||
|
@ -111,7 +111,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
this.beatmapSkin = beatmapSkin;
|
||||
}
|
||||
|
||||
protected override ISkin GetSkin() => beatmapSkin;
|
||||
protected internal override ISkin GetSkin() => beatmapSkin;
|
||||
}
|
||||
|
||||
private class TestOsuRuleset : OsuRuleset
|
||||
|
@ -40,6 +40,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
});
|
||||
|
||||
AddStep("add local player", () => createLeaderboardScore(playerScore, new User { Username = "You", Id = 3 }, true));
|
||||
AddStep("toggle expanded", () => leaderboard.Expanded.Value = !leaderboard.Expanded.Value);
|
||||
AddSliderStep("set player score", 50, 5000000, 1222333, v => playerScore.Value = v);
|
||||
}
|
||||
|
||||
@ -83,19 +84,38 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
AddStep("add frenzibyte", () => createRandomScore(new User { Username = "frenzibyte", Id = 14210502 }));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestMaxHeight()
|
||||
{
|
||||
int playerNumber = 1;
|
||||
AddRepeatStep("add 3 other players", () => createRandomScore(new User { Username = $"Player {playerNumber++}" }), 3);
|
||||
checkHeight(4);
|
||||
|
||||
AddRepeatStep("add 4 other players", () => createRandomScore(new User { Username = $"Player {playerNumber++}" }), 4);
|
||||
checkHeight(8);
|
||||
|
||||
AddRepeatStep("add 4 other players", () => createRandomScore(new User { Username = $"Player {playerNumber++}" }), 4);
|
||||
checkHeight(8);
|
||||
|
||||
void checkHeight(int panelCount)
|
||||
=> AddAssert($"leaderboard height is {panelCount} panels high", () => leaderboard.DrawHeight == (GameplayLeaderboardScore.PANEL_HEIGHT + leaderboard.Spacing) * panelCount);
|
||||
}
|
||||
|
||||
private void createRandomScore(User user) => createLeaderboardScore(new BindableDouble(RNG.Next(0, 5_000_000)), user);
|
||||
|
||||
private void createLeaderboardScore(BindableDouble score, User user, bool isTracked = false)
|
||||
{
|
||||
var leaderboardScore = leaderboard.AddPlayer(user, isTracked);
|
||||
var leaderboardScore = leaderboard.Add(user, isTracked);
|
||||
leaderboardScore.TotalScore.BindTo(score);
|
||||
}
|
||||
|
||||
private class TestGameplayLeaderboard : GameplayLeaderboard
|
||||
{
|
||||
public float Spacing => Flow.Spacing.Y;
|
||||
|
||||
public bool CheckPositionByUsername(string username, int? expectedPosition)
|
||||
{
|
||||
var scoreItem = this.FirstOrDefault(i => i.User?.Username == username);
|
||||
var scoreItem = Flow.FirstOrDefault(i => i.User?.Username == username);
|
||||
|
||||
return scoreItem != null && scoreItem.ScorePosition == expectedPosition;
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ using osu.Game.Configuration;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Screens.Play;
|
||||
using osu.Game.Skinning;
|
||||
using osuTK.Input;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Gameplay
|
||||
@ -142,6 +143,22 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
AddStep("return value", () => config.SetValue(OsuSetting.KeyOverlay, keyCounterVisibleValue));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestHiddenHUDDoesntBlockSkinnableComponentsLoad()
|
||||
{
|
||||
HUDVisibilityMode originalConfigValue = default;
|
||||
|
||||
AddStep("get original config value", () => originalConfigValue = config.Get<HUDVisibilityMode>(OsuSetting.HUDVisibilityMode));
|
||||
|
||||
AddStep("set hud to never show", () => config.SetValue(OsuSetting.HUDVisibilityMode, HUDVisibilityMode.Never));
|
||||
|
||||
createNew();
|
||||
AddUntilStep("wait for hud load", () => hudOverlay.IsLoaded);
|
||||
AddUntilStep("skinnable components loaded", () => hudOverlay.ChildrenOfType<SkinnableTargetContainer>().Single().ComponentsLoaded);
|
||||
|
||||
AddStep("set original config value", () => config.SetValue(OsuSetting.HUDVisibilityMode, originalConfigValue));
|
||||
}
|
||||
|
||||
private void createNew(Action<HUDOverlay> action = null)
|
||||
{
|
||||
AddStep("create overlay", () =>
|
||||
|
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);
|
||||
}
|
||||
}
|
||||
}
|
55
osu.Game.Tests/Visual/Mods/TestSceneModFailCondition.cs
Normal file
55
osu.Game.Tests/Visual/Mods/TestSceneModFailCondition.cs
Normal file
@ -0,0 +1,55 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Rulesets.Osu.Mods;
|
||||
using osu.Game.Screens.Play;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Mods
|
||||
{
|
||||
public class TestSceneModFailCondition : ModTestScene
|
||||
{
|
||||
private bool restartRequested;
|
||||
|
||||
protected override Ruleset CreatePlayerRuleset() => new OsuRuleset();
|
||||
|
||||
protected override TestPlayer CreateModPlayer(Ruleset ruleset)
|
||||
{
|
||||
var player = base.CreateModPlayer(ruleset);
|
||||
player.RestartRequested = () => restartRequested = true;
|
||||
return player;
|
||||
}
|
||||
|
||||
protected override bool AllowFail => true;
|
||||
|
||||
[SetUpSteps]
|
||||
public void SetUp()
|
||||
{
|
||||
AddStep("reset flag", () => restartRequested = false);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestRestartOnFailDisabled() => CreateModTest(new ModTestData
|
||||
{
|
||||
Autoplay = false,
|
||||
Mod = new OsuModSuddenDeath(),
|
||||
PassCondition = () => !restartRequested && Player.ChildrenOfType<FailOverlay>().Single().State.Value == Visibility.Visible
|
||||
});
|
||||
|
||||
[Test]
|
||||
public void TestRestartOnFailEnabled() => CreateModTest(new ModTestData
|
||||
{
|
||||
Autoplay = false,
|
||||
Mod = new OsuModSuddenDeath
|
||||
{
|
||||
Restart = { Value = true }
|
||||
},
|
||||
PassCondition = () => restartRequested && Player.ChildrenOfType<FailOverlay>().Single().State.Value == Visibility.Hidden
|
||||
});
|
||||
}
|
||||
}
|
@ -25,7 +25,7 @@ using osu.Game.Screens;
|
||||
using osu.Game.Screens.OnlinePlay.Components;
|
||||
using osu.Game.Screens.OnlinePlay.Lounge;
|
||||
using osu.Game.Screens.OnlinePlay.Lounge.Components;
|
||||
using osu.Game.Screens.OnlinePlay.Match.Components;
|
||||
using osu.Game.Screens.OnlinePlay.Match;
|
||||
using osu.Game.Screens.OnlinePlay.Multiplayer;
|
||||
using osu.Game.Screens.OnlinePlay.Multiplayer.Match;
|
||||
using osu.Game.Tests.Resources;
|
||||
@ -87,6 +87,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
public void TestEmpty()
|
||||
{
|
||||
// used to test the flow of multiplayer from visual tests.
|
||||
AddStep("empty step", () => { });
|
||||
}
|
||||
|
||||
[Test]
|
||||
@ -312,6 +313,8 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
InputManager.Click(MouseButton.Left);
|
||||
});
|
||||
|
||||
AddUntilStep("wait for spectating user state", () => client.LocalUser?.State == MultiplayerUserState.Spectating);
|
||||
|
||||
AddStep("start match externally", () => client.StartMatch());
|
||||
|
||||
AddAssert("play not started", () => multiplayerScreen.IsCurrentScreen());
|
||||
@ -348,6 +351,8 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
InputManager.Click(MouseButton.Left);
|
||||
});
|
||||
|
||||
AddUntilStep("wait for spectating user state", () => client.LocalUser?.State == MultiplayerUserState.Spectating);
|
||||
|
||||
AddStep("start match externally", () => client.StartMatch());
|
||||
|
||||
AddStep("restore beatmap", () =>
|
||||
@ -396,7 +401,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
}
|
||||
});
|
||||
|
||||
AddStep("open mod overlay", () => this.ChildrenOfType<PurpleTriangleButton>().ElementAt(2).TriggerClick());
|
||||
AddStep("open mod overlay", () => this.ChildrenOfType<RoomSubScreen.UserModSelectButton>().Single().TriggerClick());
|
||||
|
||||
AddStep("invoke on back button", () => multiplayerScreen.OnBackButton());
|
||||
|
||||
@ -404,8 +409,6 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
|
||||
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());
|
||||
|
||||
// mimics home button and OS window close
|
||||
|
@ -129,6 +129,8 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
InputManager.Click(MouseButton.Left);
|
||||
});
|
||||
|
||||
AddUntilStep("wait for spectating user state", () => Client.LocalUser?.State == MultiplayerUserState.Spectating);
|
||||
|
||||
AddUntilStep("wait for ready button to be enabled", () => this.ChildrenOfType<MultiplayerReadyButton>().Single().ChildrenOfType<ReadyButton>().Single().Enabled.Value);
|
||||
|
||||
AddStep("click ready button", () =>
|
||||
|
@ -4,6 +4,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Extensions.ObjectExtensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Testing;
|
||||
@ -48,9 +49,15 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
AddAssert("one unique panel", () => this.ChildrenOfType<ParticipantPanel>().Select(p => p.User).Distinct().Count() == 1);
|
||||
|
||||
AddStep("add non-resolvable user", () => Client.AddNullUser(-3));
|
||||
AddStep("add non-resolvable user", () => Client.AddNullUser());
|
||||
AddAssert("null user added", () => Client.Room.AsNonNull().Users.Count(u => u.User == null) == 1);
|
||||
|
||||
AddUntilStep("two unique panels", () => this.ChildrenOfType<ParticipantPanel>().Select(p => p.User).Distinct().Count() == 2);
|
||||
|
||||
AddStep("kick null user", () => this.ChildrenOfType<ParticipantPanel>().Single(p => p.User.User == null)
|
||||
.ChildrenOfType<ParticipantPanel.KickButton>().Single().TriggerClick());
|
||||
|
||||
AddAssert("null user kicked", () => Client.Room.AsNonNull().Users.Count == 1);
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -0,0 +1,51 @@
|
||||
// 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 NUnit.Framework;
|
||||
using osu.Game.Online.Rooms;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Scoring;
|
||||
using osu.Game.Screens.OnlinePlay.Multiplayer;
|
||||
using osu.Game.Users;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
public class TestSceneMultiplayerResults : ScreenTestScene
|
||||
{
|
||||
[Test]
|
||||
public void TestDisplayResults()
|
||||
{
|
||||
MultiplayerResultsScreen screen = null;
|
||||
|
||||
AddStep("show results screen", () =>
|
||||
{
|
||||
var rulesetInfo = new OsuRuleset().RulesetInfo;
|
||||
var beatmapInfo = CreateBeatmap(rulesetInfo).BeatmapInfo;
|
||||
|
||||
var score = new ScoreInfo
|
||||
{
|
||||
Rank = ScoreRank.B,
|
||||
TotalScore = 987654,
|
||||
Accuracy = 0.8,
|
||||
MaxCombo = 500,
|
||||
Combo = 250,
|
||||
Beatmap = beatmapInfo,
|
||||
User = new User { Username = "Test user" },
|
||||
Date = DateTimeOffset.Now,
|
||||
OnlineScoreID = 12345,
|
||||
Ruleset = rulesetInfo,
|
||||
};
|
||||
|
||||
PlaylistItem playlistItem = new PlaylistItem
|
||||
{
|
||||
BeatmapID = beatmapInfo.ID,
|
||||
};
|
||||
|
||||
Stack.Push(screen = new MultiplayerResultsScreen(score, 1, playlistItem));
|
||||
});
|
||||
|
||||
AddUntilStep("wait for loaded", () => screen.IsLoaded);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Game.Online.Rooms;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Scoring;
|
||||
using osu.Game.Screens.OnlinePlay.Multiplayer;
|
||||
using osu.Game.Users;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
public class TestSceneMultiplayerTeamResults : ScreenTestScene
|
||||
{
|
||||
[TestCase(7483253, 1048576)]
|
||||
[TestCase(1048576, 7483253)]
|
||||
[TestCase(1048576, 1048576)]
|
||||
public void TestDisplayTeamResults(int team1Score, int team2Score)
|
||||
{
|
||||
MultiplayerResultsScreen screen = null;
|
||||
|
||||
AddStep("show results screen", () =>
|
||||
{
|
||||
var rulesetInfo = new OsuRuleset().RulesetInfo;
|
||||
var beatmapInfo = CreateBeatmap(rulesetInfo).BeatmapInfo;
|
||||
|
||||
var score = new ScoreInfo
|
||||
{
|
||||
Rank = ScoreRank.B,
|
||||
TotalScore = 987654,
|
||||
Accuracy = 0.8,
|
||||
MaxCombo = 500,
|
||||
Combo = 250,
|
||||
Beatmap = beatmapInfo,
|
||||
User = new User { Username = "Test user" },
|
||||
Date = DateTimeOffset.Now,
|
||||
OnlineScoreID = 12345,
|
||||
Ruleset = rulesetInfo,
|
||||
};
|
||||
|
||||
PlaylistItem playlistItem = new PlaylistItem
|
||||
{
|
||||
BeatmapID = beatmapInfo.ID,
|
||||
};
|
||||
|
||||
SortedDictionary<int, BindableInt> teamScores = new SortedDictionary<int, BindableInt>
|
||||
{
|
||||
{ 0, new BindableInt(team1Score) },
|
||||
{ 1, new BindableInt(team2Score) }
|
||||
};
|
||||
|
||||
Stack.Push(screen = new MultiplayerTeamResultsScreen(score, 1, playlistItem, teamScores));
|
||||
});
|
||||
|
||||
AddUntilStep("wait for loaded", () => screen.IsLoaded);
|
||||
}
|
||||
}
|
||||
}
|
@ -6,6 +6,7 @@ using System.Collections.Generic;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Framework.Screens;
|
||||
@ -95,6 +96,8 @@ namespace osu.Game.Tests.Visual.Navigation
|
||||
|
||||
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 BackButton BackButton => base.BackButton;
|
||||
@ -103,7 +106,11 @@ namespace osu.Game.Tests.Visual.Navigation
|
||||
|
||||
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;
|
||||
|
||||
|
@ -3,84 +3,52 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Overlays.Comments;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Users;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics;
|
||||
using osuTK;
|
||||
using JetBrains.Annotations;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Testing;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Online
|
||||
{
|
||||
public class TestSceneCommentsPage : OsuTestScene
|
||||
public class TestSceneOfflineCommentsContainer : OsuTestScene
|
||||
{
|
||||
[Cached]
|
||||
private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple);
|
||||
private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue);
|
||||
|
||||
private readonly BindableBool showDeleted = new BindableBool();
|
||||
private readonly Container content;
|
||||
private TestCommentsContainer comments;
|
||||
|
||||
private TestCommentsPage commentsPage;
|
||||
|
||||
public TestSceneCommentsPage()
|
||||
[SetUp]
|
||||
public void SetUp() => Schedule(() =>
|
||||
{
|
||||
Add(new FillFlowContainer
|
||||
Clear();
|
||||
Add(new BasicScrollContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Y,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Direction = FillDirection.Vertical,
|
||||
Spacing = new Vector2(0, 10),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Container
|
||||
{
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Width = 200,
|
||||
Child = new OsuCheckbox
|
||||
{
|
||||
Current = showDeleted,
|
||||
LabelText = @"Show Deleted"
|
||||
}
|
||||
},
|
||||
content = new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
}
|
||||
}
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Child = comments = new TestCommentsContainer()
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
[Test]
|
||||
public void TestAppendDuplicatedComment()
|
||||
{
|
||||
AddStep("Create page", () => createPage(getCommentBundle()));
|
||||
AddAssert("Dictionary length is 10", () => commentsPage?.DictionaryLength == 10);
|
||||
AddStep("Append existing comment", () => commentsPage?.AppendComments(getCommentSubBundle()));
|
||||
AddAssert("Dictionary length is 10", () => commentsPage?.DictionaryLength == 10);
|
||||
AddStep("Add comment bundle", () => comments.ShowComments(getCommentBundle()));
|
||||
AddUntilStep("Dictionary length is 10", () => comments.DictionaryLength == 10);
|
||||
AddStep("Append existing comment", () => comments.AppendComments(getCommentSubBundle()));
|
||||
AddAssert("Dictionary length is 10", () => comments.DictionaryLength == 10);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestEmptyBundle()
|
||||
public void TestLocalCommentBundle()
|
||||
{
|
||||
AddStep("Create page", () => createPage(getEmptyCommentBundle()));
|
||||
AddAssert("Dictionary length is 0", () => commentsPage?.DictionaryLength == 0);
|
||||
}
|
||||
|
||||
private void createPage(CommentBundle commentBundle)
|
||||
{
|
||||
commentsPage = null;
|
||||
content.Clear();
|
||||
content.Add(commentsPage = new TestCommentsPage(commentBundle)
|
||||
{
|
||||
ShowDeleted = { BindTarget = showDeleted }
|
||||
});
|
||||
AddStep("Add comment bundle", () => comments.ShowComments(getCommentBundle()));
|
||||
AddStep("Add empty comment bundle", () => comments.ShowComments(getEmptyCommentBundle()));
|
||||
}
|
||||
|
||||
private CommentBundle getEmptyCommentBundle() => new CommentBundle
|
||||
@ -193,6 +161,7 @@ namespace osu.Game.Tests.Visual.Online
|
||||
Username = "Good_Admin"
|
||||
}
|
||||
},
|
||||
Total = 10
|
||||
};
|
||||
|
||||
private CommentBundle getCommentSubBundle() => new CommentBundle
|
||||
@ -211,16 +180,18 @@ namespace osu.Game.Tests.Visual.Online
|
||||
IncludedComments = new List<Comment>(),
|
||||
};
|
||||
|
||||
private class TestCommentsPage : CommentsPage
|
||||
private class TestCommentsContainer : CommentsContainer
|
||||
{
|
||||
public TestCommentsPage(CommentBundle commentBundle)
|
||||
: base(commentBundle)
|
||||
{
|
||||
}
|
||||
|
||||
public new void AppendComments([NotNull] CommentBundle bundle) => base.AppendComments(bundle);
|
||||
|
||||
public int DictionaryLength => CommentDictionary.Count;
|
||||
|
||||
public void ShowComments(CommentBundle bundle)
|
||||
{
|
||||
this.ChildrenOfType<TotalCommentsCounter>().Single().Current.Value = 0;
|
||||
ClearComments();
|
||||
OnSuccess(bundle);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@ -62,6 +62,24 @@ namespace osu.Game.Tests.Visual.Playlists
|
||||
AddUntilStep("last room is not masked", () => checkRoomVisible(roomsContainer.Rooms[^1]));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestEnteringRoomTakesLeaseOnSelection()
|
||||
{
|
||||
AddStep("add rooms", () => RoomManager.AddRooms(1));
|
||||
|
||||
AddAssert("selected room is not disabled", () => !OnlinePlayDependencies.SelectedRoom.Disabled);
|
||||
|
||||
AddStep("select room", () => roomsContainer.Rooms[0].TriggerClick());
|
||||
AddAssert("selected room is non-null", () => OnlinePlayDependencies.SelectedRoom.Value != null);
|
||||
|
||||
AddStep("enter room", () => roomsContainer.Rooms[0].TriggerClick());
|
||||
|
||||
AddUntilStep("wait for match load", () => Stack.CurrentScreen is PlaylistsRoomSubScreen);
|
||||
|
||||
AddAssert("selected room is non-null", () => OnlinePlayDependencies.SelectedRoom.Value != null);
|
||||
AddAssert("selected room is disabled", () => OnlinePlayDependencies.SelectedRoom.Disabled);
|
||||
}
|
||||
|
||||
private bool checkRoomVisible(DrawableRoom room) =>
|
||||
loungeScreen.ChildrenOfType<OsuScrollContainer>().First().ScreenSpaceDrawQuad
|
||||
.Contains(room.ScreenSpaceDrawQuad.Centre);
|
||||
|
@ -27,7 +27,7 @@ namespace osu.Game.Tests.Visual.Settings
|
||||
new TabletSettings(tabletHandler)
|
||||
{
|
||||
RelativeSizeAxes = Axes.None,
|
||||
Width = SettingsPanel.WIDTH,
|
||||
Width = SettingsPanel.PANEL_WIDTH,
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
}
|
||||
|
@ -1,8 +1,10 @@
|
||||
// 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.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
@ -174,6 +176,60 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
checkBindableAtValue("Circle Size", null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestModSettingChangeTracker()
|
||||
{
|
||||
ModSettingChangeTracker tracker = null;
|
||||
Queue<Mod> settingsChangedQueue = null;
|
||||
|
||||
setBeatmapWithDifficultyParameters(5);
|
||||
|
||||
AddStep("add mod settings change tracker", () =>
|
||||
{
|
||||
settingsChangedQueue = new Queue<Mod>();
|
||||
|
||||
tracker = new ModSettingChangeTracker(modDifficultyAdjust.Yield())
|
||||
{
|
||||
SettingChanged = settingsChangedQueue.Enqueue
|
||||
};
|
||||
});
|
||||
|
||||
AddAssert("no settings changed", () => settingsChangedQueue.Count == 0);
|
||||
|
||||
setSliderValue("Circle Size", 3);
|
||||
|
||||
settingsChangedFired();
|
||||
|
||||
setSliderValue("Circle Size", 5);
|
||||
checkBindableAtValue("Circle Size", 5);
|
||||
|
||||
settingsChangedFired();
|
||||
|
||||
AddStep("reset mod settings", () => modDifficultyAdjust.CircleSize.SetDefault());
|
||||
checkBindableAtValue("Circle Size", null);
|
||||
|
||||
settingsChangedFired();
|
||||
|
||||
setExtendedLimits(true);
|
||||
|
||||
settingsChangedFired();
|
||||
|
||||
AddStep("dispose tracker", () =>
|
||||
{
|
||||
tracker.Dispose();
|
||||
tracker = null;
|
||||
});
|
||||
|
||||
void settingsChangedFired()
|
||||
{
|
||||
AddAssert("setting changed event fired", () =>
|
||||
{
|
||||
settingsChangedQueue.Dequeue();
|
||||
return settingsChangedQueue.Count == 0;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void resetToDefault(string name)
|
||||
{
|
||||
AddStep($"Reset {name} to default", () =>
|
||||
|
@ -53,7 +53,7 @@ namespace osu.Game.Tests
|
||||
|
||||
protected override Waveform GetWaveform() => new Waveform(trackStore.GetStream(firstAudioFile));
|
||||
|
||||
protected override ISkin GetSkin() => null;
|
||||
protected internal override ISkin GetSkin() => null;
|
||||
|
||||
public override Stream GetStream(string storagePath) => null;
|
||||
|
||||
|
@ -534,7 +534,7 @@ namespace osu.Game.Beatmaps
|
||||
protected override IBeatmap GetBeatmap() => beatmap;
|
||||
protected override Texture GetBackground() => null;
|
||||
protected override Track GetBeatmapTrack() => null;
|
||||
protected override ISkin GetSkin() => null;
|
||||
protected internal override ISkin GetSkin() => null;
|
||||
public override Stream GetStream(string storagePath) => null;
|
||||
}
|
||||
}
|
||||
|
@ -128,7 +128,7 @@ namespace osu.Game.Beatmaps
|
||||
return storyboard;
|
||||
}
|
||||
|
||||
protected override ISkin GetSkin()
|
||||
protected internal override ISkin GetSkin()
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -50,7 +50,7 @@ namespace osu.Game.Beatmaps
|
||||
|
||||
protected override Track GetBeatmapTrack() => GetVirtualTrack();
|
||||
|
||||
protected override ISkin GetSkin() => null;
|
||||
protected internal override ISkin GetSkin() => null;
|
||||
|
||||
public override Stream GetStream(string storagePath) => null;
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using osuTK.Graphics;
|
||||
|
||||
@ -13,9 +14,17 @@ namespace osu.Game.Beatmaps.Formats
|
||||
/// </summary>
|
||||
IReadOnlyList<Color4> ComboColours { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The list of custom combo colours.
|
||||
/// If non-empty, <see cref="ComboColours"/> will return these colours;
|
||||
/// if empty, <see cref="ComboColours"/> will fall back to default combo colours.
|
||||
/// </summary>
|
||||
List<Color4> CustomComboColours { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Adds combo colours to the list.
|
||||
/// </summary>
|
||||
[Obsolete("Use CustomComboColours directly.")] // can be removed 20220215
|
||||
void AddComboColours(params Color4[] colours);
|
||||
}
|
||||
}
|
||||
|
@ -123,7 +123,7 @@ namespace osu.Game.Beatmaps.Formats
|
||||
{
|
||||
if (!(output is IHasComboColours tHasComboColours)) return;
|
||||
|
||||
tHasComboColours.AddComboColours(colour);
|
||||
tHasComboColours.CustomComboColours.Add(colour);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -327,7 +327,15 @@ namespace osu.Game.Beatmaps
|
||||
public bool SkinLoaded => skin.IsResultAvailable;
|
||||
public ISkin Skin => skin.Value;
|
||||
|
||||
protected abstract ISkin GetSkin();
|
||||
/// <summary>
|
||||
/// Creates a new skin instance for this beatmap.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This should only be called externally in scenarios where it is explicitly desired to get a new instance of a skin
|
||||
/// (e.g. for editing purposes, to avoid state pollution).
|
||||
/// For standard reading purposes, <see cref="Skin"/> should always be used directly.
|
||||
/// </remarks>
|
||||
protected internal abstract ISkin GetSkin();
|
||||
|
||||
private readonly RecyclableLazy<ISkin> skin;
|
||||
|
||||
|
@ -201,6 +201,8 @@ namespace osu.Game.Configuration
|
||||
public Func<GlobalAction, string> LookupKeyBindings { get; set; }
|
||||
}
|
||||
|
||||
// IMPORTANT: These are used in user configuration files.
|
||||
// The naming of these keys should not be changed once they are deployed in a release, unless migration logic is also added.
|
||||
public enum OsuSetting
|
||||
{
|
||||
Ruleset,
|
||||
|
64
osu.Game/Localisation/AudioSettingsStrings.cs
Normal file
64
osu.Game/Localisation/AudioSettingsStrings.cs
Normal file
@ -0,0 +1,64 @@
|
||||
// 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.Localisation;
|
||||
|
||||
namespace osu.Game.Localisation
|
||||
{
|
||||
public static class AudioSettingsStrings
|
||||
{
|
||||
private const string prefix = @"osu.Game.Resources.Localisation.AudioSettings";
|
||||
|
||||
/// <summary>
|
||||
/// "Audio"
|
||||
/// </summary>
|
||||
public static LocalisableString AudioSectionHeader => new TranslatableString(getKey(@"audio_section_header"), @"Audio");
|
||||
|
||||
/// <summary>
|
||||
/// "Devices"
|
||||
/// </summary>
|
||||
public static LocalisableString AudioDevicesHeader => new TranslatableString(getKey(@"audio_devices_header"), @"Devices");
|
||||
|
||||
/// <summary>
|
||||
/// "Volume"
|
||||
/// </summary>
|
||||
public static LocalisableString VolumeHeader => new TranslatableString(getKey(@"volume_header"), @"Volume");
|
||||
|
||||
/// <summary>
|
||||
/// "Master"
|
||||
/// </summary>
|
||||
public static LocalisableString MasterVolume => new TranslatableString(getKey(@"master_volume"), @"Master");
|
||||
|
||||
/// <summary>
|
||||
/// "Master (window inactive)"
|
||||
/// </summary>
|
||||
public static LocalisableString MasterVolumeInactive => new TranslatableString(getKey(@"master_volume_inactive"), @"Master (window inactive)");
|
||||
|
||||
/// <summary>
|
||||
/// "Effect"
|
||||
/// </summary>
|
||||
public static LocalisableString EffectVolume => new TranslatableString(getKey(@"effect_volume"), @"Effect");
|
||||
|
||||
/// <summary>
|
||||
/// "Music"
|
||||
/// </summary>
|
||||
public static LocalisableString MusicVolume => new TranslatableString(getKey(@"music_volume"), @"Music");
|
||||
|
||||
/// <summary>
|
||||
/// "Offset Adjustment"
|
||||
/// </summary>
|
||||
public static LocalisableString OffsetHeader => new TranslatableString(getKey(@"offset_header"), @"Offset Adjustment");
|
||||
|
||||
/// <summary>
|
||||
/// "Audio offset"
|
||||
/// </summary>
|
||||
public static LocalisableString AudioOffset => new TranslatableString(getKey(@"audio_offset"), @"Audio offset");
|
||||
|
||||
/// <summary>
|
||||
/// "Offset wizard"
|
||||
/// </summary>
|
||||
public static LocalisableString OffsetWizard => new TranslatableString(getKey(@"offset_wizard"), @"Offset wizard");
|
||||
|
||||
private static string getKey(string key) => $"{prefix}:{key}";
|
||||
}
|
||||
}
|
@ -14,11 +14,21 @@ namespace osu.Game.Localisation
|
||||
/// </summary>
|
||||
public static LocalisableString Cancel => new TranslatableString(getKey(@"cancel"), @"Cancel");
|
||||
|
||||
/// <summary>
|
||||
/// "Clear"
|
||||
/// </summary>
|
||||
public static LocalisableString Clear => new TranslatableString(getKey(@"clear"), @"Clear");
|
||||
|
||||
/// <summary>
|
||||
/// "Enabled"
|
||||
/// </summary>
|
||||
public static LocalisableString Enabled => new TranslatableString(getKey(@"enabled"), @"Enabled");
|
||||
|
||||
/// <summary>
|
||||
/// "Default"
|
||||
/// </summary>
|
||||
public static LocalisableString Default => new TranslatableString(getKey(@"default"), @"Default");
|
||||
|
||||
/// <summary>
|
||||
/// "Width"
|
||||
/// </summary>
|
||||
@ -31,4 +41,4 @@ namespace osu.Game.Localisation
|
||||
|
||||
private static string getKey(string key) => $@"{prefix}:{key}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
49
osu.Game/Localisation/DebugSettingsStrings.cs
Normal file
49
osu.Game/Localisation/DebugSettingsStrings.cs
Normal file
@ -0,0 +1,49 @@
|
||||
// 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.Localisation;
|
||||
|
||||
namespace osu.Game.Localisation
|
||||
{
|
||||
public static class DebugSettingsStrings
|
||||
{
|
||||
private const string prefix = @"osu.Game.Resources.Localisation.DebugSettings";
|
||||
|
||||
/// <summary>
|
||||
/// "Debug"
|
||||
/// </summary>
|
||||
public static LocalisableString DebugSectionHeader => new TranslatableString(getKey(@"debug_section_header"), @"Debug");
|
||||
|
||||
/// <summary>
|
||||
/// "General"
|
||||
/// </summary>
|
||||
public static LocalisableString GeneralHeader => new TranslatableString(getKey(@"general_header"), @"General");
|
||||
|
||||
/// <summary>
|
||||
/// "Show log overlay"
|
||||
/// </summary>
|
||||
public static LocalisableString ShowLogOverlay => new TranslatableString(getKey(@"show_log_overlay"), @"Show log overlay");
|
||||
|
||||
/// <summary>
|
||||
/// "Bypass front-to-back render pass"
|
||||
/// </summary>
|
||||
public static LocalisableString BypassFrontToBackPass => new TranslatableString(getKey(@"bypass_front_to_back_pass"), @"Bypass front-to-back render pass");
|
||||
|
||||
/// <summary>
|
||||
/// "Import files"
|
||||
/// </summary>
|
||||
public static LocalisableString ImportFiles => new TranslatableString(getKey(@"import_files"), @"Import files");
|
||||
|
||||
/// <summary>
|
||||
/// "Memory"
|
||||
/// </summary>
|
||||
public static LocalisableString MemoryHeader => new TranslatableString(getKey(@"memory_header"), @"Memory");
|
||||
|
||||
/// <summary>
|
||||
/// "Clear all caches"
|
||||
/// </summary>
|
||||
public static LocalisableString ClearAllCaches => new TranslatableString(getKey(@"clear_all_caches"), @"Clear all caches");
|
||||
|
||||
private static string getKey(string key) => $"{prefix}:{key}";
|
||||
}
|
||||
}
|
94
osu.Game/Localisation/GameplaySettingsStrings.cs
Normal file
94
osu.Game/Localisation/GameplaySettingsStrings.cs
Normal file
@ -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 osu.Framework.Localisation;
|
||||
|
||||
namespace osu.Game.Localisation
|
||||
{
|
||||
public static class GameplaySettingsStrings
|
||||
{
|
||||
private const string prefix = @"osu.Game.Resources.Localisation.GameplaySettings";
|
||||
|
||||
/// <summary>
|
||||
/// "Gameplay"
|
||||
/// </summary>
|
||||
public static LocalisableString GameplaySectionHeader => new TranslatableString(getKey(@"gameplay_section_header"), @"Gameplay");
|
||||
|
||||
/// <summary>
|
||||
/// "General"
|
||||
/// </summary>
|
||||
public static LocalisableString GeneralHeader => new TranslatableString(getKey(@"general_header"), @"General");
|
||||
|
||||
/// <summary>
|
||||
/// "Background dim"
|
||||
/// </summary>
|
||||
public static LocalisableString BackgroundDim => new TranslatableString(getKey(@"dim"), @"Background dim");
|
||||
|
||||
/// <summary>
|
||||
/// "Background blur"
|
||||
/// </summary>
|
||||
public static LocalisableString BackgroundBlur => new TranslatableString(getKey(@"blur"), @"Background blur");
|
||||
|
||||
/// <summary>
|
||||
/// "Lighten playfield during breaks"
|
||||
/// </summary>
|
||||
public static LocalisableString LightenDuringBreaks => new TranslatableString(getKey(@"lighten_during_breaks"), @"Lighten playfield during breaks");
|
||||
|
||||
/// <summary>
|
||||
/// "HUD overlay visibility mode"
|
||||
/// </summary>
|
||||
public static LocalisableString HUDVisibilityMode => new TranslatableString(getKey(@"hud_visibility_mode"), @"HUD overlay visibility mode");
|
||||
|
||||
/// <summary>
|
||||
/// "Show difficulty graph on progress bar"
|
||||
/// </summary>
|
||||
public static LocalisableString ShowDifficultyGraph => new TranslatableString(getKey(@"show_difficulty_graph"), @"Show difficulty graph on progress bar");
|
||||
|
||||
/// <summary>
|
||||
/// "Show health display even when you can't fail"
|
||||
/// </summary>
|
||||
public static LocalisableString ShowHealthDisplayWhenCantFail => new TranslatableString(getKey(@"show_health_display_when_cant_fail"), @"Show health display even when you can't fail");
|
||||
|
||||
/// <summary>
|
||||
/// "Fade playfield to red when health is low"
|
||||
/// </summary>
|
||||
public static LocalisableString FadePlayfieldWhenHealthLow => new TranslatableString(getKey(@"fade_playfield_when_health_low"), @"Fade playfield to red when health is low");
|
||||
|
||||
/// <summary>
|
||||
/// "Always show key overlay"
|
||||
/// </summary>
|
||||
public static LocalisableString AlwaysShowKeyOverlay => new TranslatableString(getKey(@"key_overlay"), @"Always show key overlay");
|
||||
|
||||
/// <summary>
|
||||
/// "Positional hitsounds"
|
||||
/// </summary>
|
||||
public static LocalisableString PositionalHitsounds => new TranslatableString(getKey(@"positional_hitsounds"), @"Positional hitsounds");
|
||||
|
||||
/// <summary>
|
||||
/// "Always play first combo break sound"
|
||||
/// </summary>
|
||||
public static LocalisableString AlwaysPlayFirstComboBreak => new TranslatableString(getKey(@"always_play_first_combo_break"), @"Always play first combo break sound");
|
||||
|
||||
/// <summary>
|
||||
/// "Score display mode"
|
||||
/// </summary>
|
||||
public static LocalisableString ScoreDisplayMode => new TranslatableString(getKey(@"score_display_mode"), @"Score display mode");
|
||||
|
||||
/// <summary>
|
||||
/// "Disable Windows key during gameplay"
|
||||
/// </summary>
|
||||
public static LocalisableString DisableWinKey => new TranslatableString(getKey(@"disable_win_key"), @"Disable Windows key during gameplay");
|
||||
|
||||
/// <summary>
|
||||
/// "Mods"
|
||||
/// </summary>
|
||||
public static LocalisableString ModsHeader => new TranslatableString(getKey(@"mods_header"), @"Mods");
|
||||
|
||||
/// <summary>
|
||||
/// "Increase visibility of first object when visual impairment mods are enabled"
|
||||
/// </summary>
|
||||
public static LocalisableString IncreaseFirstObjectVisibility => new TranslatableString(getKey(@"increase_first_object_visibility"), @"Increase visibility of first object when visual impairment mods are enabled");
|
||||
|
||||
private static string getKey(string key) => $"{prefix}:{key}";
|
||||
}
|
||||
}
|
59
osu.Game/Localisation/GeneralSettingsStrings.cs
Normal file
59
osu.Game/Localisation/GeneralSettingsStrings.cs
Normal file
@ -0,0 +1,59 @@
|
||||
// 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.Localisation;
|
||||
|
||||
namespace osu.Game.Localisation
|
||||
{
|
||||
public static class GeneralSettingsStrings
|
||||
{
|
||||
private const string prefix = @"osu.Game.Resources.Localisation.GeneralSettings";
|
||||
|
||||
/// <summary>
|
||||
/// "General"
|
||||
/// </summary>
|
||||
public static LocalisableString GeneralSectionHeader => new TranslatableString(getKey(@"general_section_header"), @"General");
|
||||
|
||||
/// <summary>
|
||||
/// "Language"
|
||||
/// </summary>
|
||||
public static LocalisableString LanguageHeader => new TranslatableString(getKey(@"language_header"), @"Language");
|
||||
|
||||
/// <summary>
|
||||
/// "Language"
|
||||
/// </summary>
|
||||
public static LocalisableString LanguageDropdown => new TranslatableString(getKey(@"language_dropdown"), @"Language");
|
||||
|
||||
/// <summary>
|
||||
/// "Prefer metadata in original language"
|
||||
/// </summary>
|
||||
public static LocalisableString PreferOriginalMetadataLanguage => new TranslatableString(getKey(@"prefer_original"), @"Prefer metadata in original language");
|
||||
|
||||
/// <summary>
|
||||
/// "Updates"
|
||||
/// </summary>
|
||||
public static LocalisableString UpdateHeader => new TranslatableString(getKey(@"update_header"), @"Updates");
|
||||
|
||||
/// <summary>
|
||||
/// "Release stream"
|
||||
/// </summary>
|
||||
public static LocalisableString ReleaseStream => new TranslatableString(getKey(@"release_stream"), @"Release stream");
|
||||
|
||||
/// <summary>
|
||||
/// "Check for updates"
|
||||
/// </summary>
|
||||
public static LocalisableString CheckUpdate => new TranslatableString(getKey(@"check_update"), @"Check for updates");
|
||||
|
||||
/// <summary>
|
||||
/// "Open osu! folder"
|
||||
/// </summary>
|
||||
public static LocalisableString OpenOsuFolder => new TranslatableString(getKey(@"open_osu_folder"), @"Open osu! folder");
|
||||
|
||||
/// <summary>
|
||||
/// "Change folder location..."
|
||||
/// </summary>
|
||||
public static LocalisableString ChangeFolderLocation => new TranslatableString(getKey(@"change_folder_location"), @"Change folder location...");
|
||||
|
||||
private static string getKey(string key) => $"{prefix}:{key}";
|
||||
}
|
||||
}
|
119
osu.Game/Localisation/GraphicsSettingsStrings.cs
Normal file
119
osu.Game/Localisation/GraphicsSettingsStrings.cs
Normal file
@ -0,0 +1,119 @@
|
||||
// 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.Localisation;
|
||||
|
||||
namespace osu.Game.Localisation
|
||||
{
|
||||
public static class GraphicsSettingsStrings
|
||||
{
|
||||
private const string prefix = @"osu.Game.Resources.Localisation.GraphicsSettings";
|
||||
|
||||
/// <summary>
|
||||
/// "Graphics"
|
||||
/// </summary>
|
||||
public static LocalisableString GraphicsSectionHeader => new TranslatableString(getKey(@"graphics_section_header"), @"Graphics");
|
||||
|
||||
/// <summary>
|
||||
/// "Renderer"
|
||||
/// </summary>
|
||||
public static LocalisableString RendererHeader => new TranslatableString(getKey(@"renderer_header"), @"Renderer");
|
||||
|
||||
/// <summary>
|
||||
/// "Frame limiter"
|
||||
/// </summary>
|
||||
public static LocalisableString FrameLimiter => new TranslatableString(getKey(@"frame_limiter"), @"Frame limiter");
|
||||
|
||||
/// <summary>
|
||||
/// "Threading mode"
|
||||
/// </summary>
|
||||
public static LocalisableString ThreadingMode => new TranslatableString(getKey(@"threading_mode"), @"Threading mode");
|
||||
|
||||
/// <summary>
|
||||
/// "Show FPS"
|
||||
/// </summary>
|
||||
public static LocalisableString ShowFPS => new TranslatableString(getKey(@"show_fps"), @"Show FPS");
|
||||
|
||||
/// <summary>
|
||||
/// "Using unlimited frame limiter can lead to stutters, bad performance and overheating. It will not improve perceived latency. "2x refresh rate" is recommended."
|
||||
/// </summary>
|
||||
public static LocalisableString UnlimitedFramesNote => new TranslatableString(getKey(@"unlimited_frames_note"), @"Using unlimited frame limiter can lead to stutters, bad performance and overheating. It will not improve perceived latency. ""2x refresh rate"" is recommended.");
|
||||
|
||||
/// <summary>
|
||||
/// "Layout"
|
||||
/// </summary>
|
||||
public static LocalisableString LayoutHeader => new TranslatableString(getKey(@"layout_header"), @"Layout");
|
||||
|
||||
/// <summary>
|
||||
/// "Screen mode"
|
||||
/// </summary>
|
||||
public static LocalisableString ScreenMode => new TranslatableString(getKey(@"screen_mode"), @"Screen mode");
|
||||
|
||||
/// <summary>
|
||||
/// "Resolution"
|
||||
/// </summary>
|
||||
public static LocalisableString Resolution => new TranslatableString(getKey(@"resolution"), @"Resolution");
|
||||
|
||||
/// <summary>
|
||||
/// "UI scaling"
|
||||
/// </summary>
|
||||
public static LocalisableString UIScaling => new TranslatableString(getKey(@"ui_scaling"), @"UI scaling");
|
||||
|
||||
/// <summary>
|
||||
/// "Screen scaling"
|
||||
/// </summary>
|
||||
public static LocalisableString ScreenScaling => new TranslatableString(getKey(@"screen_scaling"), @"Screen scaling");
|
||||
|
||||
/// <summary>
|
||||
/// "Horizontal position"
|
||||
/// </summary>
|
||||
public static LocalisableString HorizontalPosition => new TranslatableString(getKey(@"horizontal_position"), @"Horizontal position");
|
||||
|
||||
/// <summary>
|
||||
/// "Vertical position"
|
||||
/// </summary>
|
||||
public static LocalisableString VerticalPosition => new TranslatableString(getKey(@"vertical_position"), @"Vertical position");
|
||||
|
||||
/// <summary>
|
||||
/// "Horizontal scale"
|
||||
/// </summary>
|
||||
public static LocalisableString HorizontalScale => new TranslatableString(getKey(@"horizontal_scale"), @"Horizontal scale");
|
||||
|
||||
/// <summary>
|
||||
/// "Vertical scale"
|
||||
/// </summary>
|
||||
public static LocalisableString VerticalScale => new TranslatableString(getKey(@"vertical_scale"), @"Vertical scale");
|
||||
|
||||
/// <summary>
|
||||
/// "Running without fullscreen mode will increase your input latency!"
|
||||
/// </summary>
|
||||
public static LocalisableString NotFullscreenNote => new TranslatableString(getKey(@"not_fullscreen_note"), @"Running without fullscreen mode will increase your input latency!");
|
||||
|
||||
/// <summary>
|
||||
/// "Detail Settings"
|
||||
/// </summary>
|
||||
public static LocalisableString DetailSettingsHeader => new TranslatableString(getKey(@"detail_settings_header"), @"Detail Settings");
|
||||
|
||||
/// <summary>
|
||||
/// "Storyboard / video"
|
||||
/// </summary>
|
||||
public static LocalisableString StoryboardVideo => new TranslatableString(getKey(@"storyboard_video"), @"Storyboard / video");
|
||||
|
||||
/// <summary>
|
||||
/// "Hit lighting"
|
||||
/// </summary>
|
||||
public static LocalisableString HitLighting => new TranslatableString(getKey(@"hit_lighting"), @"Hit lighting");
|
||||
|
||||
/// <summary>
|
||||
/// "Screenshot format"
|
||||
/// </summary>
|
||||
public static LocalisableString ScreenshotFormat => new TranslatableString(getKey(@"screenshot_format"), @"Screenshot format");
|
||||
|
||||
/// <summary>
|
||||
/// "Show menu cursor in screenshots"
|
||||
/// </summary>
|
||||
public static LocalisableString ShowCursorInScreenshots => new TranslatableString(getKey(@"show_cursor_in_screenshots"), @"Show menu cursor in screenshots");
|
||||
|
||||
private static string getKey(string key) => $"{prefix}:{key}";
|
||||
}
|
||||
}
|
59
osu.Game/Localisation/InputSettingsStrings.cs
Normal file
59
osu.Game/Localisation/InputSettingsStrings.cs
Normal file
@ -0,0 +1,59 @@
|
||||
// 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.Localisation;
|
||||
|
||||
namespace osu.Game.Localisation
|
||||
{
|
||||
public static class InputSettingsStrings
|
||||
{
|
||||
private const string prefix = @"osu.Game.Resources.Localisation.InputSettings";
|
||||
|
||||
/// <summary>
|
||||
/// "Input"
|
||||
/// </summary>
|
||||
public static LocalisableString InputSectionHeader => new TranslatableString(getKey(@"input_section_header"), @"Input");
|
||||
|
||||
/// <summary>
|
||||
/// "Global"
|
||||
/// </summary>
|
||||
public static LocalisableString GlobalKeyBindingHeader => new TranslatableString(getKey(@"global_key_binding_header"), @"Global");
|
||||
|
||||
/// <summary>
|
||||
/// "Song Select"
|
||||
/// </summary>
|
||||
public static LocalisableString SongSelectSection => new TranslatableString(getKey(@"song_select_section"), @"Song Select");
|
||||
|
||||
/// <summary>
|
||||
/// "In Game"
|
||||
/// </summary>
|
||||
public static LocalisableString InGameSection => new TranslatableString(getKey(@"in_game_section"), @"In Game");
|
||||
|
||||
/// <summary>
|
||||
/// "Audio"
|
||||
/// </summary>
|
||||
public static LocalisableString AudioSection => new TranslatableString(getKey(@"audio_section"), @"Audio");
|
||||
|
||||
/// <summary>
|
||||
/// "Editor"
|
||||
/// </summary>
|
||||
public static LocalisableString EditorSection => new TranslatableString(getKey(@"editor_section"), @"Editor");
|
||||
|
||||
/// <summary>
|
||||
/// "Reset all bindings in section"
|
||||
/// </summary>
|
||||
public static LocalisableString ResetSectionButton => new TranslatableString(getKey(@"reset_section_button"), @"Reset all bindings in section");
|
||||
|
||||
/// <summary>
|
||||
/// "key configuration"
|
||||
/// </summary>
|
||||
public static LocalisableString KeyBindingPanelHeader => new TranslatableString(getKey(@"key_binding_panel_header"), @"key configuration");
|
||||
|
||||
/// <summary>
|
||||
/// "Customise your keys!"
|
||||
/// </summary>
|
||||
public static LocalisableString KeyBindingPanelDescription => new TranslatableString(getKey(@"key_binding_panel_description"), @"Customise your keys!");
|
||||
|
||||
private static string getKey(string key) => $"{prefix}:{key}";
|
||||
}
|
||||
}
|
74
osu.Game/Localisation/MaintenanceSettingsStrings.cs
Normal file
74
osu.Game/Localisation/MaintenanceSettingsStrings.cs
Normal file
@ -0,0 +1,74 @@
|
||||
// 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.Localisation;
|
||||
|
||||
namespace osu.Game.Localisation
|
||||
{
|
||||
public static class MaintenanceSettingsStrings
|
||||
{
|
||||
private const string prefix = @"osu.Game.Resources.Localisation.MaintenanceSettings";
|
||||
|
||||
/// <summary>
|
||||
/// "Maintenance"
|
||||
/// </summary>
|
||||
public static LocalisableString MaintenanceSectionHeader => new TranslatableString(getKey(@"maintenance_section_header"), @"Maintenance");
|
||||
|
||||
/// <summary>
|
||||
/// "Select directory"
|
||||
/// </summary>
|
||||
public static LocalisableString SelectDirectory => new TranslatableString(getKey(@"select_directory"), @"Select directory");
|
||||
|
||||
/// <summary>
|
||||
/// "Import beatmaps from stable"
|
||||
/// </summary>
|
||||
public static LocalisableString ImportBeatmapsFromStable => new TranslatableString(getKey(@"import_beatmaps_from_stable"), @"Import beatmaps from stable");
|
||||
|
||||
/// <summary>
|
||||
/// "Delete ALL beatmaps"
|
||||
/// </summary>
|
||||
public static LocalisableString DeleteAllBeatmaps => new TranslatableString(getKey(@"delete_all_beatmaps"), @"Delete ALL beatmaps");
|
||||
|
||||
/// <summary>
|
||||
/// "Import scores from stable"
|
||||
/// </summary>
|
||||
public static LocalisableString ImportScoresFromStable => new TranslatableString(getKey(@"import_scores_from_stable"), @"Import scores from stable");
|
||||
|
||||
/// <summary>
|
||||
/// "Delete ALL scores"
|
||||
/// </summary>
|
||||
public static LocalisableString DeleteAllScores => new TranslatableString(getKey(@"delete_all_scores"), @"Delete ALL scores");
|
||||
|
||||
/// <summary>
|
||||
/// "Import skins from stable"
|
||||
/// </summary>
|
||||
public static LocalisableString ImportSkinsFromStable => new TranslatableString(getKey(@"import_skins_from_stable"), @"Import skins from stable");
|
||||
|
||||
/// <summary>
|
||||
/// "Delete ALL skins"
|
||||
/// </summary>
|
||||
public static LocalisableString DeleteAllSkins => new TranslatableString(getKey(@"delete_all_skins"), @"Delete ALL skins");
|
||||
|
||||
/// <summary>
|
||||
/// "Import collections from stable"
|
||||
/// </summary>
|
||||
public static LocalisableString ImportCollectionsFromStable => new TranslatableString(getKey(@"import_collections_from_stable"), @"Import collections from stable");
|
||||
|
||||
/// <summary>
|
||||
/// "Delete ALL collections"
|
||||
/// </summary>
|
||||
public static LocalisableString DeleteAllCollections => new TranslatableString(getKey(@"delete_all_collections"), @"Delete ALL collections");
|
||||
|
||||
/// <summary>
|
||||
/// "Restore all hidden difficulties"
|
||||
/// </summary>
|
||||
public static LocalisableString RestoreAllHiddenDifficulties => new TranslatableString(getKey(@"restore_all_hidden_difficulties"), @"Restore all hidden difficulties");
|
||||
|
||||
/// <summary>
|
||||
/// "Restore all recently deleted beatmaps"
|
||||
/// </summary>
|
||||
public static LocalisableString RestoreAllRecentlyDeletedBeatmaps => new TranslatableString(getKey(@"restore_all_recently_deleted_beatmaps"), @"Restore all recently deleted beatmaps");
|
||||
|
||||
private static string getKey(string key) => $"{prefix}:{key}";
|
||||
}
|
||||
}
|
24
osu.Game/Localisation/MultiplayerTeamResultsScreenStrings.cs
Normal file
24
osu.Game/Localisation/MultiplayerTeamResultsScreenStrings.cs
Normal file
@ -0,0 +1,24 @@
|
||||
// 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.Localisation;
|
||||
|
||||
namespace osu.Game.Localisation
|
||||
{
|
||||
public static class MultiplayerTeamResultsScreenStrings
|
||||
{
|
||||
private const string prefix = @"osu.Game.Resources.Localisation.MultiplayerTeamResultsScreen";
|
||||
|
||||
/// <summary>
|
||||
/// "Team {0} wins!"
|
||||
/// </summary>
|
||||
public static LocalisableString TeamWins(string winner) => new TranslatableString(getKey(@"team_wins"), @"Team {0} wins!", winner);
|
||||
|
||||
/// <summary>
|
||||
/// "The teams are tied!"
|
||||
/// </summary>
|
||||
public static LocalisableString TheTeamsAreTied => new TranslatableString(getKey(@"the_teams_are_tied"), @"The teams are tied!");
|
||||
|
||||
private static string getKey(string key) => $@"{prefix}:{key}";
|
||||
}
|
||||
}
|
69
osu.Game/Localisation/OnlineSettingsStrings.cs
Normal file
69
osu.Game/Localisation/OnlineSettingsStrings.cs
Normal file
@ -0,0 +1,69 @@
|
||||
// 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.Localisation;
|
||||
|
||||
namespace osu.Game.Localisation
|
||||
{
|
||||
public static class OnlineSettingsStrings
|
||||
{
|
||||
private const string prefix = @"osu.Game.Resources.Localisation.OnlineSettings";
|
||||
|
||||
/// <summary>
|
||||
/// "Online"
|
||||
/// </summary>
|
||||
public static LocalisableString OnlineSectionHeader => new TranslatableString(getKey(@"online_section_header"), @"Online");
|
||||
|
||||
/// <summary>
|
||||
/// "Alerts and Privacy"
|
||||
/// </summary>
|
||||
public static LocalisableString AlertsAndPrivacyHeader => new TranslatableString(getKey(@"alerts_and_privacy_header"), @"Alerts and Privacy");
|
||||
|
||||
/// <summary>
|
||||
/// "Show a notification when someone mentions your name"
|
||||
/// </summary>
|
||||
public static LocalisableString NotifyOnMentioned => new TranslatableString(getKey(@"notify_on_mentioned"), @"Show a notification when someone mentions your name");
|
||||
|
||||
/// <summary>
|
||||
/// "Show a notification when you receive a private message"
|
||||
/// </summary>
|
||||
public static LocalisableString NotifyOnPrivateMessage => new TranslatableString(getKey(@"notify_on_private_message"), @"Show a notification when you receive a private message");
|
||||
|
||||
/// <summary>
|
||||
/// "Integrations"
|
||||
/// </summary>
|
||||
public static LocalisableString IntegrationsHeader => new TranslatableString(getKey(@"integrations_header"), @"Integrations");
|
||||
|
||||
/// <summary>
|
||||
/// "Discord Rich Presence"
|
||||
/// </summary>
|
||||
public static LocalisableString DiscordRichPresence => new TranslatableString(getKey(@"discord_rich_presence"), @"Discord Rich Presence");
|
||||
|
||||
/// <summary>
|
||||
/// "Web"
|
||||
/// </summary>
|
||||
public static LocalisableString WebHeader => new TranslatableString(getKey(@"web_header"), @"Web");
|
||||
|
||||
/// <summary>
|
||||
/// "Warn about opening external links"
|
||||
/// </summary>
|
||||
public static LocalisableString ExternalLinkWarning => new TranslatableString(getKey(@"external_link_warning"), @"Warn about opening external links");
|
||||
|
||||
/// <summary>
|
||||
/// "Prefer downloads without video"
|
||||
/// </summary>
|
||||
public static LocalisableString PreferNoVideo => new TranslatableString(getKey(@"prefer_no_video"), @"Prefer downloads without video");
|
||||
|
||||
/// <summary>
|
||||
/// "Automatically download beatmaps when spectating"
|
||||
/// </summary>
|
||||
public static LocalisableString AutomaticallyDownloadWhenSpectating => new TranslatableString(getKey(@"automatically_download_when_spectating"), @"Automatically download beatmaps when spectating");
|
||||
|
||||
/// <summary>
|
||||
/// "Show explicit content in search results"
|
||||
/// </summary>
|
||||
public static LocalisableString ShowExplicitContent => new TranslatableString(getKey(@"show_explicit_content"), @"Show explicit content in search results");
|
||||
|
||||
private static string getKey(string key) => $"{prefix}:{key}";
|
||||
}
|
||||
}
|
54
osu.Game/Localisation/SkinSettingsStrings.cs
Normal file
54
osu.Game/Localisation/SkinSettingsStrings.cs
Normal file
@ -0,0 +1,54 @@
|
||||
// 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.Localisation;
|
||||
|
||||
namespace osu.Game.Localisation
|
||||
{
|
||||
public static class SkinSettingsStrings
|
||||
{
|
||||
private const string prefix = @"osu.Game.Resources.Localisation.SkinSettings";
|
||||
|
||||
/// <summary>
|
||||
/// "Skin"
|
||||
/// </summary>
|
||||
public static LocalisableString SkinSectionHeader => new TranslatableString(getKey(@"skin_section_header"), @"Skin");
|
||||
|
||||
/// <summary>
|
||||
/// "Skin layout editor"
|
||||
/// </summary>
|
||||
public static LocalisableString SkinLayoutEditor => new TranslatableString(getKey(@"skin_layout_editor"), @"Skin layout editor");
|
||||
|
||||
/// <summary>
|
||||
/// "Gameplay cursor size"
|
||||
/// </summary>
|
||||
public static LocalisableString GameplayCursorSize => new TranslatableString(getKey(@"gameplay_cursor_size"), @"Gameplay cursor size");
|
||||
|
||||
/// <summary>
|
||||
/// "Adjust gameplay cursor size based on current beatmap"
|
||||
/// </summary>
|
||||
public static LocalisableString AutoCursorSize => new TranslatableString(getKey(@"auto_cursor_size"), @"Adjust gameplay cursor size based on current beatmap");
|
||||
|
||||
/// <summary>
|
||||
/// "Beatmap skins"
|
||||
/// </summary>
|
||||
public static LocalisableString BeatmapSkins => new TranslatableString(getKey(@"beatmap_skins"), @"Beatmap skins");
|
||||
|
||||
/// <summary>
|
||||
/// "Beatmap colours"
|
||||
/// </summary>
|
||||
public static LocalisableString BeatmapColours => new TranslatableString(getKey(@"beatmap_colours"), @"Beatmap colours");
|
||||
|
||||
/// <summary>
|
||||
/// "Beatmap hitsounds"
|
||||
/// </summary>
|
||||
public static LocalisableString BeatmapHitsounds => new TranslatableString(getKey(@"beatmap_hitsounds"), @"Beatmap hitsounds");
|
||||
|
||||
/// <summary>
|
||||
/// "Export selected skin"
|
||||
/// </summary>
|
||||
public static LocalisableString ExportSkinButton => new TranslatableString(getKey(@"export_skin_button"), @"Export selected skin");
|
||||
|
||||
private static string getKey(string key) => $"{prefix}:{key}";
|
||||
}
|
||||
}
|
114
osu.Game/Localisation/UserInterfaceStrings.cs
Normal file
114
osu.Game/Localisation/UserInterfaceStrings.cs
Normal file
@ -0,0 +1,114 @@
|
||||
// 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.Localisation;
|
||||
|
||||
namespace osu.Game.Localisation
|
||||
{
|
||||
public static class UserInterfaceStrings
|
||||
{
|
||||
private const string prefix = @"osu.Game.Resources.Localisation.UserInterface";
|
||||
|
||||
/// <summary>
|
||||
/// "User Interface"
|
||||
/// </summary>
|
||||
public static LocalisableString UserInterfaceSectionHeader => new TranslatableString(getKey(@"user_interface_section_header"), @"User Interface");
|
||||
|
||||
/// <summary>
|
||||
/// "General"
|
||||
/// </summary>
|
||||
public static LocalisableString GeneralHeader => new TranslatableString(getKey(@"general_header"), @"General");
|
||||
|
||||
/// <summary>
|
||||
/// "Rotate cursor when dragging"
|
||||
/// </summary>
|
||||
public static LocalisableString CursorRotation => new TranslatableString(getKey(@"cursor_rotation"), @"Rotate cursor when dragging");
|
||||
|
||||
/// <summary>
|
||||
/// "Menu cursor size"
|
||||
/// </summary>
|
||||
public static LocalisableString MenuCursorSize => new TranslatableString(getKey(@"menu_cursor_size"), @"Menu cursor size");
|
||||
|
||||
/// <summary>
|
||||
/// "Parallax"
|
||||
/// </summary>
|
||||
public static LocalisableString Parallax => new TranslatableString(getKey(@"parallax"), @"Parallax");
|
||||
|
||||
/// <summary>
|
||||
/// "Hold-to-confirm activation time"
|
||||
/// </summary>
|
||||
public static LocalisableString HoldToConfirmActivationTime => new TranslatableString(getKey(@"hold_to_confirm_activation_time"), @"Hold-to-confirm activation time");
|
||||
|
||||
/// <summary>
|
||||
/// "Main Menu"
|
||||
/// </summary>
|
||||
public static LocalisableString MainMenuHeader => new TranslatableString(getKey(@"main_menu_header"), @"Main Menu");
|
||||
|
||||
/// <summary>
|
||||
/// "Interface voices"
|
||||
/// </summary>
|
||||
public static LocalisableString InterfaceVoices => new TranslatableString(getKey(@"interface_voices"), @"Interface voices");
|
||||
|
||||
/// <summary>
|
||||
/// "osu! music theme"
|
||||
/// </summary>
|
||||
public static LocalisableString OsuMusicTheme => new TranslatableString(getKey(@"osu_music_theme"), @"osu! music theme");
|
||||
|
||||
/// <summary>
|
||||
/// "Intro sequence"
|
||||
/// </summary>
|
||||
public static LocalisableString IntroSequence => new TranslatableString(getKey(@"intro_sequence"), @"Intro sequence");
|
||||
|
||||
/// <summary>
|
||||
/// "Background source"
|
||||
/// </summary>
|
||||
public static LocalisableString BackgroundSource => new TranslatableString(getKey(@"background_source"), @"Background source");
|
||||
|
||||
/// <summary>
|
||||
/// "Seasonal backgrounds"
|
||||
/// </summary>
|
||||
public static LocalisableString SeasonalBackgrounds => new TranslatableString(getKey(@"seasonal_backgrounds"), @"Seasonal backgrounds");
|
||||
|
||||
/// <summary>
|
||||
/// "Changes to this setting will only apply with an active osu!supporter tag."
|
||||
/// </summary>
|
||||
public static LocalisableString NotSupporterNote => new TranslatableString(getKey(@"not_supporter_note"), @"Changes to this setting will only apply with an active osu!supporter tag.");
|
||||
|
||||
/// <summary>
|
||||
/// "Song Select"
|
||||
/// </summary>
|
||||
public static LocalisableString SongSelectHeader => new TranslatableString(getKey(@"song_select_header"), @"Song Select");
|
||||
|
||||
/// <summary>
|
||||
/// "Right mouse drag to absolute scroll"
|
||||
/// </summary>
|
||||
public static LocalisableString RightMouseScroll => new TranslatableString(getKey(@"right_mouse_scroll"), @"Right mouse drag to absolute scroll");
|
||||
|
||||
/// <summary>
|
||||
/// "Show converted beatmaps"
|
||||
/// </summary>
|
||||
public static LocalisableString ShowConvertedBeatmaps => new TranslatableString(getKey(@"show_converted_beatmaps"), @"Show converted beatmaps");
|
||||
|
||||
/// <summary>
|
||||
/// "Display beatmaps from"
|
||||
/// </summary>
|
||||
public static LocalisableString StarsMinimum => new TranslatableString(getKey(@"stars_minimum"), @"Display beatmaps from");
|
||||
|
||||
/// <summary>
|
||||
/// "up to"
|
||||
/// </summary>
|
||||
public static LocalisableString StarsMaximum => new TranslatableString(getKey(@"stars_maximum"), @"up to");
|
||||
|
||||
/// <summary>
|
||||
/// "Random selection algorithm"
|
||||
/// </summary>
|
||||
public static LocalisableString RandomSelectionAlgorithm => new TranslatableString(getKey(@"random_selection_algorithm"), @"Random selection algorithm");
|
||||
|
||||
/// <summary>
|
||||
/// "no limit"
|
||||
/// </summary>
|
||||
public static LocalisableString NoLimit => new TranslatableString(getKey(@"no_limit"), @"no limit");
|
||||
|
||||
private static string getKey(string key) => $"{prefix}:{key}";
|
||||
}
|
||||
}
|
@ -9,16 +9,16 @@ namespace osu.Game.Online.API.Requests
|
||||
{
|
||||
public class MarkChannelAsReadRequest : APIRequest
|
||||
{
|
||||
private readonly Channel channel;
|
||||
private readonly Message message;
|
||||
public readonly Channel Channel;
|
||||
public readonly Message Message;
|
||||
|
||||
public MarkChannelAsReadRequest(Channel channel, Message message)
|
||||
{
|
||||
this.channel = channel;
|
||||
this.message = message;
|
||||
Channel = channel;
|
||||
Message = message;
|
||||
}
|
||||
|
||||
protected override string Target => $"chat/channels/{channel.Id}/mark-as-read/{message.Id}";
|
||||
protected override string Target => $"chat/channels/{Channel.Id}/mark-as-read/{Message.Id}";
|
||||
|
||||
protected override WebRequest CreateWebRequest()
|
||||
{
|
||||
|
@ -553,7 +553,7 @@ namespace osu.Game.Online.Chat
|
||||
if (channel.LastMessageId == channel.LastReadId)
|
||||
return;
|
||||
|
||||
var message = channel.Messages.LastOrDefault();
|
||||
var message = channel.Messages.FindLast(msg => !(msg is LocalMessage));
|
||||
|
||||
if (message == null)
|
||||
return;
|
||||
|
@ -31,6 +31,15 @@ namespace osu.Game.Online.Multiplayer
|
||||
/// <param name="user">The user.</param>
|
||||
Task UserLeft(MultiplayerRoomUser user);
|
||||
|
||||
/// <summary>
|
||||
/// Signals that a user has been kicked from the room.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This will also be sent to the user that was kicked.
|
||||
/// </remarks>
|
||||
/// <param name="user">The user.</param>
|
||||
Task UserKicked(MultiplayerRoomUser user);
|
||||
|
||||
/// <summary>
|
||||
/// Signal that the host of the room has changed.
|
||||
/// </summary>
|
||||
|
@ -389,6 +389,18 @@ namespace osu.Game.Online.Multiplayer
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
Task IMultiplayerClient.UserKicked(MultiplayerRoomUser user)
|
||||
{
|
||||
if (LocalUser == null)
|
||||
return Task.CompletedTask;
|
||||
|
||||
if (user.Equals(LocalUser))
|
||||
LeaveRoom();
|
||||
|
||||
// TODO: also inform users of the kick operation.
|
||||
return ((IMultiplayerClient)this).UserLeft(user);
|
||||
}
|
||||
|
||||
Task IMultiplayerClient.HostChanged(int userId)
|
||||
{
|
||||
if (Room == null)
|
||||
|
@ -50,6 +50,7 @@ namespace osu.Game.Online.Multiplayer
|
||||
connection.On<MultiplayerRoomState>(nameof(IMultiplayerClient.RoomStateChanged), ((IMultiplayerClient)this).RoomStateChanged);
|
||||
connection.On<MultiplayerRoomUser>(nameof(IMultiplayerClient.UserJoined), ((IMultiplayerClient)this).UserJoined);
|
||||
connection.On<MultiplayerRoomUser>(nameof(IMultiplayerClient.UserLeft), ((IMultiplayerClient)this).UserLeft);
|
||||
connection.On<MultiplayerRoomUser>(nameof(IMultiplayerClient.UserKicked), ((IMultiplayerClient)this).UserKicked);
|
||||
connection.On<int>(nameof(IMultiplayerClient.HostChanged), ((IMultiplayerClient)this).HostChanged);
|
||||
connection.On<MultiplayerRoomSettings>(nameof(IMultiplayerClient.SettingsChanged), ((IMultiplayerClient)this).SettingsChanged);
|
||||
connection.On<int, MultiplayerUserState>(nameof(IMultiplayerClient.UserStateChanged), ((IMultiplayerClient)this).UserStateChanged);
|
||||
|
@ -64,6 +64,11 @@ namespace osu.Game
|
||||
/// </summary>
|
||||
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;
|
||||
|
||||
private ChatOverlay chatOverlay;
|
||||
@ -71,7 +76,7 @@ namespace osu.Game
|
||||
private ChannelManager channelManager;
|
||||
|
||||
[NotNull]
|
||||
private readonly NotificationOverlay notifications = new NotificationOverlay();
|
||||
protected readonly NotificationOverlay Notifications = new NotificationOverlay();
|
||||
|
||||
private BeatmapListingOverlay beatmapListing;
|
||||
|
||||
@ -97,7 +102,7 @@ namespace osu.Game
|
||||
|
||||
private ScalingContainer screenContainer;
|
||||
|
||||
private Container screenOffsetContainer;
|
||||
protected Container ScreenOffsetContainer { get; private set; }
|
||||
|
||||
[Resolved]
|
||||
private FrameworkConfigManager frameworkConfig { get; set; }
|
||||
@ -312,7 +317,7 @@ namespace osu.Game
|
||||
case LinkAction.OpenEditorTimestamp:
|
||||
case LinkAction.JoinMultiplayerMatch:
|
||||
case LinkAction.Spectate:
|
||||
waitForReady(() => notifications, _ => notifications.Post(new SimpleNotification
|
||||
waitForReady(() => Notifications, _ => Notifications.Post(new SimpleNotification
|
||||
{
|
||||
Text = @"This link type is not yet supported!",
|
||||
Icon = FontAwesome.Solid.LifeRing,
|
||||
@ -611,12 +616,12 @@ namespace osu.Game
|
||||
MenuCursorContainer.CanShowCursor = menuScreen?.CursorVisible ?? false;
|
||||
|
||||
// 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());
|
||||
|
||||
ScoreManager.PostNotification = n => notifications.Post(n);
|
||||
ScoreManager.PostNotification = n => Notifications.Post(n);
|
||||
ScoreManager.PresentImport = items => PresentScore(items.First());
|
||||
|
||||
// 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),
|
||||
ScrollActionRequested = (action, amount, isPrecise) => volume.Adjust(action, amount, isPrecise),
|
||||
},
|
||||
screenOffsetContainer = new Container
|
||||
ScreenOffsetContainer = new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Children = new Drawable[]
|
||||
@ -724,7 +729,7 @@ namespace osu.Game
|
||||
|
||||
loadComponentSingleFile(onScreenDisplay, Add, true);
|
||||
|
||||
loadComponentSingleFile(notifications.With(d =>
|
||||
loadComponentSingleFile(Notifications.With(d =>
|
||||
{
|
||||
d.GetToolbarHeight = () => ToolbarOffset;
|
||||
d.Anchor = Anchor.TopRight;
|
||||
@ -733,7 +738,7 @@ namespace osu.Game
|
||||
|
||||
loadComponentSingleFile(new CollectionManager(Storage)
|
||||
{
|
||||
PostNotification = n => notifications.Post(n),
|
||||
PostNotification = n => Notifications.Post(n),
|
||||
}, Add, true);
|
||||
|
||||
loadComponentSingleFile(stableImportManager, Add);
|
||||
@ -785,7 +790,7 @@ namespace osu.Game
|
||||
Add(new MusicKeyBindingHandler());
|
||||
|
||||
// side overlays which cancel each other.
|
||||
var singleDisplaySideOverlays = new OverlayContainer[] { Settings, notifications };
|
||||
var singleDisplaySideOverlays = new OverlayContainer[] { Settings, Notifications };
|
||||
|
||||
foreach (var overlay in singleDisplaySideOverlays)
|
||||
{
|
||||
@ -828,21 +833,6 @@ namespace osu.Game
|
||||
{
|
||||
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)
|
||||
@ -874,7 +864,7 @@ namespace osu.Game
|
||||
|
||||
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,
|
||||
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)
|
||||
{
|
||||
Schedule(() => notifications.Post(new SimpleNotification
|
||||
Schedule(() => Notifications.Post(new SimpleNotification
|
||||
{
|
||||
Icon = FontAwesome.Solid.EllipsisH,
|
||||
Text = "Subsequent messages have been logged. Click to view log files.",
|
||||
@ -1023,9 +1013,18 @@ namespace osu.Game
|
||||
{
|
||||
base.UpdateAfterChildren();
|
||||
|
||||
screenOffsetContainer.Padding = new MarginPadding { Top = ToolbarOffset };
|
||||
ScreenOffsetContainer.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;
|
||||
}
|
||||
|
||||
|
@ -139,19 +139,24 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
|
||||
|
||||
LoadComponentAsync(Preview = previewTrackManager.Get(beatmapSet), preview =>
|
||||
{
|
||||
// beatmapset may have changed.
|
||||
if (Preview != preview)
|
||||
return;
|
||||
// Make sure that we schedule to after the next audio frame to fix crashes in single-threaded execution.
|
||||
// See: https://github.com/ppy/osu-framework/issues/4692
|
||||
Schedule(() =>
|
||||
{
|
||||
// beatmapset may have changed.
|
||||
if (Preview != preview)
|
||||
return;
|
||||
|
||||
AddInternal(preview);
|
||||
loading = false;
|
||||
// make sure that the update of value of Playing (and the ensuing value change callbacks)
|
||||
// are marshaled back to the update thread.
|
||||
preview.Stopped += () => Schedule(() => playing.Value = false);
|
||||
AddInternal(preview);
|
||||
loading = false;
|
||||
// make sure that the update of value of Playing (and the ensuing value change callbacks)
|
||||
// are marshaled back to the update thread.
|
||||
preview.Stopped += () => Schedule(() => playing.Value = false);
|
||||
|
||||
// user may have changed their mind.
|
||||
if (playing.Value)
|
||||
attemptStart();
|
||||
// user may have changed their mind.
|
||||
if (playing.Value)
|
||||
attemptStart();
|
||||
});
|
||||
});
|
||||
}
|
||||
else
|
||||
|
@ -78,10 +78,10 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
Direction = FillDirection.Horizontal,
|
||||
Children = new[]
|
||||
{
|
||||
length = new Statistic(FontAwesome.Regular.Clock, "Length") { Width = 0.25f },
|
||||
bpm = new Statistic(FontAwesome.Regular.Circle, "BPM") { Width = 0.25f },
|
||||
circleCount = new Statistic(FontAwesome.Regular.Circle, "Circle Count") { Width = 0.25f },
|
||||
sliderCount = new Statistic(FontAwesome.Regular.Circle, "Slider Count") { Width = 0.25f },
|
||||
length = new Statistic(BeatmapStatisticsIconType.Length, "Length") { Width = 0.25f },
|
||||
bpm = new Statistic(BeatmapStatisticsIconType.Bpm, "BPM") { Width = 0.25f },
|
||||
circleCount = new Statistic(BeatmapStatisticsIconType.Circles, "Circle Count") { Width = 0.25f },
|
||||
sliderCount = new Statistic(BeatmapStatisticsIconType.Sliders, "Slider Count") { Width = 0.25f },
|
||||
},
|
||||
};
|
||||
}
|
||||
@ -104,7 +104,7 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
set => this.value.Text = value;
|
||||
}
|
||||
|
||||
public Statistic(IconUsage icon, string name)
|
||||
public Statistic(BeatmapStatisticsIconType icon, string name)
|
||||
{
|
||||
TooltipText = name;
|
||||
RelativeSizeAxes = Axes.X;
|
||||
@ -133,8 +133,16 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.Centre,
|
||||
Icon = icon,
|
||||
Size = new Vector2(12),
|
||||
Icon = FontAwesome.Regular.Circle,
|
||||
Size = new Vector2(10),
|
||||
Rotation = 0,
|
||||
Colour = Color4Extensions.FromHex(@"f7dd55"),
|
||||
},
|
||||
new BeatmapStatisticIcon(icon)
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.Centre,
|
||||
Size = new Vector2(10),
|
||||
Colour = Color4Extensions.FromHex(@"f7dd55"),
|
||||
Scale = new Vector2(0.8f),
|
||||
},
|
||||
|
@ -24,6 +24,7 @@ namespace osu.Game.Overlays.Changelog
|
||||
public class ChangelogSupporterPromo : CompositeDrawable
|
||||
{
|
||||
private const float image_container_width = 164;
|
||||
private const float heart_size = 75;
|
||||
|
||||
private readonly FillFlowContainer textContainer;
|
||||
private readonly Container imageContainer;
|
||||
@ -134,18 +135,30 @@ namespace osu.Game.Overlays.Changelog
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Margin = new MarginPadding { Bottom = 28 },
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
FillMode = FillMode.Fill,
|
||||
Texture = textures.Get(@"Online/supporter-pippi"),
|
||||
},
|
||||
new Sprite
|
||||
new Container
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
Width = 75,
|
||||
Height = 75,
|
||||
Size = new Vector2(heart_size),
|
||||
Margin = new MarginPadding { Top = 70 },
|
||||
Texture = textures.Get(@"Online/supporter-heart"),
|
||||
Masking = true,
|
||||
EdgeEffect = new EdgeEffectParameters
|
||||
{
|
||||
Type = EdgeEffectType.Shadow,
|
||||
Colour = colour.Pink,
|
||||
Radius = 10,
|
||||
Roundness = heart_size / 2,
|
||||
},
|
||||
Child = new Sprite
|
||||
{
|
||||
Size = new Vector2(heart_size),
|
||||
Texture = textures.Get(@"Online/supporter-heart"),
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
@ -14,6 +14,9 @@ using System.Linq;
|
||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||
using osu.Framework.Threading;
|
||||
using osu.Game.Users;
|
||||
using System.Collections.Generic;
|
||||
using JetBrains.Annotations;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
|
||||
namespace osu.Game.Overlays.Comments
|
||||
{
|
||||
@ -147,7 +150,7 @@ namespace osu.Game.Overlays.Comments
|
||||
|
||||
private void refetchComments()
|
||||
{
|
||||
clearComments();
|
||||
ClearComments();
|
||||
getComments();
|
||||
}
|
||||
|
||||
@ -160,50 +163,125 @@ namespace osu.Game.Overlays.Comments
|
||||
loadCancellation?.Cancel();
|
||||
scheduledCommentsLoad?.Cancel();
|
||||
request = new GetCommentsRequest(id.Value, type.Value, Sort.Value, currentPage++, 0);
|
||||
request.Success += res => scheduledCommentsLoad = Schedule(() => onSuccess(res));
|
||||
request.Success += res => scheduledCommentsLoad = Schedule(() => OnSuccess(res));
|
||||
api.PerformAsync(request);
|
||||
}
|
||||
|
||||
private void clearComments()
|
||||
protected void ClearComments()
|
||||
{
|
||||
currentPage = 1;
|
||||
deletedCommentsCounter.Count.Value = 0;
|
||||
moreButton.Show();
|
||||
moreButton.IsLoading = true;
|
||||
content.Clear();
|
||||
CommentDictionary.Clear();
|
||||
}
|
||||
|
||||
private void onSuccess(CommentBundle response)
|
||||
protected readonly Dictionary<long, DrawableComment> CommentDictionary = new Dictionary<long, DrawableComment>();
|
||||
|
||||
protected void OnSuccess(CommentBundle response)
|
||||
{
|
||||
loadCancellation = new CancellationTokenSource();
|
||||
commentCounter.Current.Value = response.Total;
|
||||
|
||||
LoadComponentAsync(new CommentsPage(response)
|
||||
if (!response.Comments.Any())
|
||||
{
|
||||
ShowDeleted = { BindTarget = ShowDeleted },
|
||||
Sort = { BindTarget = Sort },
|
||||
Type = { BindTarget = type },
|
||||
CommentableId = { BindTarget = id }
|
||||
}, loaded =>
|
||||
content.Add(new NoCommentsPlaceholder());
|
||||
moreButton.Hide();
|
||||
return;
|
||||
}
|
||||
|
||||
AppendComments(response);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Appends retrieved comments to the subtree rooted of comments in this page.
|
||||
/// </summary>
|
||||
/// <param name="bundle">The bundle of comments to add.</param>
|
||||
protected void AppendComments([NotNull] CommentBundle bundle)
|
||||
{
|
||||
var topLevelComments = new List<DrawableComment>();
|
||||
var orphaned = new List<Comment>();
|
||||
|
||||
foreach (var comment in bundle.Comments.Concat(bundle.IncludedComments))
|
||||
{
|
||||
content.Add(loaded);
|
||||
// Exclude possible duplicated comments.
|
||||
if (CommentDictionary.ContainsKey(comment.Id))
|
||||
continue;
|
||||
|
||||
deletedCommentsCounter.Count.Value += response.Comments.Count(c => c.IsDeleted && c.IsTopLevel);
|
||||
addNewComment(comment);
|
||||
}
|
||||
|
||||
if (response.HasMore)
|
||||
// Comments whose parents were seen later than themselves can now be added.
|
||||
foreach (var o in orphaned)
|
||||
addNewComment(o);
|
||||
|
||||
if (topLevelComments.Any())
|
||||
{
|
||||
LoadComponentsAsync(topLevelComments, loaded =>
|
||||
{
|
||||
int loadedTopLevelComments = 0;
|
||||
content.Children.OfType<FillFlowContainer>().ForEach(p => loadedTopLevelComments += p.Children.OfType<DrawableComment>().Count());
|
||||
content.AddRange(loaded);
|
||||
|
||||
moreButton.Current.Value = response.TopLevelCount - loadedTopLevelComments;
|
||||
moreButton.IsLoading = false;
|
||||
deletedCommentsCounter.Count.Value += topLevelComments.Select(d => d.Comment).Count(c => c.IsDeleted && c.IsTopLevel);
|
||||
|
||||
if (bundle.HasMore)
|
||||
{
|
||||
int loadedTopLevelComments = 0;
|
||||
content.Children.OfType<DrawableComment>().ForEach(p => loadedTopLevelComments++);
|
||||
|
||||
moreButton.Current.Value = bundle.TopLevelCount - loadedTopLevelComments;
|
||||
moreButton.IsLoading = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
moreButton.Hide();
|
||||
}
|
||||
}, (loadCancellation = new CancellationTokenSource()).Token);
|
||||
}
|
||||
|
||||
void addNewComment(Comment comment)
|
||||
{
|
||||
var drawableComment = getDrawableComment(comment);
|
||||
|
||||
if (comment.ParentId == null)
|
||||
{
|
||||
// Comments that have no parent are added as top-level comments to the flow.
|
||||
topLevelComments.Add(drawableComment);
|
||||
}
|
||||
else if (CommentDictionary.TryGetValue(comment.ParentId.Value, out var parentDrawable))
|
||||
{
|
||||
// The comment's parent has already been seen, so the parent<-> child links can be added.
|
||||
comment.ParentComment = parentDrawable.Comment;
|
||||
parentDrawable.Replies.Add(drawableComment);
|
||||
}
|
||||
else
|
||||
{
|
||||
moreButton.Hide();
|
||||
// The comment's parent has not been seen yet, so keep it orphaned for the time being. This can occur if the comments arrive out of order.
|
||||
// Since this comment has now been seen, any further children can be added to it without being orphaned themselves.
|
||||
orphaned.Add(comment);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
commentCounter.Current.Value = response.Total;
|
||||
}, loadCancellation.Token);
|
||||
private DrawableComment getDrawableComment(Comment comment)
|
||||
{
|
||||
if (CommentDictionary.TryGetValue(comment.Id, out var existing))
|
||||
return existing;
|
||||
|
||||
return CommentDictionary[comment.Id] = new DrawableComment(comment)
|
||||
{
|
||||
ShowDeleted = { BindTarget = ShowDeleted },
|
||||
Sort = { BindTarget = Sort },
|
||||
RepliesRequested = onCommentRepliesRequested
|
||||
};
|
||||
}
|
||||
|
||||
private void onCommentRepliesRequested(DrawableComment drawableComment, int page)
|
||||
{
|
||||
var req = new GetCommentsRequest(id.Value, type.Value, Sort.Value, page, drawableComment.Comment.Id);
|
||||
|
||||
req.Success += response => Schedule(() => AppendComments(response));
|
||||
|
||||
api.PerformAsync(req);
|
||||
}
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
@ -212,5 +290,30 @@ namespace osu.Game.Overlays.Comments
|
||||
loadCancellation?.Cancel();
|
||||
base.Dispose(isDisposing);
|
||||
}
|
||||
|
||||
private class NoCommentsPlaceholder : CompositeDrawable
|
||||
{
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OverlayColourProvider colourProvider)
|
||||
{
|
||||
Height = 80;
|
||||
RelativeSizeAxes = Axes.X;
|
||||
AddRangeInternal(new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = colourProvider.Background4
|
||||
},
|
||||
new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
Margin = new MarginPadding { Left = 50 },
|
||||
Text = @"No comments yet."
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,161 +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.Graphics.Containers;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using System.Linq;
|
||||
using osu.Game.Online.API.Requests;
|
||||
using osu.Game.Online.API;
|
||||
using System.Collections.Generic;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace osu.Game.Overlays.Comments
|
||||
{
|
||||
public class CommentsPage : CompositeDrawable
|
||||
{
|
||||
public readonly BindableBool ShowDeleted = new BindableBool();
|
||||
public readonly Bindable<CommentsSortCriteria> Sort = new Bindable<CommentsSortCriteria>();
|
||||
public readonly Bindable<CommentableType> Type = new Bindable<CommentableType>();
|
||||
public readonly BindableLong CommentableId = new BindableLong();
|
||||
|
||||
[Resolved]
|
||||
private IAPIProvider api { get; set; }
|
||||
|
||||
private readonly CommentBundle commentBundle;
|
||||
private FillFlowContainer flow;
|
||||
|
||||
public CommentsPage(CommentBundle commentBundle)
|
||||
{
|
||||
this.commentBundle = commentBundle;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OverlayColourProvider colourProvider)
|
||||
{
|
||||
RelativeSizeAxes = Axes.X;
|
||||
AutoSizeAxes = Axes.Y;
|
||||
|
||||
AddRangeInternal(new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = colourProvider.Background5
|
||||
},
|
||||
flow = new FillFlowContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Direction = FillDirection.Vertical,
|
||||
}
|
||||
});
|
||||
|
||||
if (!commentBundle.Comments.Any())
|
||||
{
|
||||
flow.Add(new NoCommentsPlaceholder());
|
||||
return;
|
||||
}
|
||||
|
||||
AppendComments(commentBundle);
|
||||
}
|
||||
|
||||
private DrawableComment getDrawableComment(Comment comment)
|
||||
{
|
||||
if (CommentDictionary.TryGetValue(comment.Id, out var existing))
|
||||
return existing;
|
||||
|
||||
return CommentDictionary[comment.Id] = new DrawableComment(comment)
|
||||
{
|
||||
ShowDeleted = { BindTarget = ShowDeleted },
|
||||
Sort = { BindTarget = Sort },
|
||||
RepliesRequested = onCommentRepliesRequested
|
||||
};
|
||||
}
|
||||
|
||||
private void onCommentRepliesRequested(DrawableComment drawableComment, int page)
|
||||
{
|
||||
var request = new GetCommentsRequest(CommentableId.Value, Type.Value, Sort.Value, page, drawableComment.Comment.Id);
|
||||
|
||||
request.Success += response => Schedule(() => AppendComments(response));
|
||||
|
||||
api.PerformAsync(request);
|
||||
}
|
||||
|
||||
protected readonly Dictionary<long, DrawableComment> CommentDictionary = new Dictionary<long, DrawableComment>();
|
||||
|
||||
/// <summary>
|
||||
/// Appends retrieved comments to the subtree rooted of comments in this page.
|
||||
/// </summary>
|
||||
/// <param name="bundle">The bundle of comments to add.</param>
|
||||
protected void AppendComments([NotNull] CommentBundle bundle)
|
||||
{
|
||||
var orphaned = new List<Comment>();
|
||||
|
||||
foreach (var comment in bundle.Comments.Concat(bundle.IncludedComments))
|
||||
{
|
||||
// Exclude possible duplicated comments.
|
||||
if (CommentDictionary.ContainsKey(comment.Id))
|
||||
continue;
|
||||
|
||||
addNewComment(comment);
|
||||
}
|
||||
|
||||
// Comments whose parents were seen later than themselves can now be added.
|
||||
foreach (var o in orphaned)
|
||||
addNewComment(o);
|
||||
|
||||
void addNewComment(Comment comment)
|
||||
{
|
||||
var drawableComment = getDrawableComment(comment);
|
||||
|
||||
if (comment.ParentId == null)
|
||||
{
|
||||
// Comments that have no parent are added as top-level comments to the flow.
|
||||
flow.Add(drawableComment);
|
||||
}
|
||||
else if (CommentDictionary.TryGetValue(comment.ParentId.Value, out var parentDrawable))
|
||||
{
|
||||
// The comment's parent has already been seen, so the parent<-> child links can be added.
|
||||
comment.ParentComment = parentDrawable.Comment;
|
||||
parentDrawable.Replies.Add(drawableComment);
|
||||
}
|
||||
else
|
||||
{
|
||||
// The comment's parent has not been seen yet, so keep it orphaned for the time being. This can occur if the comments arrive out of order.
|
||||
// Since this comment has now been seen, any further children can be added to it without being orphaned themselves.
|
||||
orphaned.Add(comment);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class NoCommentsPlaceholder : CompositeDrawable
|
||||
{
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OverlayColourProvider colourProvider)
|
||||
{
|
||||
Height = 80;
|
||||
RelativeSizeAxes = Axes.X;
|
||||
AddRangeInternal(new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = colourProvider.Background4
|
||||
},
|
||||
new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
Margin = new MarginPadding { Left = 50 },
|
||||
Text = @"No comments yet."
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -24,7 +24,7 @@ namespace osu.Game.Overlays
|
||||
public LocalisableString Title => NotificationsStrings.HeaderTitle;
|
||||
public LocalisableString Description => NotificationsStrings.HeaderDescription;
|
||||
|
||||
private const float width = 320;
|
||||
public const float WIDTH = 320;
|
||||
|
||||
public const float TRANSITION_LENGTH = 600;
|
||||
|
||||
@ -38,7 +38,8 @@ namespace osu.Game.Overlays
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
Width = width;
|
||||
X = WIDTH;
|
||||
Width = WIDTH;
|
||||
RelativeSizeAxes = Axes.Y;
|
||||
|
||||
Children = new Drawable[]
|
||||
@ -152,7 +153,7 @@ namespace osu.Game.Overlays
|
||||
|
||||
markAllRead();
|
||||
|
||||
this.MoveToX(width, TRANSITION_LENGTH, Easing.OutQuint);
|
||||
this.MoveToX(WIDTH, TRANSITION_LENGTH, Easing.OutQuint);
|
||||
this.FadeTo(0, TRANSITION_LENGTH, Easing.OutQuint);
|
||||
}
|
||||
|
||||
|
@ -8,12 +8,13 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Localisation;
|
||||
|
||||
namespace osu.Game.Overlays.Settings.Sections.Audio
|
||||
{
|
||||
public class AudioDevicesSettings : SettingsSubsection
|
||||
{
|
||||
protected override LocalisableString Header => "Devices";
|
||||
protected override LocalisableString Header => AudioSettingsStrings.AudioDevicesHeader;
|
||||
|
||||
[Resolved]
|
||||
private AudioManager audio { get; set; }
|
||||
@ -78,7 +79,7 @@ namespace osu.Game.Overlays.Settings.Sections.Audio
|
||||
private class AudioDeviceDropdownControl : DropdownControl
|
||||
{
|
||||
protected override LocalisableString GenerateItemText(string item)
|
||||
=> string.IsNullOrEmpty(item) ? "Default" : base.GenerateItemText(item);
|
||||
=> string.IsNullOrEmpty(item) ? CommonStrings.Default : base.GenerateItemText(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,17 +1,22 @@
|
||||
// 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.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Localisation;
|
||||
|
||||
namespace osu.Game.Overlays.Settings.Sections.Audio
|
||||
{
|
||||
public class OffsetSettings : SettingsSubsection
|
||||
{
|
||||
protected override LocalisableString Header => "Offset Adjustment";
|
||||
protected override LocalisableString Header => AudioSettingsStrings.OffsetHeader;
|
||||
|
||||
public override IEnumerable<string> FilterTerms => base.FilterTerms.Concat(new[] { "universal", "uo", "timing" });
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuConfigManager config)
|
||||
@ -20,13 +25,13 @@ namespace osu.Game.Overlays.Settings.Sections.Audio
|
||||
{
|
||||
new SettingsSlider<double, OffsetSlider>
|
||||
{
|
||||
LabelText = "Audio offset",
|
||||
LabelText = AudioSettingsStrings.AudioOffset,
|
||||
Current = config.GetBindable<double>(OsuSetting.AudioOffset),
|
||||
KeyboardStep = 1f
|
||||
},
|
||||
new SettingsButton
|
||||
{
|
||||
Text = "Offset wizard"
|
||||
Text = AudioSettingsStrings.OffsetWizard
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -6,12 +6,13 @@ using osu.Framework.Audio;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Localisation;
|
||||
|
||||
namespace osu.Game.Overlays.Settings.Sections.Audio
|
||||
{
|
||||
public class VolumeSettings : SettingsSubsection
|
||||
{
|
||||
protected override LocalisableString Header => "Volume";
|
||||
protected override LocalisableString Header => AudioSettingsStrings.VolumeHeader;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(AudioManager audio, OsuConfigManager config)
|
||||
@ -20,28 +21,28 @@ namespace osu.Game.Overlays.Settings.Sections.Audio
|
||||
{
|
||||
new SettingsSlider<double>
|
||||
{
|
||||
LabelText = "Master",
|
||||
LabelText = AudioSettingsStrings.MasterVolume,
|
||||
Current = audio.Volume,
|
||||
KeyboardStep = 0.01f,
|
||||
DisplayAsPercentage = true
|
||||
},
|
||||
new SettingsSlider<double>
|
||||
{
|
||||
LabelText = "Master (window inactive)",
|
||||
LabelText = AudioSettingsStrings.MasterVolumeInactive,
|
||||
Current = config.GetBindable<double>(OsuSetting.VolumeInactive),
|
||||
KeyboardStep = 0.01f,
|
||||
DisplayAsPercentage = true
|
||||
},
|
||||
new SettingsSlider<double>
|
||||
{
|
||||
LabelText = "Effect",
|
||||
LabelText = AudioSettingsStrings.EffectVolume,
|
||||
Current = audio.VolumeSample,
|
||||
KeyboardStep = 0.01f,
|
||||
DisplayAsPercentage = true
|
||||
},
|
||||
new SettingsSlider<double>
|
||||
{
|
||||
LabelText = "Music",
|
||||
LabelText = AudioSettingsStrings.MusicVolume,
|
||||
Current = audio.VolumeTrack,
|
||||
KeyboardStep = 0.01f,
|
||||
DisplayAsPercentage = true
|
||||
|
@ -3,15 +3,17 @@
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Game.Localisation;
|
||||
using osu.Game.Overlays.Settings.Sections.Audio;
|
||||
|
||||
namespace osu.Game.Overlays.Settings.Sections
|
||||
{
|
||||
public class AudioSection : SettingsSection
|
||||
{
|
||||
public override string Header => "Audio";
|
||||
public override LocalisableString Header => AudioSettingsStrings.AudioSectionHeader;
|
||||
|
||||
public override Drawable CreateIcon() => new SpriteIcon
|
||||
{
|
||||
|
@ -6,13 +6,14 @@ using osu.Framework.Configuration;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Game.Localisation;
|
||||
using osu.Game.Screens.Import;
|
||||
|
||||
namespace osu.Game.Overlays.Settings.Sections.Debug
|
||||
{
|
||||
public class GeneralSettings : SettingsSubsection
|
||||
{
|
||||
protected override LocalisableString Header => "General";
|
||||
protected override LocalisableString Header => DebugSettingsStrings.GeneralHeader;
|
||||
|
||||
[BackgroundDependencyLoader(true)]
|
||||
private void load(FrameworkDebugConfigManager config, FrameworkConfigManager frameworkConfig, OsuGame game)
|
||||
@ -21,18 +22,18 @@ namespace osu.Game.Overlays.Settings.Sections.Debug
|
||||
{
|
||||
new SettingsCheckbox
|
||||
{
|
||||
LabelText = "Show log overlay",
|
||||
LabelText = DebugSettingsStrings.ShowLogOverlay,
|
||||
Current = frameworkConfig.GetBindable<bool>(FrameworkSetting.ShowLogOverlay)
|
||||
},
|
||||
new SettingsCheckbox
|
||||
{
|
||||
LabelText = "Bypass front-to-back render pass",
|
||||
LabelText = DebugSettingsStrings.BypassFrontToBackPass,
|
||||
Current = config.GetBindable<bool>(DebugSetting.BypassFrontToBackPass)
|
||||
}
|
||||
};
|
||||
Add(new SettingsButton
|
||||
{
|
||||
Text = "Import files",
|
||||
Text = DebugSettingsStrings.ImportFiles,
|
||||
Action = () => game?.PerformFromScreen(menu => menu.Push(new FileImportScreen()))
|
||||
});
|
||||
}
|
||||
|
@ -6,12 +6,13 @@ using osu.Framework.Configuration;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Game.Localisation;
|
||||
|
||||
namespace osu.Game.Overlays.Settings.Sections.Debug
|
||||
{
|
||||
public class MemorySettings : SettingsSubsection
|
||||
{
|
||||
protected override LocalisableString Header => "Memory";
|
||||
protected override LocalisableString Header => DebugSettingsStrings.MemoryHeader;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(FrameworkDebugConfigManager config, GameHost host)
|
||||
@ -20,7 +21,7 @@ namespace osu.Game.Overlays.Settings.Sections.Debug
|
||||
{
|
||||
new SettingsButton
|
||||
{
|
||||
Text = "Clear all caches",
|
||||
Text = DebugSettingsStrings.ClearAllCaches,
|
||||
Action = host.Collect
|
||||
},
|
||||
};
|
||||
|
@ -3,13 +3,15 @@
|
||||
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Localisation;
|
||||
using osu.Game.Overlays.Settings.Sections.Debug;
|
||||
|
||||
namespace osu.Game.Overlays.Settings.Sections
|
||||
{
|
||||
public class DebugSection : SettingsSection
|
||||
{
|
||||
public override string Header => "Debug";
|
||||
public override LocalisableString Header => DebugSettingsStrings.DebugSectionHeader;
|
||||
|
||||
public override Drawable CreateIcon() => new SpriteIcon
|
||||
{
|
||||
|
@ -6,13 +6,14 @@ using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Localisation;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
|
||||
namespace osu.Game.Overlays.Settings.Sections.Gameplay
|
||||
{
|
||||
public class GeneralSettings : SettingsSubsection
|
||||
{
|
||||
protected override LocalisableString Header => "General";
|
||||
protected override LocalisableString Header => GameplaySettingsStrings.GeneralHeader;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuConfigManager config)
|
||||
@ -21,62 +22,62 @@ namespace osu.Game.Overlays.Settings.Sections.Gameplay
|
||||
{
|
||||
new SettingsSlider<double>
|
||||
{
|
||||
LabelText = "Background dim",
|
||||
LabelText = GameplaySettingsStrings.BackgroundDim,
|
||||
Current = config.GetBindable<double>(OsuSetting.DimLevel),
|
||||
KeyboardStep = 0.01f,
|
||||
DisplayAsPercentage = true
|
||||
},
|
||||
new SettingsSlider<double>
|
||||
{
|
||||
LabelText = "Background blur",
|
||||
LabelText = GameplaySettingsStrings.BackgroundBlur,
|
||||
Current = config.GetBindable<double>(OsuSetting.BlurLevel),
|
||||
KeyboardStep = 0.01f,
|
||||
DisplayAsPercentage = true
|
||||
},
|
||||
new SettingsCheckbox
|
||||
{
|
||||
LabelText = "Lighten playfield during breaks",
|
||||
LabelText = GameplaySettingsStrings.LightenDuringBreaks,
|
||||
Current = config.GetBindable<bool>(OsuSetting.LightenDuringBreaks)
|
||||
},
|
||||
new SettingsEnumDropdown<HUDVisibilityMode>
|
||||
{
|
||||
LabelText = "HUD overlay visibility mode",
|
||||
LabelText = GameplaySettingsStrings.HUDVisibilityMode,
|
||||
Current = config.GetBindable<HUDVisibilityMode>(OsuSetting.HUDVisibilityMode)
|
||||
},
|
||||
new SettingsCheckbox
|
||||
{
|
||||
LabelText = "Show difficulty graph on progress bar",
|
||||
LabelText = GameplaySettingsStrings.ShowDifficultyGraph,
|
||||
Current = config.GetBindable<bool>(OsuSetting.ShowProgressGraph)
|
||||
},
|
||||
new SettingsCheckbox
|
||||
{
|
||||
LabelText = "Show health display even when you can't fail",
|
||||
LabelText = GameplaySettingsStrings.ShowHealthDisplayWhenCantFail,
|
||||
Current = config.GetBindable<bool>(OsuSetting.ShowHealthDisplayWhenCantFail),
|
||||
Keywords = new[] { "hp", "bar" }
|
||||
},
|
||||
new SettingsCheckbox
|
||||
{
|
||||
LabelText = "Fade playfield to red when health is low",
|
||||
LabelText = GameplaySettingsStrings.FadePlayfieldWhenHealthLow,
|
||||
Current = config.GetBindable<bool>(OsuSetting.FadePlayfieldWhenHealthLow),
|
||||
},
|
||||
new SettingsCheckbox
|
||||
{
|
||||
LabelText = "Always show key overlay",
|
||||
LabelText = GameplaySettingsStrings.AlwaysShowKeyOverlay,
|
||||
Current = config.GetBindable<bool>(OsuSetting.KeyOverlay)
|
||||
},
|
||||
new SettingsCheckbox
|
||||
{
|
||||
LabelText = "Positional hitsounds",
|
||||
LabelText = GameplaySettingsStrings.PositionalHitsounds,
|
||||
Current = config.GetBindable<bool>(OsuSetting.PositionalHitSounds)
|
||||
},
|
||||
new SettingsCheckbox
|
||||
{
|
||||
LabelText = "Always play first combo break sound",
|
||||
LabelText = GameplaySettingsStrings.AlwaysPlayFirstComboBreak,
|
||||
Current = config.GetBindable<bool>(OsuSetting.AlwaysPlayFirstComboBreak)
|
||||
},
|
||||
new SettingsEnumDropdown<ScoringMode>
|
||||
{
|
||||
LabelText = "Score display mode",
|
||||
LabelText = GameplaySettingsStrings.ScoreDisplayMode,
|
||||
Current = config.GetBindable<ScoringMode>(OsuSetting.ScoreDisplayMode),
|
||||
Keywords = new[] { "scoring" }
|
||||
},
|
||||
@ -86,7 +87,7 @@ namespace osu.Game.Overlays.Settings.Sections.Gameplay
|
||||
{
|
||||
Add(new SettingsCheckbox
|
||||
{
|
||||
LabelText = "Disable Windows key during gameplay",
|
||||
LabelText = GameplaySettingsStrings.DisableWinKey,
|
||||
Current = config.GetBindable<bool>(OsuSetting.GameplayDisableWinKey)
|
||||
});
|
||||
}
|
||||
|
@ -6,12 +6,13 @@ using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Localisation;
|
||||
|
||||
namespace osu.Game.Overlays.Settings.Sections.Gameplay
|
||||
{
|
||||
public class ModsSettings : SettingsSubsection
|
||||
{
|
||||
protected override LocalisableString Header => "Mods";
|
||||
protected override LocalisableString Header => GameplaySettingsStrings.ModsHeader;
|
||||
|
||||
public override IEnumerable<string> FilterTerms => base.FilterTerms.Concat(new[] { "mod" });
|
||||
|
||||
@ -22,7 +23,7 @@ namespace osu.Game.Overlays.Settings.Sections.Gameplay
|
||||
{
|
||||
new SettingsCheckbox
|
||||
{
|
||||
LabelText = "Increase visibility of first object when visual impairment mods are enabled",
|
||||
LabelText = GameplaySettingsStrings.IncreaseFirstObjectVisibility,
|
||||
Current = config.GetBindable<bool>(OsuSetting.IncreaseFirstObjectVisibility),
|
||||
},
|
||||
};
|
||||
|
@ -9,12 +9,14 @@ using osu.Game.Rulesets;
|
||||
using System.Linq;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Logging;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Localisation;
|
||||
|
||||
namespace osu.Game.Overlays.Settings.Sections
|
||||
{
|
||||
public class GameplaySection : SettingsSection
|
||||
{
|
||||
public override string Header => "Gameplay";
|
||||
public override LocalisableString Header => GameplaySettingsStrings.GameplaySectionHeader;
|
||||
|
||||
public override Drawable CreateIcon() => new SpriteIcon
|
||||
{
|
||||
|
@ -16,7 +16,7 @@ namespace osu.Game.Overlays.Settings.Sections.General
|
||||
private SettingsDropdown<Language> languageSelection;
|
||||
private Bindable<string> frameworkLocale;
|
||||
|
||||
protected override LocalisableString Header => "Language";
|
||||
protected override LocalisableString Header => GeneralSettingsStrings.LanguageHeader;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(FrameworkConfigManager frameworkConfig)
|
||||
@ -27,11 +27,11 @@ namespace osu.Game.Overlays.Settings.Sections.General
|
||||
{
|
||||
languageSelection = new SettingsEnumDropdown<Language>
|
||||
{
|
||||
LabelText = "Language",
|
||||
LabelText = GeneralSettingsStrings.LanguageDropdown,
|
||||
},
|
||||
new SettingsCheckbox
|
||||
{
|
||||
LabelText = "Prefer metadata in original language",
|
||||
LabelText = GeneralSettingsStrings.PreferOriginalMetadataLanguage,
|
||||
Current = frameworkConfig.GetBindable<bool>(FrameworkSetting.ShowUnicode)
|
||||
},
|
||||
};
|
||||
|
@ -9,6 +9,7 @@ using osu.Framework.Localisation;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Localisation;
|
||||
using osu.Game.Overlays.Notifications;
|
||||
using osu.Game.Overlays.Settings.Sections.Maintenance;
|
||||
using osu.Game.Updater;
|
||||
@ -20,7 +21,7 @@ namespace osu.Game.Overlays.Settings.Sections.General
|
||||
[Resolved(CanBeNull = true)]
|
||||
private UpdateManager updateManager { get; set; }
|
||||
|
||||
protected override LocalisableString Header => "Updates";
|
||||
protected override LocalisableString Header => GeneralSettingsStrings.UpdateHeader;
|
||||
|
||||
private SettingsButton checkForUpdatesButton;
|
||||
|
||||
@ -32,7 +33,7 @@ namespace osu.Game.Overlays.Settings.Sections.General
|
||||
{
|
||||
Add(new SettingsEnumDropdown<ReleaseStream>
|
||||
{
|
||||
LabelText = "Release stream",
|
||||
LabelText = GeneralSettingsStrings.ReleaseStream,
|
||||
Current = config.GetBindable<ReleaseStream>(OsuSetting.ReleaseStream),
|
||||
});
|
||||
|
||||
@ -40,7 +41,7 @@ namespace osu.Game.Overlays.Settings.Sections.General
|
||||
{
|
||||
Add(checkForUpdatesButton = new SettingsButton
|
||||
{
|
||||
Text = "Check for updates",
|
||||
Text = GeneralSettingsStrings.CheckUpdate,
|
||||
Action = () =>
|
||||
{
|
||||
checkForUpdatesButton.Enabled.Value = false;
|
||||
@ -65,13 +66,13 @@ namespace osu.Game.Overlays.Settings.Sections.General
|
||||
{
|
||||
Add(new SettingsButton
|
||||
{
|
||||
Text = "Open osu! folder",
|
||||
Text = GeneralSettingsStrings.OpenOsuFolder,
|
||||
Action = storage.OpenInNativeExplorer,
|
||||
});
|
||||
|
||||
Add(new SettingsButton
|
||||
{
|
||||
Text = "Change folder location...",
|
||||
Text = GeneralSettingsStrings.ChangeFolderLocation,
|
||||
Action = () => game?.PerformFromScreen(menu => menu.Push(new MigrationSelectScreen()))
|
||||
});
|
||||
}
|
||||
|
@ -3,13 +3,15 @@
|
||||
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Localisation;
|
||||
using osu.Game.Overlays.Settings.Sections.General;
|
||||
|
||||
namespace osu.Game.Overlays.Settings.Sections
|
||||
{
|
||||
public class GeneralSection : SettingsSection
|
||||
{
|
||||
public override string Header => "General";
|
||||
public override LocalisableString Header => GeneralSettingsStrings.GeneralSectionHeader;
|
||||
|
||||
public override Drawable CreateIcon() => new SpriteIcon
|
||||
{
|
||||
|
@ -5,12 +5,13 @@ using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Localisation;
|
||||
|
||||
namespace osu.Game.Overlays.Settings.Sections.Graphics
|
||||
{
|
||||
public class DetailSettings : SettingsSubsection
|
||||
{
|
||||
protected override LocalisableString Header => "Detail Settings";
|
||||
protected override LocalisableString Header => GraphicsSettingsStrings.DetailSettingsHeader;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuConfigManager config)
|
||||
@ -19,22 +20,22 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
|
||||
{
|
||||
new SettingsCheckbox
|
||||
{
|
||||
LabelText = "Storyboard / Video",
|
||||
LabelText = GraphicsSettingsStrings.StoryboardVideo,
|
||||
Current = config.GetBindable<bool>(OsuSetting.ShowStoryboard)
|
||||
},
|
||||
new SettingsCheckbox
|
||||
{
|
||||
LabelText = "Hit Lighting",
|
||||
LabelText = GraphicsSettingsStrings.HitLighting,
|
||||
Current = config.GetBindable<bool>(OsuSetting.HitLighting)
|
||||
},
|
||||
new SettingsEnumDropdown<ScreenshotFormat>
|
||||
{
|
||||
LabelText = "Screenshot format",
|
||||
LabelText = GraphicsSettingsStrings.ScreenshotFormat,
|
||||
Current = config.GetBindable<ScreenshotFormat>(OsuSetting.ScreenshotFormat)
|
||||
},
|
||||
new SettingsCheckbox
|
||||
{
|
||||
LabelText = "Show menu cursor in screenshots",
|
||||
LabelText = GraphicsSettingsStrings.ShowCursorInScreenshots,
|
||||
Current = config.GetBindable<bool>(OsuSetting.ScreenshotCaptureMenuCursor)
|
||||
}
|
||||
};
|
||||
|
@ -16,13 +16,14 @@ using osu.Framework.Platform;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Localisation;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Overlays.Settings.Sections.Graphics
|
||||
{
|
||||
public class LayoutSettings : SettingsSubsection
|
||||
{
|
||||
protected override LocalisableString Header => "Layout";
|
||||
protected override LocalisableString Header => GraphicsSettingsStrings.LayoutHeader;
|
||||
|
||||
private FillFlowContainer<SettingsSlider<float>> scalingSettings;
|
||||
|
||||
@ -67,20 +68,20 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
|
||||
{
|
||||
windowModeDropdown = new SettingsDropdown<WindowMode>
|
||||
{
|
||||
LabelText = "Screen mode",
|
||||
LabelText = GraphicsSettingsStrings.ScreenMode,
|
||||
ItemSource = windowModes,
|
||||
Current = config.GetBindable<WindowMode>(FrameworkSetting.WindowMode),
|
||||
},
|
||||
resolutionDropdown = new ResolutionSettingsDropdown
|
||||
{
|
||||
LabelText = "Resolution",
|
||||
LabelText = GraphicsSettingsStrings.Resolution,
|
||||
ShowsDefaultIndicator = false,
|
||||
ItemSource = resolutions,
|
||||
Current = sizeFullscreen
|
||||
},
|
||||
new SettingsSlider<float, UIScaleSlider>
|
||||
{
|
||||
LabelText = "UI Scaling",
|
||||
LabelText = GraphicsSettingsStrings.UIScaling,
|
||||
TransferValueOnCommit = true,
|
||||
Current = osuConfig.GetBindable<float>(OsuSetting.UIScale),
|
||||
KeyboardStep = 0.01f,
|
||||
@ -88,7 +89,7 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
|
||||
},
|
||||
new SettingsEnumDropdown<ScalingMode>
|
||||
{
|
||||
LabelText = "Screen Scaling",
|
||||
LabelText = GraphicsSettingsStrings.ScreenScaling,
|
||||
Current = osuConfig.GetBindable<ScalingMode>(OsuSetting.Scaling),
|
||||
Keywords = new[] { "scale", "letterbox" },
|
||||
},
|
||||
@ -104,28 +105,28 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
|
||||
{
|
||||
new SettingsSlider<float>
|
||||
{
|
||||
LabelText = "Horizontal position",
|
||||
LabelText = GraphicsSettingsStrings.HorizontalPosition,
|
||||
Current = scalingPositionX,
|
||||
KeyboardStep = 0.01f,
|
||||
DisplayAsPercentage = true
|
||||
},
|
||||
new SettingsSlider<float>
|
||||
{
|
||||
LabelText = "Vertical position",
|
||||
LabelText = GraphicsSettingsStrings.VerticalPosition,
|
||||
Current = scalingPositionY,
|
||||
KeyboardStep = 0.01f,
|
||||
DisplayAsPercentage = true
|
||||
},
|
||||
new SettingsSlider<float>
|
||||
{
|
||||
LabelText = "Horizontal scale",
|
||||
LabelText = GraphicsSettingsStrings.HorizontalScale,
|
||||
Current = scalingSizeX,
|
||||
KeyboardStep = 0.01f,
|
||||
DisplayAsPercentage = true
|
||||
},
|
||||
new SettingsSlider<float>
|
||||
{
|
||||
LabelText = "Vertical scale",
|
||||
LabelText = GraphicsSettingsStrings.VerticalScale,
|
||||
Current = scalingSizeY,
|
||||
KeyboardStep = 0.01f,
|
||||
DisplayAsPercentage = true
|
||||
@ -145,9 +146,7 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
|
||||
{
|
||||
updateResolutionDropdown();
|
||||
|
||||
const string not_fullscreen_note = "Running without fullscreen mode will increase your input latency!";
|
||||
|
||||
windowModeDropdown.WarningText = mode.NewValue != WindowMode.Fullscreen ? not_fullscreen_note : string.Empty;
|
||||
windowModeDropdown.WarningText = mode.NewValue != WindowMode.Fullscreen ? GraphicsSettingsStrings.NotFullscreenNote : default;
|
||||
}, true);
|
||||
|
||||
windowModes.BindCollectionChanged((sender, args) =>
|
||||
@ -245,7 +244,7 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
|
||||
protected override LocalisableString GenerateItemText(Size item)
|
||||
{
|
||||
if (item == new Size(9999, 9999))
|
||||
return "Default";
|
||||
return CommonStrings.Default;
|
||||
|
||||
return $"{item.Width}x{item.Height}";
|
||||
}
|
||||
|
@ -7,12 +7,13 @@ using osu.Framework.Graphics;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Localisation;
|
||||
|
||||
namespace osu.Game.Overlays.Settings.Sections.Graphics
|
||||
{
|
||||
public class RendererSettings : SettingsSubsection
|
||||
{
|
||||
protected override LocalisableString Header => "Renderer";
|
||||
protected override LocalisableString Header => GraphicsSettingsStrings.RendererHeader;
|
||||
|
||||
private SettingsEnumDropdown<FrameSync> frameLimiterDropdown;
|
||||
|
||||
@ -25,17 +26,17 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
|
||||
// TODO: this needs to be a custom dropdown at some point
|
||||
frameLimiterDropdown = new SettingsEnumDropdown<FrameSync>
|
||||
{
|
||||
LabelText = "Frame limiter",
|
||||
LabelText = GraphicsSettingsStrings.FrameLimiter,
|
||||
Current = config.GetBindable<FrameSync>(FrameworkSetting.FrameSync)
|
||||
},
|
||||
new SettingsEnumDropdown<ExecutionMode>
|
||||
{
|
||||
LabelText = "Threading mode",
|
||||
LabelText = GraphicsSettingsStrings.ThreadingMode,
|
||||
Current = config.GetBindable<ExecutionMode>(FrameworkSetting.ExecutionMode)
|
||||
},
|
||||
new SettingsCheckbox
|
||||
{
|
||||
LabelText = "Show FPS",
|
||||
LabelText = GraphicsSettingsStrings.ShowFPS,
|
||||
Current = osuConfig.GetBindable<bool>(OsuSetting.ShowFpsDisplay)
|
||||
},
|
||||
};
|
||||
@ -47,9 +48,7 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
|
||||
|
||||
frameLimiterDropdown.Current.BindValueChanged(limit =>
|
||||
{
|
||||
const string unlimited_frames_note = "Using unlimited frame limiter can lead to stutters, bad performance and overheating. It will not improve perceived latency. \"2x refresh rate\" is recommended.";
|
||||
|
||||
frameLimiterDropdown.WarningText = limit.NewValue == FrameSync.Unlimited ? unlimited_frames_note : string.Empty;
|
||||
frameLimiterDropdown.WarningText = limit.NewValue == FrameSync.Unlimited ? GraphicsSettingsStrings.UnlimitedFramesNote : default;
|
||||
}, true);
|
||||
}
|
||||
}
|
||||
|
@ -3,13 +3,15 @@
|
||||
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Localisation;
|
||||
using osu.Game.Overlays.Settings.Sections.Graphics;
|
||||
|
||||
namespace osu.Game.Overlays.Settings.Sections
|
||||
{
|
||||
public class GraphicsSection : SettingsSection
|
||||
{
|
||||
public override string Header => "Graphics";
|
||||
public override LocalisableString Header => GraphicsSettingsStrings.GraphicsSectionHeader;
|
||||
|
||||
public override Drawable CreateIcon() => new SpriteIcon
|
||||
{
|
||||
|
@ -5,6 +5,7 @@ using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Input.Bindings;
|
||||
using osu.Game.Localisation;
|
||||
|
||||
namespace osu.Game.Overlays.Settings.Sections.Input
|
||||
{
|
||||
@ -15,7 +16,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input
|
||||
Icon = FontAwesome.Solid.Globe
|
||||
};
|
||||
|
||||
public override string Header => "Global";
|
||||
public override LocalisableString Header => InputSettingsStrings.GlobalKeyBindingHeader;
|
||||
|
||||
public GlobalKeyBindingsSection(GlobalActionContainer manager)
|
||||
{
|
||||
@ -39,7 +40,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input
|
||||
|
||||
private class SongSelectKeyBindingSubsection : KeyBindingsSubsection
|
||||
{
|
||||
protected override LocalisableString Header => "Song Select";
|
||||
protected override LocalisableString Header => InputSettingsStrings.SongSelectSection;
|
||||
|
||||
public SongSelectKeyBindingSubsection(GlobalActionContainer manager)
|
||||
: base(null)
|
||||
@ -50,7 +51,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input
|
||||
|
||||
private class InGameKeyBindingsSubsection : KeyBindingsSubsection
|
||||
{
|
||||
protected override LocalisableString Header => "In Game";
|
||||
protected override LocalisableString Header => InputSettingsStrings.InGameSection;
|
||||
|
||||
public InGameKeyBindingsSubsection(GlobalActionContainer manager)
|
||||
: base(null)
|
||||
@ -61,7 +62,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input
|
||||
|
||||
private class AudioControlKeyBindingsSubsection : KeyBindingsSubsection
|
||||
{
|
||||
protected override LocalisableString Header => "Audio";
|
||||
protected override LocalisableString Header => InputSettingsStrings.AudioSection;
|
||||
|
||||
public AudioControlKeyBindingsSubsection(GlobalActionContainer manager)
|
||||
: base(null)
|
||||
@ -72,7 +73,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input
|
||||
|
||||
private class EditorKeyBindingsSubsection : KeyBindingsSubsection
|
||||
{
|
||||
protected override LocalisableString Header => "Editor";
|
||||
protected override LocalisableString Header => InputSettingsStrings.EditorSection;
|
||||
|
||||
public EditorKeyBindingsSubsection(GlobalActionContainer manager)
|
||||
: base(null)
|
||||
|
@ -4,13 +4,14 @@
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Input.Bindings;
|
||||
using osu.Game.Localisation;
|
||||
using osu.Game.Rulesets;
|
||||
|
||||
namespace osu.Game.Overlays.Settings.Sections.Input
|
||||
{
|
||||
public class KeyBindingPanel : SettingsSubPanel
|
||||
{
|
||||
protected override Drawable CreateHeader() => new SettingsHeader("key configuration", "Customise your keys!");
|
||||
protected override Drawable CreateHeader() => new SettingsHeader(InputSettingsStrings.KeyBindingPanelHeader, InputSettingsStrings.KeyBindingPanelDescription);
|
||||
|
||||
[BackgroundDependencyLoader(permitNulls: true)]
|
||||
private void load(RulesetStore rulesets, GlobalActionContainer global)
|
||||
|
@ -20,6 +20,7 @@ using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Input;
|
||||
using osu.Game.Input.Bindings;
|
||||
using osu.Game.Localisation;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
using osuTK.Input;
|
||||
@ -385,7 +386,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input
|
||||
{
|
||||
public CancelButton()
|
||||
{
|
||||
Text = "Cancel";
|
||||
Text = CommonStrings.Cancel;
|
||||
Size = new Vector2(80, 20);
|
||||
}
|
||||
}
|
||||
@ -394,7 +395,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input
|
||||
{
|
||||
public ClearButton()
|
||||
{
|
||||
Text = "Clear";
|
||||
Text = CommonStrings.Clear;
|
||||
Size = new Vector2(80, 20);
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ using osu.Game.Database;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Input.Bindings;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Localisation;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Overlays.Settings.Sections.Input
|
||||
@ -64,7 +65,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
Text = "Reset all bindings in section";
|
||||
Text = InputSettingsStrings.ResetSectionButton;
|
||||
RelativeSizeAxes = Axes.X;
|
||||
Width = 0.5f;
|
||||
Anchor = Anchor.TopCentre;
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Rulesets;
|
||||
|
||||
@ -15,7 +16,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input
|
||||
Icon = OsuIcon.Hot
|
||||
};
|
||||
|
||||
public override string Header => ruleset.Name;
|
||||
public override LocalisableString Header => ruleset.Name;
|
||||
|
||||
private readonly RulesetInfo ruleset;
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
// 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;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
@ -9,9 +10,11 @@ using osu.Framework.Input.Handlers.Tablet;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Framework.Threading;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osuTK;
|
||||
using osu.Game.Localisation;
|
||||
using osu.Game.Online.Chat;
|
||||
|
||||
namespace osu.Game.Overlays.Settings.Sections.Input
|
||||
{
|
||||
@ -19,6 +22,8 @@ namespace osu.Game.Overlays.Settings.Sections.Input
|
||||
{
|
||||
private readonly ITabletHandler tabletHandler;
|
||||
|
||||
private readonly Bindable<bool> enabled = new BindableBool(true);
|
||||
|
||||
private readonly Bindable<Vector2> areaOffset = new Bindable<Vector2>();
|
||||
private readonly Bindable<Vector2> areaSize = new Bindable<Vector2>();
|
||||
private readonly IBindable<TabletInfo> tablet = new Bindable<TabletInfo>();
|
||||
@ -52,7 +57,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input
|
||||
|
||||
private FillFlowContainer mainSettings;
|
||||
|
||||
private OsuSpriteText noTabletMessage;
|
||||
private FillFlowContainer noTabletMessage;
|
||||
|
||||
protected override LocalisableString Header => TabletSettingsStrings.Tablet;
|
||||
|
||||
@ -62,7 +67,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
Children = new Drawable[]
|
||||
{
|
||||
@ -71,14 +76,41 @@ namespace osu.Game.Overlays.Settings.Sections.Input
|
||||
LabelText = CommonStrings.Enabled,
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
Current = tabletHandler.Enabled
|
||||
Current = enabled,
|
||||
},
|
||||
noTabletMessage = new OsuSpriteText
|
||||
noTabletMessage = new FillFlowContainer
|
||||
{
|
||||
Text = TabletSettingsStrings.NoTabletDetected,
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
Padding = new MarginPadding { Horizontal = SettingsPanel.CONTENT_MARGINS }
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Direction = FillDirection.Vertical,
|
||||
Padding = new MarginPadding { Horizontal = SettingsPanel.CONTENT_MARGINS },
|
||||
Spacing = new Vector2(5f),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
Text = TabletSettingsStrings.NoTabletDetected,
|
||||
},
|
||||
new SettingsNoticeText(colours)
|
||||
{
|
||||
TextAnchor = Anchor.TopCentre,
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
}.With(t =>
|
||||
{
|
||||
if (RuntimeInfo.OS == RuntimeInfo.Platform.Windows || RuntimeInfo.OS == RuntimeInfo.Platform.Linux)
|
||||
{
|
||||
t.NewLine();
|
||||
t.AddText("If your tablet is not detected, please read ");
|
||||
t.AddLink("this FAQ", LinkAction.External, RuntimeInfo.OS == RuntimeInfo.Platform.Windows
|
||||
? @"https://github.com/OpenTabletDriver/OpenTabletDriver/wiki/Windows-FAQ"
|
||||
: @"https://github.com/OpenTabletDriver/OpenTabletDriver/wiki/Linux-FAQ");
|
||||
t.AddText(" for troubleshooting steps.");
|
||||
}
|
||||
}),
|
||||
}
|
||||
},
|
||||
mainSettings = new FillFlowContainer
|
||||
{
|
||||
@ -164,6 +196,9 @@ namespace osu.Game.Overlays.Settings.Sections.Input
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
enabled.BindTo(tabletHandler.Enabled);
|
||||
enabled.BindValueChanged(_ => Scheduler.AddOnce(updateVisibility));
|
||||
|
||||
rotation.BindTo(tabletHandler.Rotation);
|
||||
|
||||
areaOffset.BindTo(tabletHandler.AreaOffset);
|
||||
@ -209,7 +244,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input
|
||||
tablet.BindTo(tabletHandler.Tablet);
|
||||
tablet.BindValueChanged(val =>
|
||||
{
|
||||
Scheduler.AddOnce(toggleVisibility);
|
||||
Scheduler.AddOnce(updateVisibility);
|
||||
|
||||
var tab = val.NewValue;
|
||||
|
||||
@ -229,19 +264,18 @@ namespace osu.Game.Overlays.Settings.Sections.Input
|
||||
}, true);
|
||||
}
|
||||
|
||||
private void toggleVisibility()
|
||||
private void updateVisibility()
|
||||
{
|
||||
bool tabletFound = tablet.Value != null;
|
||||
|
||||
if (!tabletFound)
|
||||
{
|
||||
mainSettings.Hide();
|
||||
noTabletMessage.Show();
|
||||
return;
|
||||
}
|
||||
|
||||
mainSettings.Show();
|
||||
mainSettings.Hide();
|
||||
noTabletMessage.Hide();
|
||||
|
||||
if (!tabletHandler.Enabled.Value)
|
||||
return;
|
||||
|
||||
if (tablet.Value != null)
|
||||
mainSettings.Show();
|
||||
else
|
||||
noTabletMessage.Show();
|
||||
}
|
||||
|
||||
private void applyAspectRatio(BindableNumber<float> sizeChanged)
|
||||
|
@ -11,6 +11,7 @@ using osu.Framework.Input.Handlers.Mouse;
|
||||
using osu.Framework.Input.Handlers.Tablet;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Game.Localisation;
|
||||
using osu.Game.Overlays.Settings.Sections.Input;
|
||||
|
||||
namespace osu.Game.Overlays.Settings.Sections
|
||||
@ -19,7 +20,7 @@ namespace osu.Game.Overlays.Settings.Sections
|
||||
{
|
||||
private readonly KeyBindingPanel keyConfig;
|
||||
|
||||
public override string Header => "Input";
|
||||
public override LocalisableString Header => InputSettingsStrings.InputSectionHeader;
|
||||
|
||||
[Resolved]
|
||||
private GameHost host { get; set; }
|
||||
@ -95,7 +96,7 @@ namespace osu.Game.Overlays.Settings.Sections
|
||||
{
|
||||
new SettingsCheckbox
|
||||
{
|
||||
LabelText = "Enabled",
|
||||
LabelText = CommonStrings.Enabled,
|
||||
Current = handler.Enabled
|
||||
},
|
||||
};
|
||||
|
@ -14,6 +14,7 @@ using osu.Framework.Localisation;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Localisation;
|
||||
|
||||
namespace osu.Game.Overlays.Settings.Sections.Maintenance
|
||||
{
|
||||
@ -104,7 +105,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance
|
||||
Origin = Anchor.Centre,
|
||||
Width = 300,
|
||||
Margin = new MarginPadding(10),
|
||||
Text = "Select directory",
|
||||
Text = MaintenanceSettingsStrings.SelectDirectory,
|
||||
Action = () => OnSelection(directorySelector.CurrentPath.Value)
|
||||
},
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ using osu.Game.Beatmaps;
|
||||
using osu.Game.Collections;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Localisation;
|
||||
using osu.Game.Scoring;
|
||||
using osu.Game.Skinning;
|
||||
|
||||
@ -37,7 +38,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance
|
||||
{
|
||||
Add(importBeatmapsButton = new SettingsButton
|
||||
{
|
||||
Text = "Import beatmaps from stable",
|
||||
Text = MaintenanceSettingsStrings.ImportBeatmapsFromStable,
|
||||
Action = () =>
|
||||
{
|
||||
importBeatmapsButton.Enabled.Value = false;
|
||||
@ -48,7 +49,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance
|
||||
|
||||
Add(deleteBeatmapsButton = new DangerousSettingsButton
|
||||
{
|
||||
Text = "Delete ALL beatmaps",
|
||||
Text = MaintenanceSettingsStrings.DeleteAllBeatmaps,
|
||||
Action = () =>
|
||||
{
|
||||
dialogOverlay?.Push(new DeleteAllBeatmapsDialog(() =>
|
||||
@ -63,7 +64,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance
|
||||
{
|
||||
Add(importScoresButton = new SettingsButton
|
||||
{
|
||||
Text = "Import scores from stable",
|
||||
Text = MaintenanceSettingsStrings.ImportScoresFromStable,
|
||||
Action = () =>
|
||||
{
|
||||
importScoresButton.Enabled.Value = false;
|
||||
@ -74,7 +75,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance
|
||||
|
||||
Add(deleteScoresButton = new DangerousSettingsButton
|
||||
{
|
||||
Text = "Delete ALL scores",
|
||||
Text = MaintenanceSettingsStrings.DeleteAllScores,
|
||||
Action = () =>
|
||||
{
|
||||
dialogOverlay?.Push(new DeleteAllBeatmapsDialog(() =>
|
||||
@ -89,7 +90,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance
|
||||
{
|
||||
Add(importSkinsButton = new SettingsButton
|
||||
{
|
||||
Text = "Import skins from stable",
|
||||
Text = MaintenanceSettingsStrings.ImportSkinsFromStable,
|
||||
Action = () =>
|
||||
{
|
||||
importSkinsButton.Enabled.Value = false;
|
||||
@ -100,7 +101,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance
|
||||
|
||||
Add(deleteSkinsButton = new DangerousSettingsButton
|
||||
{
|
||||
Text = "Delete ALL skins",
|
||||
Text = MaintenanceSettingsStrings.DeleteAllSkins,
|
||||
Action = () =>
|
||||
{
|
||||
dialogOverlay?.Push(new DeleteAllBeatmapsDialog(() =>
|
||||
@ -117,7 +118,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance
|
||||
{
|
||||
Add(importCollectionsButton = new SettingsButton
|
||||
{
|
||||
Text = "Import collections from stable",
|
||||
Text = MaintenanceSettingsStrings.ImportCollectionsFromStable,
|
||||
Action = () =>
|
||||
{
|
||||
importCollectionsButton.Enabled.Value = false;
|
||||
@ -128,7 +129,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance
|
||||
|
||||
Add(new DangerousSettingsButton
|
||||
{
|
||||
Text = "Delete ALL collections",
|
||||
Text = MaintenanceSettingsStrings.DeleteAllCollections,
|
||||
Action = () =>
|
||||
{
|
||||
dialogOverlay?.Push(new DeleteAllBeatmapsDialog(collectionManager.DeleteAll));
|
||||
@ -140,7 +141,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance
|
||||
{
|
||||
restoreButton = new SettingsButton
|
||||
{
|
||||
Text = "Restore all hidden difficulties",
|
||||
Text = MaintenanceSettingsStrings.RestoreAllHiddenDifficulties,
|
||||
Action = () =>
|
||||
{
|
||||
restoreButton.Enabled.Value = false;
|
||||
@ -153,7 +154,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance
|
||||
},
|
||||
undeleteButton = new SettingsButton
|
||||
{
|
||||
Text = "Restore all recently deleted beatmaps",
|
||||
Text = MaintenanceSettingsStrings.RestoreAllRecentlyDeletedBeatmaps,
|
||||
Action = () =>
|
||||
{
|
||||
undeleteButton.Enabled.Value = false;
|
||||
|
@ -3,6 +3,8 @@
|
||||
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Localisation;
|
||||
using osu.Game.Overlays.Settings.Sections.Maintenance;
|
||||
using osuTK;
|
||||
|
||||
@ -10,7 +12,7 @@ namespace osu.Game.Overlays.Settings.Sections
|
||||
{
|
||||
public class MaintenanceSection : SettingsSection
|
||||
{
|
||||
public override string Header => "Maintenance";
|
||||
public override LocalisableString Header => MaintenanceSettingsStrings.MaintenanceSectionHeader;
|
||||
|
||||
public override Drawable CreateIcon() => new SpriteIcon
|
||||
{
|
||||
|
@ -5,12 +5,13 @@ using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Localisation;
|
||||
|
||||
namespace osu.Game.Overlays.Settings.Sections.Online
|
||||
{
|
||||
public class AlertsAndPrivacySettings : SettingsSubsection
|
||||
{
|
||||
protected override LocalisableString Header => "Alerts and Privacy";
|
||||
protected override LocalisableString Header => OnlineSettingsStrings.AlertsAndPrivacyHeader;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuConfigManager config)
|
||||
@ -19,12 +20,12 @@ namespace osu.Game.Overlays.Settings.Sections.Online
|
||||
{
|
||||
new SettingsCheckbox
|
||||
{
|
||||
LabelText = "Show a notification when someone mentions your name",
|
||||
LabelText = OnlineSettingsStrings.NotifyOnMentioned,
|
||||
Current = config.GetBindable<bool>(OsuSetting.NotifyOnUsernameMentioned)
|
||||
},
|
||||
new SettingsCheckbox
|
||||
{
|
||||
LabelText = "Show a notification when you receive a private message",
|
||||
LabelText = OnlineSettingsStrings.NotifyOnPrivateMessage,
|
||||
Current = config.GetBindable<bool>(OsuSetting.NotifyOnPrivateMessage)
|
||||
},
|
||||
};
|
||||
|
@ -5,12 +5,13 @@ using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Localisation;
|
||||
|
||||
namespace osu.Game.Overlays.Settings.Sections.Online
|
||||
{
|
||||
public class IntegrationSettings : SettingsSubsection
|
||||
{
|
||||
protected override LocalisableString Header => "Integrations";
|
||||
protected override LocalisableString Header => OnlineSettingsStrings.IntegrationsHeader;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuConfigManager config)
|
||||
@ -19,7 +20,7 @@ namespace osu.Game.Overlays.Settings.Sections.Online
|
||||
{
|
||||
new SettingsEnumDropdown<DiscordRichPresenceMode>
|
||||
{
|
||||
LabelText = "Discord Rich Presence",
|
||||
LabelText = OnlineSettingsStrings.DiscordRichPresence,
|
||||
Current = config.GetBindable<DiscordRichPresenceMode>(OsuSetting.DiscordRichPresence)
|
||||
}
|
||||
};
|
||||
|
@ -5,12 +5,13 @@ using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Localisation;
|
||||
|
||||
namespace osu.Game.Overlays.Settings.Sections.Online
|
||||
{
|
||||
public class WebSettings : SettingsSubsection
|
||||
{
|
||||
protected override LocalisableString Header => "Web";
|
||||
protected override LocalisableString Header => OnlineSettingsStrings.WebHeader;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuConfigManager config)
|
||||
@ -19,24 +20,24 @@ namespace osu.Game.Overlays.Settings.Sections.Online
|
||||
{
|
||||
new SettingsCheckbox
|
||||
{
|
||||
LabelText = "Warn about opening external links",
|
||||
LabelText = OnlineSettingsStrings.ExternalLinkWarning,
|
||||
Current = config.GetBindable<bool>(OsuSetting.ExternalLinkWarning)
|
||||
},
|
||||
new SettingsCheckbox
|
||||
{
|
||||
LabelText = "Prefer downloads without video",
|
||||
LabelText = OnlineSettingsStrings.PreferNoVideo,
|
||||
Keywords = new[] { "no-video" },
|
||||
Current = config.GetBindable<bool>(OsuSetting.PreferNoVideo)
|
||||
},
|
||||
new SettingsCheckbox
|
||||
{
|
||||
LabelText = "Automatically download beatmaps when spectating",
|
||||
LabelText = OnlineSettingsStrings.AutomaticallyDownloadWhenSpectating,
|
||||
Keywords = new[] { "spectator" },
|
||||
Current = config.GetBindable<bool>(OsuSetting.AutomaticallyDownloadWhenSpectating),
|
||||
},
|
||||
new SettingsCheckbox
|
||||
{
|
||||
LabelText = "Show explicit content in search results",
|
||||
LabelText = OnlineSettingsStrings.ShowExplicitContent,
|
||||
Keywords = new[] { "nsfw", "18+", "offensive" },
|
||||
Current = config.GetBindable<bool>(OsuSetting.ShowOnlineExplicitContent),
|
||||
}
|
||||
|
@ -3,13 +3,15 @@
|
||||
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Localisation;
|
||||
using osu.Game.Overlays.Settings.Sections.Online;
|
||||
|
||||
namespace osu.Game.Overlays.Settings.Sections
|
||||
{
|
||||
public class OnlineSection : SettingsSection
|
||||
{
|
||||
public override string Header => "Online";
|
||||
public override LocalisableString Header => OnlineSettingsStrings.OnlineSectionHeader;
|
||||
|
||||
public override Drawable CreateIcon() => new SpriteIcon
|
||||
{
|
||||
|
@ -13,6 +13,7 @@ using osu.Framework.Localisation;
|
||||
using osu.Framework.Logging;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Localisation;
|
||||
using osu.Game.Skinning;
|
||||
using osu.Game.Skinning.Editor;
|
||||
using osuTK;
|
||||
@ -23,7 +24,7 @@ namespace osu.Game.Overlays.Settings.Sections
|
||||
{
|
||||
private SkinSettingsDropdown skinDropdown;
|
||||
|
||||
public override string Header => "Skin";
|
||||
public override LocalisableString Header => SkinSettingsStrings.SkinSectionHeader;
|
||||
|
||||
public override Drawable CreateIcon() => new SpriteIcon
|
||||
{
|
||||
@ -69,34 +70,34 @@ namespace osu.Game.Overlays.Settings.Sections
|
||||
skinDropdown = new SkinSettingsDropdown(),
|
||||
new SettingsButton
|
||||
{
|
||||
Text = "Skin layout editor",
|
||||
Text = SkinSettingsStrings.SkinLayoutEditor,
|
||||
Action = () => skinEditor?.Toggle(),
|
||||
},
|
||||
new ExportSkinButton(),
|
||||
new SettingsSlider<float, SizeSlider>
|
||||
{
|
||||
LabelText = "Gameplay cursor size",
|
||||
LabelText = SkinSettingsStrings.GameplayCursorSize,
|
||||
Current = config.GetBindable<float>(OsuSetting.GameplayCursorSize),
|
||||
KeyboardStep = 0.01f
|
||||
},
|
||||
new SettingsCheckbox
|
||||
{
|
||||
LabelText = "Adjust gameplay cursor size based on current beatmap",
|
||||
LabelText = SkinSettingsStrings.AutoCursorSize,
|
||||
Current = config.GetBindable<bool>(OsuSetting.AutoCursorSize)
|
||||
},
|
||||
new SettingsCheckbox
|
||||
{
|
||||
LabelText = "Beatmap skins",
|
||||
LabelText = SkinSettingsStrings.BeatmapSkins,
|
||||
Current = config.GetBindable<bool>(OsuSetting.BeatmapSkins)
|
||||
},
|
||||
new SettingsCheckbox
|
||||
{
|
||||
LabelText = "Beatmap colours",
|
||||
LabelText = SkinSettingsStrings.BeatmapColours,
|
||||
Current = config.GetBindable<bool>(OsuSetting.BeatmapColours)
|
||||
},
|
||||
new SettingsCheckbox
|
||||
{
|
||||
LabelText = "Beatmap hitsounds",
|
||||
LabelText = SkinSettingsStrings.BeatmapHitsounds,
|
||||
Current = config.GetBindable<bool>(OsuSetting.BeatmapHitsounds)
|
||||
},
|
||||
};
|
||||
@ -200,7 +201,7 @@ namespace osu.Game.Overlays.Settings.Sections
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
Text = "Export selected skin";
|
||||
Text = SkinSettingsStrings.ExportSkinButton;
|
||||
Action = export;
|
||||
|
||||
currentSkin = skins.CurrentSkin.GetBoundCopy();
|
||||
|
@ -6,12 +6,13 @@ using osu.Framework.Graphics;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Localisation;
|
||||
|
||||
namespace osu.Game.Overlays.Settings.Sections.UserInterface
|
||||
{
|
||||
public class GeneralSettings : SettingsSubsection
|
||||
{
|
||||
protected override LocalisableString Header => "General";
|
||||
protected override LocalisableString Header => UserInterfaceStrings.GeneralHeader;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuConfigManager config)
|
||||
@ -20,23 +21,23 @@ namespace osu.Game.Overlays.Settings.Sections.UserInterface
|
||||
{
|
||||
new SettingsCheckbox
|
||||
{
|
||||
LabelText = "Rotate cursor when dragging",
|
||||
LabelText = UserInterfaceStrings.CursorRotation,
|
||||
Current = config.GetBindable<bool>(OsuSetting.CursorRotation)
|
||||
},
|
||||
new SettingsSlider<float, SizeSlider>
|
||||
{
|
||||
LabelText = "Menu cursor size",
|
||||
LabelText = UserInterfaceStrings.MenuCursorSize,
|
||||
Current = config.GetBindable<float>(OsuSetting.MenuCursorSize),
|
||||
KeyboardStep = 0.01f
|
||||
},
|
||||
new SettingsCheckbox
|
||||
{
|
||||
LabelText = "Parallax",
|
||||
LabelText = UserInterfaceStrings.Parallax,
|
||||
Current = config.GetBindable<bool>(OsuSetting.MenuParallax)
|
||||
},
|
||||
new SettingsSlider<float, TimeSlider>
|
||||
{
|
||||
LabelText = "Hold-to-confirm activation time",
|
||||
LabelText = UserInterfaceStrings.HoldToConfirmActivationTime,
|
||||
Current = config.GetBindable<float>(OsuSetting.UIHoldActivationDelay),
|
||||
KeyboardStep = 50
|
||||
},
|
||||
|
@ -6,6 +6,7 @@ using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Localisation;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Users;
|
||||
|
||||
@ -13,7 +14,7 @@ namespace osu.Game.Overlays.Settings.Sections.UserInterface
|
||||
{
|
||||
public class MainMenuSettings : SettingsSubsection
|
||||
{
|
||||
protected override LocalisableString Header => "Main Menu";
|
||||
protected override LocalisableString Header => UserInterfaceStrings.MainMenuHeader;
|
||||
|
||||
private IBindable<User> user;
|
||||
|
||||
@ -28,27 +29,27 @@ namespace osu.Game.Overlays.Settings.Sections.UserInterface
|
||||
{
|
||||
new SettingsCheckbox
|
||||
{
|
||||
LabelText = "Interface voices",
|
||||
LabelText = UserInterfaceStrings.InterfaceVoices,
|
||||
Current = config.GetBindable<bool>(OsuSetting.MenuVoice)
|
||||
},
|
||||
new SettingsCheckbox
|
||||
{
|
||||
LabelText = "osu! music theme",
|
||||
LabelText = UserInterfaceStrings.OsuMusicTheme,
|
||||
Current = config.GetBindable<bool>(OsuSetting.MenuMusic)
|
||||
},
|
||||
new SettingsEnumDropdown<IntroSequence>
|
||||
{
|
||||
LabelText = "Intro sequence",
|
||||
LabelText = UserInterfaceStrings.IntroSequence,
|
||||
Current = config.GetBindable<IntroSequence>(OsuSetting.IntroSequence),
|
||||
},
|
||||
backgroundSourceDropdown = new SettingsEnumDropdown<BackgroundSource>
|
||||
{
|
||||
LabelText = "Background source",
|
||||
LabelText = UserInterfaceStrings.BackgroundSource,
|
||||
Current = config.GetBindable<BackgroundSource>(OsuSetting.MenuBackgroundSource),
|
||||
},
|
||||
new SettingsEnumDropdown<SeasonalBackgroundMode>
|
||||
{
|
||||
LabelText = "Seasonal backgrounds",
|
||||
LabelText = UserInterfaceStrings.SeasonalBackgrounds,
|
||||
Current = config.GetBindable<SeasonalBackgroundMode>(OsuSetting.SeasonalBackgroundMode),
|
||||
}
|
||||
};
|
||||
@ -60,9 +61,7 @@ namespace osu.Game.Overlays.Settings.Sections.UserInterface
|
||||
|
||||
user.BindValueChanged(u =>
|
||||
{
|
||||
const string not_supporter_note = "Changes to this setting will only apply with an active osu!supporter tag.";
|
||||
|
||||
backgroundSourceDropdown.WarningText = u.NewValue?.IsSupporter != true ? not_supporter_note : string.Empty;
|
||||
backgroundSourceDropdown.WarningText = u.NewValue?.IsSupporter != true ? UserInterfaceStrings.NotSupporterNote : default;
|
||||
}, true);
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user