mirror of
https://github.com/ppy/osu.git
synced 2024-11-11 12:17:26 +08:00
Merge branch 'master' into no-unranked-display
This commit is contained in:
commit
a44fd887ee
@ -52,6 +52,6 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.525.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2021.608.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2021.609.0" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
@ -8,9 +8,7 @@ namespace osu.Game.Rulesets.Catch
|
||||
Fruit,
|
||||
Banana,
|
||||
Droplet,
|
||||
CatcherIdle,
|
||||
CatcherFail,
|
||||
CatcherKiai,
|
||||
Catcher,
|
||||
CatchComboCounter
|
||||
}
|
||||
}
|
||||
|
54
osu.Game.Rulesets.Catch/Skinning/Default/DefaultCatcher.cs
Normal file
54
osu.Game.Rulesets.Catch/Skinning/Default/DefaultCatcher.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 System.Collections.Generic;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Game.Rulesets.Catch.UI;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Skinning.Default
|
||||
{
|
||||
public class DefaultCatcher : CompositeDrawable, ICatcherSprite
|
||||
{
|
||||
public Bindable<CatcherAnimationState> CurrentState { get; } = new Bindable<CatcherAnimationState>();
|
||||
|
||||
public Texture CurrentTexture => sprite.Texture;
|
||||
|
||||
private readonly Sprite sprite;
|
||||
|
||||
private readonly Dictionary<CatcherAnimationState, Texture> textures = new Dictionary<CatcherAnimationState, Texture>();
|
||||
|
||||
public DefaultCatcher()
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
InternalChild = sprite = new Sprite
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
FillMode = FillMode.Fit
|
||||
};
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(TextureStore store, Bindable<CatcherAnimationState> currentState)
|
||||
{
|
||||
CurrentState.BindTo(currentState);
|
||||
|
||||
textures[CatcherAnimationState.Idle] = store.Get(@"Gameplay/catch/fruit-catcher-idle");
|
||||
textures[CatcherAnimationState.Fail] = store.Get(@"Gameplay/catch/fruit-catcher-fail");
|
||||
textures[CatcherAnimationState.Kiai] = store.Get(@"Gameplay/catch/fruit-catcher-kiai");
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
CurrentState.BindValueChanged(state => sprite.Texture = textures[state.NewValue], true);
|
||||
}
|
||||
}
|
||||
}
|
12
osu.Game.Rulesets.Catch/Skinning/ICatcherSprite.cs
Normal file
12
osu.Game.Rulesets.Catch/Skinning/ICatcherSprite.cs
Normal file
@ -0,0 +1,12 @@
|
||||
// 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.Textures;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Skinning
|
||||
{
|
||||
public interface ICatcherSprite
|
||||
{
|
||||
Texture CurrentTexture { get; }
|
||||
}
|
||||
}
|
@ -65,17 +65,21 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy
|
||||
|
||||
return null;
|
||||
|
||||
case CatchSkinComponents.CatcherIdle:
|
||||
return this.GetAnimation("fruit-catcher-idle", true, true, true) ??
|
||||
this.GetAnimation("fruit-ryuuta", true, true, true);
|
||||
case CatchSkinComponents.Catcher:
|
||||
var version = Source.GetConfig<LegacySkinConfiguration.LegacySetting, decimal>(LegacySkinConfiguration.LegacySetting.Version)?.Value ?? 1;
|
||||
|
||||
case CatchSkinComponents.CatcherFail:
|
||||
return this.GetAnimation("fruit-catcher-fail", true, true, true) ??
|
||||
this.GetAnimation("fruit-ryuuta", true, true, true);
|
||||
if (version < 2.3m)
|
||||
{
|
||||
if (GetTexture(@"fruit-ryuuta") != null ||
|
||||
GetTexture(@"fruit-ryuuta-0") != null)
|
||||
return new LegacyCatcherOld();
|
||||
}
|
||||
|
||||
case CatchSkinComponents.CatcherKiai:
|
||||
return this.GetAnimation("fruit-catcher-kiai", true, true, true) ??
|
||||
this.GetAnimation("fruit-ryuuta", true, true, true);
|
||||
if (GetTexture(@"fruit-catcher-idle") != null ||
|
||||
GetTexture(@"fruit-catcher-idle-0") != null)
|
||||
return new LegacyCatcherNew();
|
||||
|
||||
return null;
|
||||
|
||||
case CatchSkinComponents.CatchComboCounter:
|
||||
if (providesComboCounter)
|
||||
|
73
osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyCatcherNew.cs
Normal file
73
osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyCatcherNew.cs
Normal file
@ -0,0 +1,73 @@
|
||||
// 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 System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Animations;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Game.Rulesets.Catch.UI;
|
||||
using osu.Game.Skinning;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Skinning.Legacy
|
||||
{
|
||||
public class LegacyCatcherNew : CompositeDrawable, ICatcherSprite
|
||||
{
|
||||
[Resolved]
|
||||
private Bindable<CatcherAnimationState> currentState { get; set; }
|
||||
|
||||
public Texture CurrentTexture => (currentDrawable as TextureAnimation)?.CurrentFrame ?? (currentDrawable as Sprite)?.Texture;
|
||||
|
||||
private readonly Dictionary<CatcherAnimationState, Drawable> drawables = new Dictionary<CatcherAnimationState, Drawable>();
|
||||
|
||||
private Drawable currentDrawable;
|
||||
|
||||
public LegacyCatcherNew()
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(ISkinSource skin)
|
||||
{
|
||||
foreach (var state in Enum.GetValues(typeof(CatcherAnimationState)).Cast<CatcherAnimationState>())
|
||||
{
|
||||
AddInternal(drawables[state] = getDrawableFor(state).With(d =>
|
||||
{
|
||||
d.Anchor = Anchor.TopCentre;
|
||||
d.Origin = Anchor.TopCentre;
|
||||
d.RelativeSizeAxes = Axes.Both;
|
||||
d.Size = Vector2.One;
|
||||
d.FillMode = FillMode.Fit;
|
||||
d.Alpha = 0;
|
||||
}));
|
||||
}
|
||||
|
||||
currentDrawable = drawables[CatcherAnimationState.Idle];
|
||||
|
||||
Drawable getDrawableFor(CatcherAnimationState state) =>
|
||||
skin.GetAnimation(@$"fruit-catcher-{state.ToString().ToLowerInvariant()}", true, true, true) ??
|
||||
skin.GetAnimation(@"fruit-catcher-idle", true, true, true);
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
currentState.BindValueChanged(state =>
|
||||
{
|
||||
currentDrawable.Alpha = 0;
|
||||
currentDrawable = drawables[state.NewValue];
|
||||
currentDrawable.Alpha = 1;
|
||||
|
||||
(currentDrawable as IFramedAnimation)?.GotoFrame(0);
|
||||
}, true);
|
||||
}
|
||||
}
|
||||
}
|
37
osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyCatcherOld.cs
Normal file
37
osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyCatcherOld.cs
Normal file
@ -0,0 +1,37 @@
|
||||
// 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;
|
||||
using osu.Framework.Graphics.Animations;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Game.Skinning;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Skinning.Legacy
|
||||
{
|
||||
public class LegacyCatcherOld : CompositeDrawable, ICatcherSprite
|
||||
{
|
||||
public Texture CurrentTexture => (InternalChild as TextureAnimation)?.CurrentFrame ?? (InternalChild as Sprite)?.Texture;
|
||||
|
||||
public LegacyCatcherOld()
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(ISkinSource skin)
|
||||
{
|
||||
InternalChild = skin.GetAnimation(@"fruit-ryuuta", true, true, true).With(d =>
|
||||
{
|
||||
d.Anchor = Anchor.TopCentre;
|
||||
d.Origin = Anchor.TopCentre;
|
||||
d.RelativeSizeAxes = Axes.Both;
|
||||
d.Size = Vector2.One;
|
||||
d.FillMode = FillMode.Fit;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -7,9 +7,9 @@ using JetBrains.Annotations;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Animations;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Pooling;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Framework.Input.Bindings;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Game.Beatmaps;
|
||||
@ -18,6 +18,7 @@ using osu.Game.Rulesets.Catch.Judgements;
|
||||
using osu.Game.Rulesets.Catch.Objects;
|
||||
using osu.Game.Rulesets.Catch.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Catch.Skinning;
|
||||
using osu.Game.Rulesets.Catch.Skinning.Default;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Skinning;
|
||||
using osuTK;
|
||||
@ -78,17 +79,17 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
/// </summary>
|
||||
private readonly Container<CaughtObject> droppedObjectTarget;
|
||||
|
||||
public CatcherAnimationState CurrentState { get; private set; }
|
||||
[Cached]
|
||||
protected readonly Bindable<CatcherAnimationState> CurrentStateBindable = new Bindable<CatcherAnimationState>();
|
||||
|
||||
public CatcherAnimationState CurrentState => CurrentStateBindable.Value;
|
||||
|
||||
/// <summary>
|
||||
/// The width of the catcher which can receive fruit. Equivalent to "catchMargin" in osu-stable.
|
||||
/// </summary>
|
||||
public const float ALLOWED_CATCH_RANGE = 0.8f;
|
||||
|
||||
/// <summary>
|
||||
/// The drawable catcher for <see cref="CurrentState"/>.
|
||||
/// </summary>
|
||||
internal Drawable CurrentDrawableCatcher => currentCatcher.Drawable;
|
||||
internal Texture CurrentTexture => ((ICatcherSprite)currentCatcher.Drawable).CurrentTexture;
|
||||
|
||||
private bool dashing;
|
||||
|
||||
@ -110,11 +111,7 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
/// </summary>
|
||||
private readonly float catchWidth;
|
||||
|
||||
private readonly CatcherSprite catcherIdle;
|
||||
private readonly CatcherSprite catcherKiai;
|
||||
private readonly CatcherSprite catcherFail;
|
||||
|
||||
private CatcherSprite currentCatcher;
|
||||
private readonly SkinnableDrawable currentCatcher;
|
||||
|
||||
private Color4 hyperDashColour = DEFAULT_HYPER_DASH_COLOUR;
|
||||
private Color4 hyperDashEndGlowColour = DEFAULT_HYPER_DASH_COLOUR;
|
||||
@ -156,20 +153,12 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.BottomCentre,
|
||||
},
|
||||
catcherIdle = new CatcherSprite(CatcherAnimationState.Idle)
|
||||
currentCatcher = new SkinnableDrawable(
|
||||
new CatchSkinComponent(CatchSkinComponents.Catcher),
|
||||
_ => new DefaultCatcher())
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Alpha = 0,
|
||||
},
|
||||
catcherKiai = new CatcherSprite(CatcherAnimationState.Kiai)
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Alpha = 0,
|
||||
},
|
||||
catcherFail = new CatcherSprite(CatcherAnimationState.Fail)
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Alpha = 0,
|
||||
OriginPosition = new Vector2(0.5f, 0.06f) * CatcherArea.CATCHER_SIZE
|
||||
},
|
||||
hitExplosionContainer = new HitExplosionContainer
|
||||
{
|
||||
@ -184,8 +173,6 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
{
|
||||
hitLighting = config.GetBindable<bool>(OsuSetting.HitLighting);
|
||||
trails = new CatcherTrailDisplay(this);
|
||||
|
||||
updateCatcher();
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
@ -436,36 +423,12 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
}
|
||||
}
|
||||
|
||||
private void updateCatcher()
|
||||
{
|
||||
currentCatcher?.Hide();
|
||||
|
||||
switch (CurrentState)
|
||||
{
|
||||
default:
|
||||
currentCatcher = catcherIdle;
|
||||
break;
|
||||
|
||||
case CatcherAnimationState.Fail:
|
||||
currentCatcher = catcherFail;
|
||||
break;
|
||||
|
||||
case CatcherAnimationState.Kiai:
|
||||
currentCatcher = catcherKiai;
|
||||
break;
|
||||
}
|
||||
|
||||
currentCatcher.Show();
|
||||
(currentCatcher.Drawable as IFramedAnimation)?.GotoFrame(0);
|
||||
}
|
||||
|
||||
private void updateState(CatcherAnimationState state)
|
||||
{
|
||||
if (CurrentState == state)
|
||||
return;
|
||||
|
||||
CurrentState = state;
|
||||
updateCatcher();
|
||||
CurrentStateBindable.Value = state;
|
||||
}
|
||||
|
||||
private void placeCaughtObject(DrawablePalpableCatchHitObject drawableObject, Vector2 position)
|
||||
|
@ -1,59 +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;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Game.Skinning;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.UI
|
||||
{
|
||||
public class CatcherSprite : SkinnableDrawable
|
||||
{
|
||||
protected override bool ApplySizeRestrictionsToDefault => true;
|
||||
|
||||
public CatcherSprite(CatcherAnimationState state)
|
||||
: base(new CatchSkinComponent(componentFromState(state)), _ =>
|
||||
new DefaultCatcherSprite(state), confineMode: ConfineMode.ScaleToFit)
|
||||
{
|
||||
RelativeSizeAxes = Axes.None;
|
||||
Size = new Vector2(CatcherArea.CATCHER_SIZE);
|
||||
|
||||
// Sets the origin roughly to the centre of the catcher's plate to allow for correct scaling.
|
||||
OriginPosition = new Vector2(0.5f, 0.06f) * CatcherArea.CATCHER_SIZE;
|
||||
}
|
||||
|
||||
private static CatchSkinComponents componentFromState(CatcherAnimationState state)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case CatcherAnimationState.Fail:
|
||||
return CatchSkinComponents.CatcherFail;
|
||||
|
||||
case CatcherAnimationState.Kiai:
|
||||
return CatchSkinComponents.CatcherKiai;
|
||||
|
||||
default:
|
||||
return CatchSkinComponents.CatcherIdle;
|
||||
}
|
||||
}
|
||||
|
||||
private class DefaultCatcherSprite : Sprite
|
||||
{
|
||||
private readonly CatcherAnimationState state;
|
||||
|
||||
public DefaultCatcherSprite(CatcherAnimationState state)
|
||||
{
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(TextureStore textures)
|
||||
{
|
||||
Texture = textures.Get($"Gameplay/catch/fruit-catcher-{state.ToString().ToLower()}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -4,10 +4,8 @@
|
||||
using System;
|
||||
using JetBrains.Annotations;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Animations;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Pooling;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
@ -120,11 +118,9 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
|
||||
private CatcherTrailSprite createTrailSprite(Container<CatcherTrailSprite> target)
|
||||
{
|
||||
var texture = (catcher.CurrentDrawableCatcher as TextureAnimation)?.CurrentFrame ?? ((Sprite)catcher.CurrentDrawableCatcher).Texture;
|
||||
|
||||
CatcherTrailSprite sprite = trailPool.Get();
|
||||
|
||||
sprite.Texture = texture;
|
||||
sprite.Texture = catcher.CurrentTexture;
|
||||
sprite.Anchor = catcher.Anchor;
|
||||
sprite.Scale = catcher.Scale;
|
||||
sprite.Blending = BlendingParameters.Additive;
|
||||
|
@ -71,7 +71,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy
|
||||
{
|
||||
isLegacySkin = new Lazy<bool>(() => FindProvider(s => s.GetConfig<LegacySkinConfiguration.LegacySetting, decimal>(LegacySkinConfiguration.LegacySetting.Version) != null) != null);
|
||||
hasKeyTexture = new Lazy<bool>(() => FindProvider(s => s.GetAnimation(
|
||||
this.GetManiaSkinConfig<string>(LegacyManiaSkinConfigurationLookups.KeyImage, 0)?.Value
|
||||
s.GetManiaSkinConfig<string>(LegacyManiaSkinConfigurationLookups.KeyImage, 0)?.Value
|
||||
?? "mania-key1", true, true) != null) != null);
|
||||
}
|
||||
|
||||
|
@ -15,8 +15,6 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default
|
||||
{
|
||||
public class MainCirclePiece : CompositeDrawable
|
||||
{
|
||||
public override bool RemoveCompletedTransforms => false;
|
||||
|
||||
private readonly CirclePiece circle;
|
||||
private readonly RingPiece ring;
|
||||
private readonly FlashPiece flash;
|
||||
@ -44,7 +42,6 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default
|
||||
|
||||
private readonly IBindable<Color4> accentColour = new Bindable<Color4>();
|
||||
private readonly IBindable<int> indexInCurrentCombo = new Bindable<int>();
|
||||
private readonly IBindable<ArmedState> armedState = new Bindable<ArmedState>();
|
||||
|
||||
[Resolved]
|
||||
private DrawableHitObject drawableObject { get; set; }
|
||||
@ -56,7 +53,6 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default
|
||||
|
||||
accentColour.BindTo(drawableObject.AccentColour);
|
||||
indexInCurrentCombo.BindTo(drawableOsuObject.IndexInCurrentComboBindable);
|
||||
armedState.BindTo(drawableObject.State);
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
@ -72,19 +68,18 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default
|
||||
|
||||
indexInCurrentCombo.BindValueChanged(index => number.Text = (index.NewValue + 1).ToString(), true);
|
||||
|
||||
armedState.BindValueChanged(animate, true);
|
||||
drawableObject.ApplyCustomUpdateState += updateStateTransforms;
|
||||
updateStateTransforms(drawableObject, drawableObject.State.Value);
|
||||
}
|
||||
|
||||
private void animate(ValueChangedEvent<ArmedState> state)
|
||||
private void updateStateTransforms(DrawableHitObject drawableHitObject, ArmedState state)
|
||||
{
|
||||
ClearTransforms(true);
|
||||
|
||||
using (BeginAbsoluteSequence(drawableObject.StateUpdateTime))
|
||||
glow.FadeOut(400);
|
||||
|
||||
using (BeginAbsoluteSequence(drawableObject.HitStateUpdateTime))
|
||||
{
|
||||
switch (state.NewValue)
|
||||
switch (state)
|
||||
{
|
||||
case ArmedState.Hit:
|
||||
const double flash_in = 40;
|
||||
@ -111,5 +106,13 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
{
|
||||
base.Dispose(isDisposing);
|
||||
|
||||
if (drawableObject != null)
|
||||
drawableObject.ApplyCustomUpdateState -= updateStateTransforms;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -41,7 +41,6 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
||||
|
||||
private readonly Bindable<Color4> accentColour = new Bindable<Color4>();
|
||||
private readonly IBindable<int> indexInCurrentCombo = new Bindable<int>();
|
||||
private readonly IBindable<ArmedState> armedState = new Bindable<ArmedState>();
|
||||
|
||||
[Resolved]
|
||||
private DrawableHitObject drawableObject { get; set; }
|
||||
@ -116,7 +115,6 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
||||
|
||||
accentColour.BindTo(drawableObject.AccentColour);
|
||||
indexInCurrentCombo.BindTo(drawableOsuObject.IndexInCurrentComboBindable);
|
||||
armedState.BindTo(drawableObject.State);
|
||||
|
||||
Texture getTextureWithFallback(string name)
|
||||
{
|
||||
@ -142,18 +140,17 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
||||
if (hasNumber)
|
||||
indexInCurrentCombo.BindValueChanged(index => hitCircleText.Text = (index.NewValue + 1).ToString(), true);
|
||||
|
||||
armedState.BindValueChanged(animate, true);
|
||||
drawableObject.ApplyCustomUpdateState += updateStateTransforms;
|
||||
updateStateTransforms(drawableObject, drawableObject.State.Value);
|
||||
}
|
||||
|
||||
private void animate(ValueChangedEvent<ArmedState> state)
|
||||
private void updateStateTransforms(DrawableHitObject drawableHitObject, ArmedState state)
|
||||
{
|
||||
const double legacy_fade_duration = 240;
|
||||
|
||||
ClearTransforms(true);
|
||||
|
||||
using (BeginAbsoluteSequence(drawableObject.HitStateUpdateTime))
|
||||
{
|
||||
switch (state.NewValue)
|
||||
switch (state)
|
||||
{
|
||||
case ArmedState.Hit:
|
||||
circleSprites.FadeOut(legacy_fade_duration, Easing.Out);
|
||||
@ -178,5 +175,13 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
{
|
||||
base.Dispose(isDisposing);
|
||||
|
||||
if (drawableObject != null)
|
||||
drawableObject.ApplyCustomUpdateState -= updateStateTransforms;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
@ -11,6 +12,7 @@ using osu.Game.Graphics.Backgrounds;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Screens;
|
||||
using osu.Game.Screens.Backgrounds;
|
||||
using osu.Game.Skinning;
|
||||
using osu.Game.Users;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Background
|
||||
@ -23,6 +25,9 @@ namespace osu.Game.Tests.Visual.Background
|
||||
|
||||
private Graphics.Backgrounds.Background getCurrentBackground() => screen.ChildrenOfType<Graphics.Backgrounds.Background>().FirstOrDefault();
|
||||
|
||||
[Resolved]
|
||||
private SkinManager skins { get; set; }
|
||||
|
||||
[Resolved]
|
||||
private OsuConfigManager config { get; set; }
|
||||
|
||||
@ -35,7 +40,7 @@ namespace osu.Game.Tests.Visual.Background
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestTogglingStoryboardSwitchesBackgroundType()
|
||||
public void TestBackgroundTypeSwitch()
|
||||
{
|
||||
setSupporter(true);
|
||||
|
||||
@ -44,6 +49,12 @@ namespace osu.Game.Tests.Visual.Background
|
||||
|
||||
setSourceMode(BackgroundSource.BeatmapWithStoryboard);
|
||||
AddUntilStep("is storyboard background", () => getCurrentBackground() is BeatmapBackgroundWithStoryboard);
|
||||
|
||||
setSourceMode(BackgroundSource.Skin);
|
||||
AddUntilStep("is default background", () => getCurrentBackground().GetType() == typeof(Graphics.Backgrounds.Background));
|
||||
|
||||
setCustomSkin();
|
||||
AddUntilStep("is skin background", () => getCurrentBackground() is SkinBackground);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@ -61,15 +72,19 @@ namespace osu.Game.Tests.Visual.Background
|
||||
AddUntilStep("is beatmap background", () => getCurrentBackground() is BeatmapBackground);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestBeatmapDoesntReloadOnNoChange()
|
||||
[TestCase(BackgroundSource.Beatmap, typeof(BeatmapBackground))]
|
||||
[TestCase(BackgroundSource.BeatmapWithStoryboard, typeof(BeatmapBackgroundWithStoryboard))]
|
||||
[TestCase(BackgroundSource.Skin, typeof(SkinBackground))]
|
||||
public void TestBackgroundDoesntReloadOnNoChange(BackgroundSource source, Type backgroundType)
|
||||
{
|
||||
BeatmapBackground last = null;
|
||||
Graphics.Backgrounds.Background last = null;
|
||||
|
||||
setSourceMode(BackgroundSource.Beatmap);
|
||||
setSourceMode(source);
|
||||
setSupporter(true);
|
||||
if (source == BackgroundSource.Skin)
|
||||
setCustomSkin();
|
||||
|
||||
AddUntilStep("wait for beatmap background to be loaded", () => (last = getCurrentBackground() as BeatmapBackground) != null);
|
||||
AddUntilStep("wait for beatmap background to be loaded", () => (last = getCurrentBackground())?.GetType() == backgroundType);
|
||||
AddAssert("next doesn't load new background", () => screen.Next() == false);
|
||||
|
||||
// doesn't really need to be checked but might as well.
|
||||
@ -77,8 +92,25 @@ namespace osu.Game.Tests.Visual.Background
|
||||
AddUntilStep("ensure same background instance", () => last == getCurrentBackground());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestBackgroundCyclingOnDefaultSkin([Values] bool supporter)
|
||||
{
|
||||
Graphics.Backgrounds.Background last = null;
|
||||
|
||||
setSourceMode(BackgroundSource.Skin);
|
||||
setSupporter(supporter);
|
||||
setDefaultSkin();
|
||||
|
||||
AddUntilStep("wait for beatmap background to be loaded", () => (last = getCurrentBackground())?.GetType() == typeof(Graphics.Backgrounds.Background));
|
||||
AddAssert("next cycles background", () => screen.Next());
|
||||
|
||||
// doesn't really need to be checked but might as well.
|
||||
AddWaitStep("wait a bit", 5);
|
||||
AddUntilStep("ensure different background instance", () => last != getCurrentBackground());
|
||||
}
|
||||
|
||||
private void setSourceMode(BackgroundSource source) =>
|
||||
AddStep("set background mode to beatmap", () => config.SetValue(OsuSetting.MenuBackgroundSource, source));
|
||||
AddStep($"set background mode to {source}", () => config.SetValue(OsuSetting.MenuBackgroundSource, source));
|
||||
|
||||
private void setSupporter(bool isSupporter) =>
|
||||
AddStep($"set supporter {isSupporter}", () => ((DummyAPIAccess)API).LocalUser.Value = new User
|
||||
@ -86,5 +118,16 @@ namespace osu.Game.Tests.Visual.Background
|
||||
IsSupporter = isSupporter,
|
||||
Id = API.LocalUser.Value.Id + 1,
|
||||
});
|
||||
|
||||
private void setCustomSkin()
|
||||
{
|
||||
// feign a skin switch. this doesn't do anything except force CurrentSkin to become a LegacySkin.
|
||||
AddStep("set custom skin", () => skins.CurrentSkinInfo.Value = new SkinInfo { ID = 5 });
|
||||
}
|
||||
|
||||
private void setDefaultSkin() => AddStep("set default skin", () => skins.CurrentSkinInfo.SetDefault());
|
||||
|
||||
[TearDownSteps]
|
||||
public void TearDown() => setDefaultSkin();
|
||||
}
|
||||
}
|
||||
|
@ -109,6 +109,34 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
meter => meter.ChildrenOfType<ColourHitErrorMeter.HitErrorCircle>().Count() == 2));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestBonus()
|
||||
{
|
||||
AddStep("OD 1", () => recreateDisplay(new OsuHitWindows(), 1));
|
||||
|
||||
AddStep("small bonus", () => newJudgement(result: HitResult.SmallBonus));
|
||||
AddAssert("no bars added", () => !this.ChildrenOfType<BarHitErrorMeter.JudgementLine>().Any());
|
||||
AddAssert("no circle added", () => !this.ChildrenOfType<ColourHitErrorMeter.HitErrorCircle>().Any());
|
||||
|
||||
AddStep("large bonus", () => newJudgement(result: HitResult.LargeBonus));
|
||||
AddAssert("no bars added", () => !this.ChildrenOfType<BarHitErrorMeter.JudgementLine>().Any());
|
||||
AddAssert("no circle added", () => !this.ChildrenOfType<ColourHitErrorMeter.HitErrorCircle>().Any());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestIgnore()
|
||||
{
|
||||
AddStep("OD 1", () => recreateDisplay(new OsuHitWindows(), 1));
|
||||
|
||||
AddStep("ignore hit", () => newJudgement(result: HitResult.IgnoreHit));
|
||||
AddAssert("no bars added", () => !this.ChildrenOfType<BarHitErrorMeter.JudgementLine>().Any());
|
||||
AddAssert("no circle added", () => !this.ChildrenOfType<ColourHitErrorMeter.HitErrorCircle>().Any());
|
||||
|
||||
AddStep("ignore miss", () => newJudgement(result: HitResult.IgnoreMiss));
|
||||
AddAssert("no bars added", () => !this.ChildrenOfType<BarHitErrorMeter.JudgementLine>().Any());
|
||||
AddAssert("no circle added", () => !this.ChildrenOfType<ColourHitErrorMeter.HitErrorCircle>().Any());
|
||||
}
|
||||
|
||||
private void recreateDisplay(HitWindows hitWindows, float overallDifficulty)
|
||||
{
|
||||
hitWindows?.SetDifficulty(overallDifficulty);
|
||||
|
@ -143,6 +143,25 @@ Line after image";
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestTableWithImageContent()
|
||||
{
|
||||
AddStep("Add Table", () =>
|
||||
{
|
||||
markdownContainer.DocumentUrl = "https://dev.ppy.sh";
|
||||
markdownContainer.Text = @"
|
||||
| Image | Name | Effect |
|
||||
| :-: | :-: | :-- |
|
||||
| ![](/wiki/Skinning/Interface/img/hit300.png ""300"") | 300 | A possible score when tapping a hit circle precisely on time, completing a Slider and keeping the cursor over every tick, or completing a Spinner with the Spinner Metre full. A score of 300 appears in an blue score by default. Scoring nothing except 300s in a beatmap will award the player with the SS or SSH grade. |
|
||||
| ![](/wiki/Skinning/Interface/img/hit300g.png ""Geki"") | (激) Geki | A term from Ouendan, called Elite Beat! in EBA. Appears when playing the last element in a combo in which the player has scored only 300s. Getting a Geki will give a sizable boost to the Life Bar. By default, it is blue. |
|
||||
| ![](/wiki/Skinning/Interface/img/hit100.png ""100"") | 100 | A possible score one can get when tapping a Hit Object slightly late or early, completing a Slider and missing a number of ticks, or completing a Spinner with the Spinner Meter almost full. A score of 100 appears in a green score by default. When very skilled players test a beatmap and they get a lot of 100s, this may mean that the beatmap does not have correct timing. |
|
||||
| ![](/wiki/Skinning/Interface/img/hit300k.png ""300 Katu"") ![](/wiki/Skinning/Interface/img/hit100k.png ""100 Katu"") | (喝) Katu or Katsu | A term from Ouendan, called Beat! in EBA. Appears when playing the last element in a combo in which the player has scored at least one 100, but no 50s or misses. Getting a Katu will give a small boost to the Life Bar. By default, it is coloured green or blue depending on whether the Katu itself is a 100 or a 300. |
|
||||
| ![](/wiki/Skinning/Interface/img/hit50.png ""50"") | 50 | A possible score one can get when tapping a hit circle rather early or late but not early or late enough to cause a miss, completing a Slider and missing a lot of ticks, or completing a Spinner with the Spinner Metre close to full. A score of 50 appears in a orange score by default. Scoring a 50 in a combo will prevent the appearance of a Katu or a Geki at the combo's end. |
|
||||
| ![](/wiki/Skinning/Interface/img/hit0.png ""Miss"") | Miss | A possible score one can get when not tapping a hit circle or too early (based on OD and AR, it may *shake* instead), not tapping or holding the Slider at least once, or completing a Spinner with low Spinner Metre fill. Scoring a Miss will reset the current combo to 0 and will prevent the appearance of a Katu or a Geki at the combo's end. |
|
||||
";
|
||||
});
|
||||
}
|
||||
|
||||
private class TestMarkdownContainer : WikiMarkdownContainer
|
||||
{
|
||||
public LinkInline Link;
|
||||
|
File diff suppressed because one or more lines are too long
65
osu.Game.Tests/Visual/Online/TestSceneWikiSidebar.cs
Normal file
65
osu.Game.Tests/Visual/Online/TestSceneWikiSidebar.cs
Normal file
@ -0,0 +1,65 @@
|
||||
// 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 Markdig.Parsers;
|
||||
using Markdig.Syntax;
|
||||
using Markdig.Syntax.Inlines;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Game.Graphics.Containers.Markdown;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Overlays.Wiki;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Online
|
||||
{
|
||||
public class TestSceneWikiSidebar : OsuTestScene
|
||||
{
|
||||
[Cached]
|
||||
private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Orange);
|
||||
|
||||
[Cached]
|
||||
private readonly OverlayScrollContainer scrollContainer = new OverlayScrollContainer();
|
||||
|
||||
private WikiSidebar sidebar;
|
||||
|
||||
[SetUp]
|
||||
public void SetUp() => Schedule(() => Child = sidebar = new WikiSidebar());
|
||||
|
||||
[Test]
|
||||
public void TestNoContent()
|
||||
{
|
||||
AddStep("No Content", () => { });
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestOnlyMainTitle()
|
||||
{
|
||||
AddStep("Add TOC", () =>
|
||||
{
|
||||
for (var i = 0; i < 10; i++)
|
||||
addTitle($"This is a very long title {i + 1}");
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestWithSubtitle()
|
||||
{
|
||||
AddStep("Add TOC", () =>
|
||||
{
|
||||
for (var i = 0; i < 10; i++)
|
||||
addTitle($"This is a very long title {i + 1}", i % 4 != 0);
|
||||
});
|
||||
}
|
||||
|
||||
private void addTitle(string text, bool subtitle = false)
|
||||
{
|
||||
var headingBlock = new HeadingBlock(new HeadingBlockParser())
|
||||
{
|
||||
Inline = new ContainerInline().AppendChild(new LiteralInline(text)),
|
||||
Level = subtitle ? 3 : 2,
|
||||
};
|
||||
var heading = new OsuMarkdownHeading(headingBlock);
|
||||
sidebar.AddEntry(headingBlock, heading);
|
||||
}
|
||||
}
|
||||
}
|
@ -2,11 +2,14 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Graphics.UserInterfaceV2;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Tests.Visual.UserInterface
|
||||
@ -21,6 +24,45 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
[TestCase(true)]
|
||||
public void TestNonPadded(bool hasDescription) => createPaddedComponent(hasDescription, false);
|
||||
|
||||
[Test]
|
||||
public void TestFixedWidth()
|
||||
{
|
||||
const float label_width = 200;
|
||||
|
||||
AddStep("create components", () => Child = new FillFlowContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Vertical,
|
||||
Spacing = new Vector2(0, 10),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new NonPaddedLabelledDrawable
|
||||
{
|
||||
Label = "short",
|
||||
FixedLabelWidth = label_width
|
||||
},
|
||||
new NonPaddedLabelledDrawable
|
||||
{
|
||||
Label = "very very very very very very very very very very very long",
|
||||
FixedLabelWidth = label_width
|
||||
},
|
||||
new PaddedLabelledDrawable
|
||||
{
|
||||
Label = "short",
|
||||
FixedLabelWidth = label_width
|
||||
},
|
||||
new PaddedLabelledDrawable
|
||||
{
|
||||
Label = "very very very very very very very very very very very long",
|
||||
FixedLabelWidth = label_width
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
AddStep("unset label width", () => this.ChildrenOfType<LabelledDrawable<Drawable>>().ForEach(d => d.FixedLabelWidth = null));
|
||||
AddStep("reset label width", () => this.ChildrenOfType<LabelledDrawable<Drawable>>().ForEach(d => d.FixedLabelWidth = label_width));
|
||||
}
|
||||
|
||||
private void createPaddedComponent(bool hasDescription = false, bool padded = true)
|
||||
{
|
||||
AddStep("create component", () =>
|
||||
|
@ -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 osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
@ -14,7 +15,7 @@ namespace osu.Game.Graphics.Backgrounds
|
||||
/// <summary>
|
||||
/// A background which offers blurring via a <see cref="BufferedContainer"/> on demand.
|
||||
/// </summary>
|
||||
public class Background : CompositeDrawable
|
||||
public class Background : CompositeDrawable, IEquatable<Background>
|
||||
{
|
||||
private const float blur_scale = 0.5f;
|
||||
|
||||
@ -71,5 +72,14 @@ namespace osu.Game.Graphics.Backgrounds
|
||||
|
||||
bufferedContainer?.BlurTo(newBlurSigma * blur_scale, duration, easing);
|
||||
}
|
||||
|
||||
public virtual bool Equals(Background other)
|
||||
{
|
||||
if (ReferenceEquals(null, other)) return false;
|
||||
if (ReferenceEquals(this, other)) return true;
|
||||
|
||||
return other.GetType() == GetType()
|
||||
&& other.textureName == textureName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,5 +24,14 @@ namespace osu.Game.Graphics.Backgrounds
|
||||
{
|
||||
Sprite.Texture = Beatmap?.Background ?? textures.Get(fallbackTextureName);
|
||||
}
|
||||
|
||||
public override bool Equals(Background other)
|
||||
{
|
||||
if (ReferenceEquals(null, other)) return false;
|
||||
if (ReferenceEquals(this, other)) return true;
|
||||
|
||||
return other.GetType() == GetType()
|
||||
&& ((BeatmapBackground)other).Beatmap == Beatmap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
34
osu.Game/Graphics/Backgrounds/SkinBackground.cs
Normal file
34
osu.Game/Graphics/Backgrounds/SkinBackground.cs
Normal file
@ -0,0 +1,34 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Game.Skinning;
|
||||
|
||||
namespace osu.Game.Graphics.Backgrounds
|
||||
{
|
||||
internal class SkinBackground : Background
|
||||
{
|
||||
private readonly Skin skin;
|
||||
|
||||
public SkinBackground(Skin skin, string fallbackTextureName)
|
||||
: base(fallbackTextureName)
|
||||
{
|
||||
this.skin = skin;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
Sprite.Texture = skin.GetTexture("menu-background") ?? Sprite.Texture;
|
||||
}
|
||||
|
||||
public override bool Equals(Background other)
|
||||
{
|
||||
if (ReferenceEquals(null, other)) return false;
|
||||
if (ReferenceEquals(this, other)) return true;
|
||||
|
||||
return other.GetType() == GetType()
|
||||
&& ((SkinBackground)other).skin.SkinInfo.Equals(skin.SkinInfo);
|
||||
}
|
||||
}
|
||||
}
|
@ -57,12 +57,6 @@ namespace osu.Game.Graphics.Backgrounds
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether we want to expire triangles as they exit our draw area completely.
|
||||
/// </summary>
|
||||
[Obsolete("Unused.")] // Can be removed 20210518
|
||||
protected virtual bool ExpireOffScreenTriangles => true;
|
||||
|
||||
/// <summary>
|
||||
/// Whether we should create new triangles as others expire.
|
||||
/// </summary>
|
||||
|
20
osu.Game/Graphics/Containers/Markdown/OsuMarkdownImage.cs
Normal file
20
osu.Game/Graphics/Containers/Markdown/OsuMarkdownImage.cs
Normal file
@ -0,0 +1,20 @@
|
||||
// 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 Markdig.Syntax.Inlines;
|
||||
using osu.Framework.Graphics.Containers.Markdown;
|
||||
using osu.Framework.Graphics.Cursor;
|
||||
|
||||
namespace osu.Game.Graphics.Containers.Markdown
|
||||
{
|
||||
public class OsuMarkdownImage : MarkdownImage, IHasTooltip
|
||||
{
|
||||
public string TooltipText { get; }
|
||||
|
||||
public OsuMarkdownImage(LinkInline linkInline)
|
||||
: base(linkInline.Url)
|
||||
{
|
||||
TooltipText = linkInline.Title;
|
||||
}
|
||||
}
|
||||
}
|
@ -17,6 +17,8 @@ namespace osu.Game.Graphics.Containers.Markdown
|
||||
protected override void AddLinkText(string text, LinkInline linkInline)
|
||||
=> AddDrawable(new OsuMarkdownLinkText(text, linkInline));
|
||||
|
||||
protected override void AddImage(LinkInline linkInline) => AddDrawable(new OsuMarkdownImage(linkInline));
|
||||
|
||||
// TODO : Change font to monospace
|
||||
protected override void AddCodeInLine(CodeInline codeInline) => AddDrawable(new OsuMarkdownInlineCode
|
||||
{
|
||||
|
@ -14,6 +14,27 @@ namespace osu.Game.Graphics.UserInterfaceV2
|
||||
public abstract class LabelledDrawable<T> : CompositeDrawable
|
||||
where T : Drawable
|
||||
{
|
||||
private float? fixedLabelWidth;
|
||||
|
||||
/// <summary>
|
||||
/// The fixed width of the label of this <see cref="LabelledDrawable{T}"/>.
|
||||
/// If <c>null</c>, the label portion will auto-size to its content.
|
||||
/// Can be used in layout scenarios where several labels must match in length for the components to be aligned properly.
|
||||
/// </summary>
|
||||
public float? FixedLabelWidth
|
||||
{
|
||||
get => fixedLabelWidth;
|
||||
set
|
||||
{
|
||||
if (fixedLabelWidth == value)
|
||||
return;
|
||||
|
||||
fixedLabelWidth = value;
|
||||
|
||||
updateLabelWidth();
|
||||
}
|
||||
}
|
||||
|
||||
protected const float CONTENT_PADDING_VERTICAL = 10;
|
||||
protected const float CONTENT_PADDING_HORIZONTAL = 15;
|
||||
protected const float CORNER_RADIUS = 15;
|
||||
@ -23,6 +44,7 @@ namespace osu.Game.Graphics.UserInterfaceV2
|
||||
/// </summary>
|
||||
protected readonly T Component;
|
||||
|
||||
private readonly GridContainer grid;
|
||||
private readonly OsuTextFlowContainer labelText;
|
||||
private readonly OsuTextFlowContainer descriptionText;
|
||||
|
||||
@ -56,7 +78,7 @@ namespace osu.Game.Graphics.UserInterfaceV2
|
||||
Spacing = new Vector2(0, 12),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new GridContainer
|
||||
grid = new GridContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
@ -69,7 +91,13 @@ namespace osu.Game.Graphics.UserInterfaceV2
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Padding = new MarginPadding { Right = 20 }
|
||||
Padding = new MarginPadding
|
||||
{
|
||||
Right = 20,
|
||||
// ensure that the label is always vertically padded even if the component itself isn't.
|
||||
// this may become an issue if the label is taller than the component.
|
||||
Vertical = padded ? 0 : CONTENT_PADDING_VERTICAL
|
||||
}
|
||||
},
|
||||
new Container
|
||||
{
|
||||
@ -87,7 +115,6 @@ namespace osu.Game.Graphics.UserInterfaceV2
|
||||
},
|
||||
},
|
||||
RowDimensions = new[] { new Dimension(GridSizeMode.AutoSize) },
|
||||
ColumnDimensions = new[] { new Dimension(GridSizeMode.AutoSize) }
|
||||
},
|
||||
descriptionText = new OsuTextFlowContainer(s => s.Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold, italics: true))
|
||||
{
|
||||
@ -99,6 +126,24 @@ namespace osu.Game.Graphics.UserInterfaceV2
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
updateLabelWidth();
|
||||
}
|
||||
|
||||
private void updateLabelWidth()
|
||||
{
|
||||
if (fixedLabelWidth == null)
|
||||
{
|
||||
grid.ColumnDimensions = new[] { new Dimension(GridSizeMode.AutoSize) };
|
||||
labelText.RelativeSizeAxes = Axes.None;
|
||||
labelText.AutoSizeAxes = Axes.Both;
|
||||
}
|
||||
else
|
||||
{
|
||||
grid.ColumnDimensions = new[] { new Dimension(GridSizeMode.Absolute, fixedLabelWidth.Value) };
|
||||
labelText.AutoSizeAxes = Axes.Y;
|
||||
labelText.RelativeSizeAxes = Axes.X;
|
||||
}
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
|
@ -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.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
@ -13,7 +14,9 @@ namespace osu.Game.Overlays
|
||||
{
|
||||
protected override Container<Drawable> Content => content;
|
||||
|
||||
[Cached]
|
||||
protected readonly OverlayScrollContainer ScrollFlow;
|
||||
|
||||
protected readonly LoadingLayer Loading;
|
||||
private readonly Container content;
|
||||
|
||||
|
@ -2,19 +2,15 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using Markdig.Syntax.Inlines;
|
||||
using osu.Framework.Graphics.Containers.Markdown;
|
||||
using osu.Framework.Graphics.Cursor;
|
||||
using osu.Game.Graphics.Containers.Markdown;
|
||||
|
||||
namespace osu.Game.Overlays.Wiki.Markdown
|
||||
{
|
||||
public class WikiMarkdownImage : MarkdownImage, IHasTooltip
|
||||
public class WikiMarkdownImage : OsuMarkdownImage
|
||||
{
|
||||
public string TooltipText { get; }
|
||||
|
||||
public WikiMarkdownImage(LinkInline linkInline)
|
||||
: base(linkInline.Url)
|
||||
: base(linkInline)
|
||||
{
|
||||
TooltipText = linkInline.Title;
|
||||
}
|
||||
|
||||
protected override ImageContainer CreateImageContainer(string url)
|
||||
|
80
osu.Game/Overlays/Wiki/WikiArticlePage.cs
Normal file
80
osu.Game/Overlays/Wiki/WikiArticlePage.cs
Normal file
@ -0,0 +1,80 @@
|
||||
// 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 Markdig.Syntax;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Containers.Markdown;
|
||||
using osu.Game.Overlays.Wiki.Markdown;
|
||||
|
||||
namespace osu.Game.Overlays.Wiki
|
||||
{
|
||||
public class WikiArticlePage : CompositeDrawable
|
||||
{
|
||||
public Container SidebarContainer { get; }
|
||||
|
||||
public WikiArticlePage(string currentPath, string markdown)
|
||||
{
|
||||
RelativeSizeAxes = Axes.X;
|
||||
AutoSizeAxes = Axes.Y;
|
||||
|
||||
WikiSidebar sidebar;
|
||||
|
||||
InternalChild = new GridContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
RowDimensions = new[]
|
||||
{
|
||||
new Dimension(GridSizeMode.AutoSize),
|
||||
},
|
||||
ColumnDimensions = new[]
|
||||
{
|
||||
new Dimension(GridSizeMode.AutoSize),
|
||||
new Dimension(),
|
||||
},
|
||||
Content = new[]
|
||||
{
|
||||
new Drawable[]
|
||||
{
|
||||
SidebarContainer = new Container
|
||||
{
|
||||
AutoSizeAxes = Axes.X,
|
||||
Child = sidebar = new WikiSidebar(),
|
||||
},
|
||||
new ArticleMarkdownContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
CurrentPath = currentPath,
|
||||
Text = markdown,
|
||||
DocumentMargin = new MarginPadding(0),
|
||||
DocumentPadding = new MarginPadding
|
||||
{
|
||||
Vertical = 20,
|
||||
Left = 30,
|
||||
Right = 50,
|
||||
},
|
||||
OnAddHeading = sidebar.AddEntry,
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
private class ArticleMarkdownContainer : WikiMarkdownContainer
|
||||
{
|
||||
public Action<HeadingBlock, MarkdownHeading> OnAddHeading;
|
||||
|
||||
protected override MarkdownHeading CreateHeading(HeadingBlock headingBlock)
|
||||
{
|
||||
var heading = base.CreateHeading(headingBlock);
|
||||
|
||||
OnAddHeading(headingBlock, heading);
|
||||
|
||||
return heading;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
66
osu.Game/Overlays/Wiki/WikiSidebar.cs
Normal file
66
osu.Game/Overlays/Wiki/WikiSidebar.cs
Normal file
@ -0,0 +1,66 @@
|
||||
// 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 Markdig.Syntax;
|
||||
using Markdig.Syntax.Inlines;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Containers.Markdown;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
|
||||
namespace osu.Game.Overlays.Wiki
|
||||
{
|
||||
public class WikiSidebar : OverlaySidebar
|
||||
{
|
||||
private WikiTableOfContents tableOfContents;
|
||||
|
||||
protected override Drawable CreateContent() => new FillFlowContainer
|
||||
{
|
||||
Direction = FillDirection.Vertical,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = "CONTENTS",
|
||||
Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold),
|
||||
Margin = new MarginPadding { Bottom = 5 },
|
||||
},
|
||||
tableOfContents = new WikiTableOfContents(),
|
||||
},
|
||||
};
|
||||
|
||||
public void AddEntry(HeadingBlock headingBlock, MarkdownHeading heading)
|
||||
{
|
||||
switch (headingBlock.Level)
|
||||
{
|
||||
case 2:
|
||||
case 3:
|
||||
tableOfContents.AddEntry(getTitle(headingBlock.Inline), heading, headingBlock.Level == 3);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private string getTitle(ContainerInline containerInline)
|
||||
{
|
||||
foreach (var inline in containerInline)
|
||||
{
|
||||
switch (inline)
|
||||
{
|
||||
case LiteralInline literalInline:
|
||||
return literalInline.Content.ToString();
|
||||
|
||||
case LinkInline linkInline:
|
||||
if (!linkInline.IsImage)
|
||||
return getTitle(linkInline);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
91
osu.Game/Overlays/Wiki/WikiTableOfContents.cs
Normal file
91
osu.Game/Overlays/Wiki/WikiTableOfContents.cs
Normal file
@ -0,0 +1,91 @@
|
||||
// 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 osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Containers.Markdown;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
|
||||
namespace osu.Game.Overlays.Wiki
|
||||
{
|
||||
public class WikiTableOfContents : CompositeDrawable
|
||||
{
|
||||
private readonly FillFlowContainer content;
|
||||
|
||||
private TableOfContentsEntry lastMainTitle;
|
||||
|
||||
private TableOfContentsEntry lastSubTitle;
|
||||
|
||||
public WikiTableOfContents()
|
||||
{
|
||||
RelativeSizeAxes = Axes.X;
|
||||
AutoSizeAxes = Axes.Y;
|
||||
InternalChild = content = new FillFlowContainer
|
||||
{
|
||||
Direction = FillDirection.Vertical,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
};
|
||||
}
|
||||
|
||||
public void AddEntry(string title, MarkdownHeading target, bool subtitle = false)
|
||||
{
|
||||
var entry = new TableOfContentsEntry(title, target, subtitle);
|
||||
|
||||
if (subtitle)
|
||||
{
|
||||
lastMainTitle.Margin = new MarginPadding(0);
|
||||
|
||||
if (lastSubTitle != null)
|
||||
lastSubTitle.Margin = new MarginPadding(0);
|
||||
|
||||
content.Add(lastSubTitle = entry.With(d => d.Margin = new MarginPadding { Bottom = 10 }));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
lastSubTitle = null;
|
||||
|
||||
content.Add(lastMainTitle = entry.With(d => d.Margin = new MarginPadding { Bottom = 5 }));
|
||||
}
|
||||
|
||||
private class TableOfContentsEntry : OsuHoverContainer
|
||||
{
|
||||
private readonly MarkdownHeading target;
|
||||
|
||||
private readonly OsuTextFlowContainer textFlow;
|
||||
|
||||
public TableOfContentsEntry(string text, MarkdownHeading target, bool subtitle = false)
|
||||
{
|
||||
this.target = target;
|
||||
|
||||
RelativeSizeAxes = Axes.X;
|
||||
AutoSizeAxes = Axes.Y;
|
||||
Child = textFlow = new OsuTextFlowContainer(t =>
|
||||
{
|
||||
t.Font = OsuFont.GetFont(size: subtitle ? 12 : 15);
|
||||
}).With(f =>
|
||||
{
|
||||
f.AddText(text);
|
||||
f.RelativeSizeAxes = Axes.X;
|
||||
f.AutoSizeAxes = Axes.Y;
|
||||
f.Margin = new MarginPadding { Bottom = 2 };
|
||||
});
|
||||
Padding = new MarginPadding { Left = subtitle ? 10 : 0 };
|
||||
}
|
||||
|
||||
protected override IEnumerable<Drawable> EffectTargets => new Drawable[] { textFlow };
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OverlayColourProvider colourProvider, OverlayScrollContainer scrollContainer)
|
||||
{
|
||||
IdleColour = colourProvider.Light2;
|
||||
HoverColour = colourProvider.Light1;
|
||||
Action = () => scrollContainer.ScrollTo(target);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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.Linq;
|
||||
using System.Threading;
|
||||
using osu.Framework.Allocation;
|
||||
@ -10,7 +11,6 @@ using osu.Game.Online.API;
|
||||
using osu.Game.Online.API.Requests;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Overlays.Wiki;
|
||||
using osu.Game.Overlays.Wiki.Markdown;
|
||||
|
||||
namespace osu.Game.Overlays
|
||||
{
|
||||
@ -31,6 +31,8 @@ namespace osu.Game.Overlays
|
||||
|
||||
private bool displayUpdateRequired = true;
|
||||
|
||||
private WikiArticlePage articlePage;
|
||||
|
||||
public WikiOverlay()
|
||||
: base(OverlayColourScheme.Orange, false)
|
||||
{
|
||||
@ -82,6 +84,17 @@ namespace osu.Game.Overlays
|
||||
}, (cancellationToken = new CancellationTokenSource()).Token);
|
||||
}
|
||||
|
||||
protected override void UpdateAfterChildren()
|
||||
{
|
||||
base.UpdateAfterChildren();
|
||||
|
||||
if (articlePage != null)
|
||||
{
|
||||
articlePage.SidebarContainer.Height = DrawHeight;
|
||||
articlePage.SidebarContainer.Y = Math.Clamp(ScrollFlow.Current - Header.DrawHeight, 0, Math.Max(ScrollFlow.ScrollContent.DrawHeight - DrawHeight - Header.DrawHeight, 0));
|
||||
}
|
||||
}
|
||||
|
||||
private void onPathChanged(ValueChangedEvent<string> e)
|
||||
{
|
||||
cancellationToken?.Cancel();
|
||||
@ -115,39 +128,14 @@ namespace osu.Game.Overlays
|
||||
}
|
||||
else
|
||||
{
|
||||
LoadDisplay(new WikiMarkdownContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
CurrentPath = $@"{api.WebsiteRootUrl}/wiki/{path.Value}/",
|
||||
Text = response.Markdown,
|
||||
DocumentMargin = new MarginPadding(0),
|
||||
DocumentPadding = new MarginPadding
|
||||
{
|
||||
Vertical = 20,
|
||||
Left = 30,
|
||||
Right = 50,
|
||||
},
|
||||
});
|
||||
LoadDisplay(articlePage = new WikiArticlePage($@"{api.WebsiteRootUrl}/wiki/{path.Value}/", response.Markdown));
|
||||
}
|
||||
}
|
||||
|
||||
private void onFail()
|
||||
{
|
||||
LoadDisplay(new WikiMarkdownContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
CurrentPath = $@"{api.WebsiteRootUrl}/wiki/",
|
||||
Text = $"Something went wrong when trying to fetch page \"{path.Value}\".\n\n[Return to the main page](Main_Page).",
|
||||
DocumentMargin = new MarginPadding(0),
|
||||
DocumentPadding = new MarginPadding
|
||||
{
|
||||
Vertical = 20,
|
||||
Left = 30,
|
||||
Right = 50,
|
||||
},
|
||||
});
|
||||
LoadDisplay(articlePage = new WikiArticlePage($@"{api.WebsiteRootUrl}/wiki/",
|
||||
$"Something went wrong when trying to fetch page \"{path.Value}\".\n\n[Return to the main page](Main_Page)."));
|
||||
}
|
||||
|
||||
private void showParentPage()
|
||||
|
@ -1,7 +1,6 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using JetBrains.Annotations;
|
||||
using osu.Framework.Allocation;
|
||||
@ -32,18 +31,6 @@ namespace osu.Game.Rulesets.Judgements
|
||||
|
||||
private readonly Container aboveHitObjectsContent;
|
||||
|
||||
/// <summary>
|
||||
/// Duration of initial fade in.
|
||||
/// </summary>
|
||||
[Obsolete("Apply any animations manually via ApplyHitAnimations / ApplyMissAnimations. Defaults were moved inside skinned components.")]
|
||||
protected virtual double FadeInDuration => 100;
|
||||
|
||||
/// <summary>
|
||||
/// Duration to wait until fade out begins. Defaults to <see cref="FadeInDuration"/>.
|
||||
/// </summary>
|
||||
[Obsolete("Apply any animations manually via ApplyHitAnimations / ApplyMissAnimations. Defaults were moved inside skinned components.")]
|
||||
protected virtual double FadeOutDelay => FadeInDuration;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a drawable which visualises a <see cref="Judgements.Judgement"/>.
|
||||
/// </summary>
|
||||
|
@ -1,7 +1,6 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
|
||||
@ -69,14 +68,6 @@ namespace osu.Game.Rulesets.Judgements
|
||||
/// </summary>
|
||||
public double MaxHealthIncrease => HealthIncreaseFor(MaxResult);
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the numeric score representation of a <see cref="HitResult"/>.
|
||||
/// </summary>
|
||||
/// <param name="result">The <see cref="HitResult"/> to find the numeric score representation for.</param>
|
||||
/// <returns>The numeric score representation of <paramref name="result"/>.</returns>
|
||||
[Obsolete("Has no effect. Use ToNumericResult(HitResult) (standardised across all rulesets).")] // Can be made non-virtual 20210328
|
||||
protected virtual int NumericResultFor(HitResult result) => ToNumericResult(result);
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the numeric score representation of a <see cref="JudgementResult"/>.
|
||||
/// </summary>
|
||||
|
@ -192,7 +192,7 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
||||
/// <summary>
|
||||
/// Applies a hit object to be represented by this <see cref="DrawableHitObject"/>.
|
||||
/// </summary>
|
||||
[Obsolete("Use either overload of Apply that takes a single argument of type HitObject or HitObjectLifetimeEntry")]
|
||||
[Obsolete("Use either overload of Apply that takes a single argument of type HitObject or HitObjectLifetimeEntry")] // Can be removed 20211021.
|
||||
public void Apply([NotNull] HitObject hitObject, [CanBeNull] HitObjectLifetimeEntry lifetimeEntry)
|
||||
{
|
||||
if (lifetimeEntry != null)
|
||||
@ -409,11 +409,6 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
||||
using (BeginAbsoluteSequence(StateUpdateTime, true))
|
||||
UpdateStartTimeStateTransforms();
|
||||
|
||||
#pragma warning disable 618
|
||||
using (BeginAbsoluteSequence(StateUpdateTime + (Result?.TimeOffset ?? 0), true))
|
||||
UpdateStateTransforms(newState);
|
||||
#pragma warning restore 618
|
||||
|
||||
using (BeginAbsoluteSequence(HitStateUpdateTime, true))
|
||||
UpdateHitStateTransforms(newState);
|
||||
|
||||
@ -447,7 +442,7 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
||||
/// By default, this will fade in the object from zero with no duration.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is called once before every <see cref="UpdateStateTransforms"/>. This is to ensure a good state in the case
|
||||
/// This is called once before every <see cref="UpdateHitStateTransforms"/>. This is to ensure a good state in the case
|
||||
/// the <see cref="JudgementResult.TimeOffset"/> was negative and potentially altered the pre-hit transforms.
|
||||
/// </remarks>
|
||||
protected virtual void UpdateInitialTransforms()
|
||||
@ -455,16 +450,6 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
||||
this.FadeInFromZero();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Apply transforms based on the current <see cref="ArmedState"/>. Previous states are automatically cleared.
|
||||
/// In the case of a non-idle <see cref="ArmedState"/>, and if <see cref="Drawable.LifetimeEnd"/> was not set during this call, <see cref="Drawable.Expire"/> will be invoked.
|
||||
/// </summary>
|
||||
/// <param name="state">The new armed state.</param>
|
||||
[Obsolete("Use UpdateStartTimeStateTransforms and UpdateHitStateTransforms instead")] // Can be removed 20210504
|
||||
protected virtual void UpdateStateTransforms(ArmedState state)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Apply passive transforms at the <see cref="HitObject"/>'s StartTime.
|
||||
/// This is called each time <see cref="State"/> changes.
|
||||
@ -520,23 +505,6 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
||||
AccentColour.Value = combo.GetComboColour(comboColours);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called to retrieve the combo colour. Automatically assigned to <see cref="AccentColour"/>.
|
||||
/// Defaults to using <see cref="IHasComboInformation.ComboIndex"/> to decide on a colour.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This will only be called if the <see cref="HitObject"/> implements <see cref="IHasComboInformation"/>.
|
||||
/// </remarks>
|
||||
/// <param name="comboColours">A list of combo colours provided by the beatmap or skin. Can be null if not available.</param>
|
||||
[Obsolete("Unused. Implement IHasComboInformation and IHasComboInformation.GetComboColour() on the HitObject model instead.")] // Can be removed 20210527
|
||||
protected virtual Color4 GetComboColour(IReadOnlyList<Color4> comboColours)
|
||||
{
|
||||
if (!(HitObject is IHasComboInformation combo))
|
||||
throw new InvalidOperationException($"{nameof(HitObject)} must implement {nameof(IHasComboInformation)}");
|
||||
|
||||
return comboColours?.Count > 0 ? comboColours[combo.ComboIndex % comboColours.Count] : Color4.White;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when a change is made to the skin.
|
||||
/// </summary>
|
||||
@ -630,7 +598,7 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
||||
|
||||
/// <summary>
|
||||
/// The time at which state transforms should be applied that line up to <see cref="HitObject"/>'s StartTime.
|
||||
/// This is used to offset calls to <see cref="UpdateStateTransforms"/>.
|
||||
/// This is used to offset calls to <see cref="UpdateStartTimeStateTransforms"/>.
|
||||
/// </summary>
|
||||
public double StateUpdateTime => HitObject.StartTime;
|
||||
|
||||
|
@ -112,17 +112,24 @@ namespace osu.Game.Screens.Backgrounds
|
||||
newBackground = new BeatmapBackgroundWithStoryboard(beatmap.Value, getBackgroundTextureName());
|
||||
newBackground ??= new BeatmapBackground(beatmap.Value, getBackgroundTextureName());
|
||||
|
||||
// this method is called in many cases where the beatmap hasn't changed (ie. on screen transitions).
|
||||
// if a background is already displayed for the requested beatmap, we don't want to load it again.
|
||||
if (background?.GetType() == newBackground.GetType() &&
|
||||
(background as BeatmapBackground)?.Beatmap == beatmap.Value)
|
||||
return background;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case BackgroundSource.Skin:
|
||||
// default skins should use the default background rotation, which won't be the case if a SkinBackground is created for them.
|
||||
if (skin.Value is DefaultSkin || skin.Value is DefaultLegacySkin)
|
||||
break;
|
||||
|
||||
newBackground = new SkinBackground(skin.Value, getBackgroundTextureName());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// this method is called in many cases where the background might not necessarily need to change.
|
||||
// if an equivalent background is currently being shown, we don't want to load it again.
|
||||
if (newBackground?.Equals(background) == true)
|
||||
return background;
|
||||
|
||||
newBackground ??= new Background(getBackgroundTextureName());
|
||||
newBackground.Depth = currentDisplay;
|
||||
|
||||
@ -140,22 +147,5 @@ namespace osu.Game.Screens.Backgrounds
|
||||
return $@"Menu/menu-background-{currentDisplay % background_count + 1}";
|
||||
}
|
||||
}
|
||||
|
||||
private class SkinnedBackground : Background
|
||||
{
|
||||
private readonly Skin skin;
|
||||
|
||||
public SkinnedBackground(Skin skin, string fallbackTextureName)
|
||||
: base(fallbackTextureName)
|
||||
{
|
||||
this.skin = skin;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
Sprite.Texture = skin.GetTexture("menu-background") ?? Sprite.Texture;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ namespace osu.Game.Screens.Edit.Setup
|
||||
comboColours = new LabelledColourPalette
|
||||
{
|
||||
Label = "Hitcircle / Slider Combos",
|
||||
FixedLabelWidth = LABEL_WIDTH,
|
||||
ColourNamePrefix = "Combo"
|
||||
}
|
||||
};
|
||||
|
@ -28,6 +28,7 @@ namespace osu.Game.Screens.Edit.Setup
|
||||
circleSizeSlider = new LabelledSliderBar<float>
|
||||
{
|
||||
Label = "Object Size",
|
||||
FixedLabelWidth = LABEL_WIDTH,
|
||||
Description = "The size of all hit objects",
|
||||
Current = new BindableFloat(Beatmap.BeatmapInfo.BaseDifficulty.CircleSize)
|
||||
{
|
||||
@ -40,6 +41,7 @@ namespace osu.Game.Screens.Edit.Setup
|
||||
healthDrainSlider = new LabelledSliderBar<float>
|
||||
{
|
||||
Label = "Health Drain",
|
||||
FixedLabelWidth = LABEL_WIDTH,
|
||||
Description = "The rate of passive health drain throughout playable time",
|
||||
Current = new BindableFloat(Beatmap.BeatmapInfo.BaseDifficulty.DrainRate)
|
||||
{
|
||||
@ -52,6 +54,7 @@ namespace osu.Game.Screens.Edit.Setup
|
||||
approachRateSlider = new LabelledSliderBar<float>
|
||||
{
|
||||
Label = "Approach Rate",
|
||||
FixedLabelWidth = LABEL_WIDTH,
|
||||
Description = "The speed at which objects are presented to the player",
|
||||
Current = new BindableFloat(Beatmap.BeatmapInfo.BaseDifficulty.ApproachRate)
|
||||
{
|
||||
@ -64,6 +67,7 @@ namespace osu.Game.Screens.Edit.Setup
|
||||
overallDifficultySlider = new LabelledSliderBar<float>
|
||||
{
|
||||
Label = "Overall Difficulty",
|
||||
FixedLabelWidth = LABEL_WIDTH,
|
||||
Description = "The harshness of hit windows and difficulty of special objects (ie. spinners)",
|
||||
Current = new BindableFloat(Beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty)
|
||||
{
|
||||
|
@ -27,24 +27,28 @@ namespace osu.Game.Screens.Edit.Setup
|
||||
artistTextBox = new LabelledTextBox
|
||||
{
|
||||
Label = "Artist",
|
||||
FixedLabelWidth = LABEL_WIDTH,
|
||||
Current = { Value = Beatmap.Metadata.Artist },
|
||||
TabbableContentContainer = this
|
||||
},
|
||||
titleTextBox = new LabelledTextBox
|
||||
{
|
||||
Label = "Title",
|
||||
FixedLabelWidth = LABEL_WIDTH,
|
||||
Current = { Value = Beatmap.Metadata.Title },
|
||||
TabbableContentContainer = this
|
||||
},
|
||||
creatorTextBox = new LabelledTextBox
|
||||
{
|
||||
Label = "Creator",
|
||||
FixedLabelWidth = LABEL_WIDTH,
|
||||
Current = { Value = Beatmap.Metadata.AuthorString },
|
||||
TabbableContentContainer = this
|
||||
},
|
||||
difficultyTextBox = new LabelledTextBox
|
||||
{
|
||||
Label = "Difficulty Name",
|
||||
FixedLabelWidth = LABEL_WIDTH,
|
||||
Current = { Value = Beatmap.BeatmapInfo.Version },
|
||||
TabbableContentContainer = this
|
||||
},
|
||||
|
@ -54,6 +54,7 @@ namespace osu.Game.Screens.Edit.Setup
|
||||
backgroundTextBox = new FileChooserLabelledTextBox(".jpg", ".jpeg", ".png")
|
||||
{
|
||||
Label = "Background",
|
||||
FixedLabelWidth = LABEL_WIDTH,
|
||||
PlaceholderText = "Click to select a background image",
|
||||
Current = { Value = working.Value.Metadata.BackgroundFile },
|
||||
Target = backgroundFileChooserContainer,
|
||||
@ -72,6 +73,7 @@ namespace osu.Game.Screens.Edit.Setup
|
||||
audioTrackTextBox = new FileChooserLabelledTextBox(".mp3", ".ogg")
|
||||
{
|
||||
Label = "Audio Track",
|
||||
FixedLabelWidth = LABEL_WIDTH,
|
||||
PlaceholderText = "Click to select a track",
|
||||
Current = { Value = working.Value.Metadata.AudioFile },
|
||||
Target = audioTrackFileChooserContainer,
|
||||
|
@ -7,6 +7,7 @@ using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Graphics.UserInterfaceV2;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Screens.Edit.Setup
|
||||
@ -15,6 +16,11 @@ namespace osu.Game.Screens.Edit.Setup
|
||||
{
|
||||
private readonly FillFlowContainer flow;
|
||||
|
||||
/// <summary>
|
||||
/// Used to align some of the child <see cref="LabelledDrawable{T}"/>s together to achieve a grid-like look.
|
||||
/// </summary>
|
||||
protected const float LABEL_WIDTH = 160;
|
||||
|
||||
[Resolved]
|
||||
protected OsuColour Colours { get; private set; }
|
||||
|
||||
|
@ -217,6 +217,9 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters
|
||||
if (!judgement.IsHit || judgement.HitObject.HitWindows?.WindowFor(HitResult.Miss) == 0)
|
||||
return;
|
||||
|
||||
if (!judgement.Type.IsScorable() || judgement.Type.IsBonus())
|
||||
return;
|
||||
|
||||
if (judgementsContainer.Count > max_concurrent_judgements)
|
||||
{
|
||||
const double quick_fade_time = 100;
|
||||
|
@ -7,6 +7,7 @@ using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
@ -24,7 +25,13 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters
|
||||
InternalChild = judgementsFlow = new JudgementFlow();
|
||||
}
|
||||
|
||||
protected override void OnNewJudgement(JudgementResult judgement) => judgementsFlow.Push(GetColourForHitResult(judgement.Type));
|
||||
protected override void OnNewJudgement(JudgementResult judgement)
|
||||
{
|
||||
if (!judgement.Type.IsScorable() || judgement.Type.IsBonus())
|
||||
return;
|
||||
|
||||
judgementsFlow.Push(GetColourForHitResult(judgement.Type));
|
||||
}
|
||||
|
||||
private class JudgementFlow : FillFlowContainer<HitErrorCircle>
|
||||
{
|
||||
|
@ -41,6 +41,8 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters
|
||||
{
|
||||
switch (result)
|
||||
{
|
||||
case HitResult.SmallTickMiss:
|
||||
case HitResult.LargeTickMiss:
|
||||
case HitResult.Miss:
|
||||
return colours.Red;
|
||||
|
||||
@ -53,6 +55,8 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters
|
||||
case HitResult.Good:
|
||||
return colours.GreenLight;
|
||||
|
||||
case HitResult.SmallTickHit:
|
||||
case HitResult.LargeTickHit:
|
||||
case HitResult.Great:
|
||||
return colours.Blue;
|
||||
|
||||
|
@ -32,6 +32,7 @@ using osu.Game.Scoring.Legacy;
|
||||
using osu.Game.Screens.Ranking;
|
||||
using osu.Game.Skinning;
|
||||
using osu.Game.Users;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Screens.Play
|
||||
{
|
||||
@ -856,6 +857,7 @@ namespace osu.Game.Screens.Play
|
||||
{
|
||||
b.IgnoreUserSettings.Value = false;
|
||||
b.BlurAmount.Value = 0;
|
||||
b.FadeColour(Color4.White, 250);
|
||||
|
||||
// bind component bindables.
|
||||
b.IsBreakTime.BindTo(breakTracker.IsBreakTime);
|
||||
|
@ -184,8 +184,6 @@ namespace osu.Game.Screens.Play
|
||||
{
|
||||
if (epilepsyWarning != null)
|
||||
epilepsyWarning.DimmableBackground = b;
|
||||
|
||||
b?.FadeColour(Color4.White, 800, Easing.OutQuint);
|
||||
});
|
||||
|
||||
Beatmap.Value.Track.AddAdjustment(AdjustableProperty.Volume, volumeAdjustment);
|
||||
@ -334,6 +332,8 @@ namespace osu.Game.Screens.Play
|
||||
|
||||
content.FadeInFromZero(400);
|
||||
content.ScaleTo(1, 650, Easing.OutQuint).Then().Schedule(prepareNewPlayer);
|
||||
|
||||
ApplyToBackground(b => b?.FadeColour(Color4.White, 800, Easing.OutQuint));
|
||||
}
|
||||
|
||||
private void contentOut()
|
||||
|
@ -13,6 +13,7 @@ using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Input.Bindings;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Game.Audio;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Input.Bindings;
|
||||
@ -256,7 +257,7 @@ namespace osu.Game.Screens.Ranking
|
||||
ApplyToBackground(b =>
|
||||
{
|
||||
b.BlurAmount.Value = BACKGROUND_BLUR;
|
||||
b.FadeTo(0.5f, 250);
|
||||
b.FadeColour(OsuColour.Gray(0.5f), 250);
|
||||
});
|
||||
|
||||
bottomPanel.FadeTo(1, 250);
|
||||
@ -264,9 +265,11 @@ namespace osu.Game.Screens.Ranking
|
||||
|
||||
public override bool OnExiting(IScreen next)
|
||||
{
|
||||
ApplyToBackground(b => b.FadeTo(1, 250));
|
||||
if (base.OnExiting(next))
|
||||
return true;
|
||||
|
||||
return base.OnExiting(next);
|
||||
this.FadeOut(100);
|
||||
return false;
|
||||
}
|
||||
|
||||
public override bool OnBackButton()
|
||||
@ -314,7 +317,7 @@ namespace osu.Game.Screens.Ranking
|
||||
ScorePanelList.HandleInput = false;
|
||||
|
||||
// Dim background.
|
||||
ApplyToBackground(b => b.FadeTo(0.1f, 150));
|
||||
ApplyToBackground(b => b.FadeColour(OsuColour.Gray(0.1f), 150));
|
||||
|
||||
detachedPanel = expandedPanel;
|
||||
}
|
||||
@ -338,7 +341,7 @@ namespace osu.Game.Screens.Ranking
|
||||
ScorePanelList.HandleInput = true;
|
||||
|
||||
// Un-dim background.
|
||||
ApplyToBackground(b => b.FadeTo(0.5f, 150));
|
||||
ApplyToBackground(b => b.FadeColour(OsuColour.Gray(0.5f), 150));
|
||||
|
||||
detachedPanel = null;
|
||||
}
|
||||
|
@ -8,9 +8,11 @@ using System.Linq;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Scoring;
|
||||
using osuTK;
|
||||
using osuTK.Input;
|
||||
|
||||
namespace osu.Game.Screens.Ranking
|
||||
{
|
||||
@ -263,6 +265,26 @@ namespace osu.Game.Screens.Ranking
|
||||
container.Attach();
|
||||
}
|
||||
|
||||
protected override bool OnKeyDown(KeyDownEvent e)
|
||||
{
|
||||
var expandedPanelIndex = flow.GetPanelIndex(expandedPanel.Score);
|
||||
|
||||
switch (e.Key)
|
||||
{
|
||||
case Key.Left:
|
||||
if (expandedPanelIndex > 0)
|
||||
SelectedScore.Value = flow.Children[expandedPanelIndex - 1].Panel.Score;
|
||||
return true;
|
||||
|
||||
case Key.Right:
|
||||
if (expandedPanelIndex < flow.Count - 1)
|
||||
SelectedScore.Value = flow.Children[expandedPanelIndex + 1].Panel.Score;
|
||||
return true;
|
||||
}
|
||||
|
||||
return base.OnKeyDown(e);
|
||||
}
|
||||
|
||||
private class Flow : FillFlowContainer<ScorePanelTrackingContainer>
|
||||
{
|
||||
public override IEnumerable<Drawable> FlowingChildren => applySorting(AliveInternalChildren);
|
||||
|
@ -50,6 +50,8 @@ namespace osu.Game.Skinning
|
||||
|
||||
private readonly Skin defaultLegacySkin;
|
||||
|
||||
private readonly Skin defaultSkin;
|
||||
|
||||
public SkinManager(Storage storage, DatabaseContextFactory contextFactory, GameHost host, IResourceStore<byte[]> resources, AudioManager audio)
|
||||
: base(storage, contextFactory, new SkinStore(contextFactory, storage), host)
|
||||
{
|
||||
@ -58,10 +60,11 @@ namespace osu.Game.Skinning
|
||||
this.resources = resources;
|
||||
|
||||
defaultLegacySkin = new DefaultLegacySkin(this);
|
||||
defaultSkin = new DefaultSkin(this);
|
||||
|
||||
CurrentSkinInfo.ValueChanged += skin => CurrentSkin.Value = GetSkin(skin.NewValue);
|
||||
|
||||
CurrentSkin.Value = new DefaultSkin(this);
|
||||
CurrentSkin.Value = defaultSkin;
|
||||
CurrentSkin.ValueChanged += skin =>
|
||||
{
|
||||
if (skin.NewValue.SkinInfo != CurrentSkinInfo.Value)
|
||||
@ -226,24 +229,26 @@ namespace osu.Game.Skinning
|
||||
if (CurrentSkin.Value is LegacySkin && lookupFunction(defaultLegacySkin))
|
||||
return defaultLegacySkin;
|
||||
|
||||
if (lookupFunction(defaultSkin))
|
||||
return defaultSkin;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private T lookupWithFallback<T>(Func<ISkin, T> func)
|
||||
private T lookupWithFallback<T>(Func<ISkin, T> lookupFunction)
|
||||
where T : class
|
||||
{
|
||||
var selectedSkin = func(CurrentSkin.Value);
|
||||
|
||||
if (selectedSkin != null)
|
||||
return selectedSkin;
|
||||
if (lookupFunction(CurrentSkin.Value) is T skinSourced)
|
||||
return skinSourced;
|
||||
|
||||
// TODO: we also want to return a DefaultLegacySkin here if the current *beatmap* is providing any skinned elements.
|
||||
// When attempting to address this, we may want to move the full DefaultLegacySkin fallback logic to within Player itself (to better allow
|
||||
// for beatmap skin visibility).
|
||||
if (CurrentSkin.Value is LegacySkin)
|
||||
return func(defaultLegacySkin);
|
||||
if (CurrentSkin.Value is LegacySkin && lookupFunction(defaultLegacySkin) is T legacySourced)
|
||||
return legacySourced;
|
||||
|
||||
return null;
|
||||
// Finally fall back to the (non-legacy) default.
|
||||
return lookupFunction(defaultSkin);
|
||||
}
|
||||
|
||||
#region IResourceStorageProvider
|
||||
|
@ -34,7 +34,7 @@
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2021.608.0" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2021.609.0" />
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.525.0" />
|
||||
<PackageReference Include="Sentry" Version="3.4.0" />
|
||||
<PackageReference Include="SharpCompress" Version="0.28.2" />
|
||||
|
@ -70,7 +70,7 @@
|
||||
<Reference Include="System.Net.Http" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="ppy.osu.Framework.iOS" Version="2021.608.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.iOS" Version="2021.609.0" />
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.525.0" />
|
||||
</ItemGroup>
|
||||
<!-- See https://github.com/dotnet/runtime/issues/35988 (can be removed after Xamarin uses net5.0 / net6.0) -->
|
||||
@ -93,7 +93,7 @@
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2021.608.0" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2021.609.0" />
|
||||
<PackageReference Include="SharpCompress" Version="0.28.2" />
|
||||
<PackageReference Include="NUnit" Version="3.13.2" />
|
||||
<PackageReference Include="SharpRaven" Version="2.4.0" />
|
||||
|
Loading…
Reference in New Issue
Block a user