2019-08-30 11:59:58 +08:00
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Allocation ;
using osu.Framework.Bindables ;
using osu.Framework.Graphics ;
using osu.Framework.Graphics.Containers ;
using osu.Framework.Graphics.Sprites ;
2020-03-28 12:39:08 +08:00
using osu.Framework.Graphics.Textures ;
2019-08-30 11:59:58 +08:00
using osu.Game.Graphics ;
using osu.Game.Graphics.Sprites ;
using osu.Game.Rulesets.Objects.Drawables ;
using osu.Game.Rulesets.Osu.Objects ;
2020-11-05 13:40:48 +08:00
using osu.Game.Rulesets.Osu.Objects.Drawables ;
2019-08-30 11:59:58 +08:00
using osu.Game.Skinning ;
using osuTK ;
using osuTK.Graphics ;
2020-08-06 01:07:05 +08:00
using static osu . Game . Skinning . LegacySkinConfiguration ;
2019-08-30 11:59:58 +08:00
namespace osu.Game.Rulesets.Osu.Skinning
{
public class LegacyMainCirclePiece : CompositeDrawable
{
2020-03-28 12:39:08 +08:00
private readonly string priorityLookup ;
2020-10-02 12:40:24 +08:00
private readonly bool hasNumber ;
2020-03-28 12:39:08 +08:00
2020-10-02 12:40:24 +08:00
public LegacyMainCirclePiece ( string priorityLookup = null , bool hasNumber = true )
2019-08-30 11:59:58 +08:00
{
2020-03-28 12:39:08 +08:00
this . priorityLookup = priorityLookup ;
2020-10-02 12:40:24 +08:00
this . hasNumber = hasNumber ;
2020-03-28 12:39:08 +08:00
2019-08-30 11:59:58 +08:00
Size = new Vector2 ( OsuHitObject . OBJECT_RADIUS * 2 ) ;
}
2020-08-06 04:45:00 +08:00
private Container < Sprite > circleSprites ;
2020-08-07 15:36:40 +08:00
private Sprite hitCircleSprite ;
private Sprite hitCircleOverlay ;
2020-08-06 01:07:05 +08:00
2019-10-01 13:23:41 +08:00
private SkinnableSpriteText hitCircleText ;
2019-08-30 11:59:58 +08:00
private readonly Bindable < Color4 > accentColour = new Bindable < Color4 > ( ) ;
2019-09-26 15:57:58 +08:00
private readonly IBindable < int > indexInCurrentCombo = new Bindable < int > ( ) ;
2019-10-01 13:23:41 +08:00
2020-11-04 16:30:23 +08:00
[Resolved]
private DrawableHitObject drawableObject { get ; set ; }
2019-10-03 10:58:20 +08:00
[Resolved]
private ISkinSource skin { get ; set ; }
2019-08-30 11:59:58 +08:00
[BackgroundDependencyLoader]
2020-11-04 16:30:23 +08:00
private void load ( )
2019-08-30 11:59:58 +08:00
{
2020-11-05 13:40:48 +08:00
var drawableOsuObject = ( DrawableOsuHitObject ) drawableObject ;
2019-08-30 11:59:58 +08:00
2020-10-06 12:56:38 +08:00
bool allowFallback = false ;
// attempt lookup using priority specification
2020-10-06 13:12:46 +08:00
Texture baseTexture = getTextureWithFallback ( string . Empty ) ;
2020-10-06 12:56:38 +08:00
// if the base texture was not found without a fallback, switch on fallback mode and re-perform the lookup.
if ( baseTexture = = null )
{
allowFallback = true ;
baseTexture = getTextureWithFallback ( string . Empty ) ;
}
// at this point, any further texture fetches should be correctly using the priority source if the base texture was retrieved using it.
// the flow above handles the case where a sliderendcircle.png is retrieved from the skin, but sliderendcircleoverlay.png doesn't exist.
// expected behaviour in this scenario is not showing the overlay, rather than using hitcircleoverlay.png (potentially from the default/fall-through skin).
2020-10-06 13:12:46 +08:00
Texture overlayTexture = getTextureWithFallback ( "overlay" ) ;
2020-10-06 12:56:38 +08:00
2019-08-30 11:59:58 +08:00
InternalChildren = new Drawable [ ]
{
2020-08-06 04:45:00 +08:00
circleSprites = new Container < Sprite >
2019-08-30 11:59:58 +08:00
{
Anchor = Anchor . Centre ,
Origin = Anchor . Centre ,
2020-08-06 01:07:05 +08:00
RelativeSizeAxes = Axes . Both ,
Children = new [ ]
{
hitCircleSprite = new Sprite
{
2020-10-06 12:56:38 +08:00
Texture = baseTexture ,
2020-08-06 01:07:05 +08:00
Anchor = Anchor . Centre ,
Origin = Anchor . Centre ,
} ,
hitCircleOverlay = new Sprite
{
2020-10-06 12:56:38 +08:00
Texture = overlayTexture ,
2020-08-06 01:07:05 +08:00
Anchor = Anchor . Centre ,
Origin = Anchor . Centre ,
}
}
2019-08-30 11:59:58 +08:00
} ,
2020-10-02 12:40:24 +08:00
} ;
if ( hasNumber )
{
AddInternal ( hitCircleText = new SkinnableSpriteText ( new OsuSkinComponent ( OsuSkinComponents . HitCircleText ) , _ = > new OsuSpriteText
2019-08-30 11:59:58 +08:00
{
Font = OsuFont . Numeric . With ( size : 40 ) ,
UseFullGlyphHeight = false ,
2019-10-03 11:49:32 +08:00
} , confineMode : ConfineMode . NoScaling )
{
Anchor = Anchor . Centre ,
Origin = Anchor . Centre ,
2020-10-02 12:40:24 +08:00
} ) ;
}
2019-08-30 11:59:58 +08:00
2020-03-30 18:42:18 +08:00
bool overlayAboveNumber = skin . GetConfig < OsuSkinConfiguration , bool > ( OsuSkinConfiguration . HitCircleOverlayAboveNumber ) ? . Value ? ? true ;
2020-08-06 01:07:05 +08:00
if ( overlayAboveNumber )
AddInternal ( hitCircleOverlay . CreateProxy ( ) ) ;
2020-03-30 18:42:18 +08:00
2019-08-30 11:59:58 +08:00
accentColour . BindTo ( drawableObject . AccentColour ) ;
2020-11-05 13:40:48 +08:00
indexInCurrentCombo . BindTo ( drawableOsuObject . IndexInCurrentComboBindable ) ;
2020-03-28 12:39:08 +08:00
Texture getTextureWithFallback ( string name )
{
Texture tex = null ;
if ( ! string . IsNullOrEmpty ( priorityLookup ) )
2020-10-06 12:56:38 +08:00
{
2020-03-28 12:39:08 +08:00
tex = skin . GetTexture ( $"{priorityLookup}{name}" ) ;
2020-10-06 12:56:38 +08:00
if ( ! allowFallback )
return tex ;
}
2020-03-28 12:39:08 +08:00
return tex ? ? skin . GetTexture ( $"hitcircle{name}" ) ;
}
2019-08-30 11:59:58 +08:00
}
2020-08-06 01:07:05 +08:00
protected override void LoadComplete ( )
{
base . LoadComplete ( ) ;
2020-08-25 14:16:41 +08:00
accentColour . BindValueChanged ( colour = > hitCircleSprite . Colour = LegacyColourCompatibility . DisallowZeroAlpha ( colour . NewValue ) , true ) ;
2020-10-02 12:40:24 +08:00
if ( hasNumber )
indexInCurrentCombo . BindValueChanged ( index = > hitCircleText . Text = ( index . NewValue + 1 ) . ToString ( ) , true ) ;
2020-11-25 16:54:03 +08:00
drawableObject . ApplyCustomUpdateState + = updateState ;
updateState ( drawableObject , drawableObject . State . Value ) ;
2020-08-06 01:07:05 +08:00
}
2020-11-25 16:54:03 +08:00
private void updateState ( DrawableHitObject drawableObject , ArmedState state )
2019-08-30 11:59:58 +08:00
{
const double legacy_fade_duration = 240 ;
2020-11-04 16:30:23 +08:00
using ( BeginAbsoluteSequence ( drawableObject . HitStateUpdateTime , true ) )
2019-08-30 11:59:58 +08:00
{
2020-11-25 16:54:03 +08:00
switch ( state )
2020-11-04 16:30:23 +08:00
{
case ArmedState . Hit :
circleSprites . FadeOut ( legacy_fade_duration , Easing . Out ) ;
circleSprites . ScaleTo ( 1.4f , legacy_fade_duration , Easing . Out ) ;
2020-10-02 12:40:24 +08:00
2020-11-04 16:30:23 +08:00
if ( hasNumber )
2020-10-02 12:40:24 +08:00
{
2020-11-04 16:30:23 +08:00
var legacyVersion = skin . GetConfig < LegacySetting , decimal > ( LegacySetting . Version ) ? . Value ;
if ( legacyVersion > = 2.0 m )
// legacy skins of version 2.0 and newer only apply very short fade out to the number piece.
hitCircleText . FadeOut ( legacy_fade_duration / 4 , Easing . Out ) ;
else
{
// old skins scale and fade it normally along other pieces.
hitCircleText . FadeOut ( legacy_fade_duration , Easing . Out ) ;
hitCircleText . ScaleTo ( 1.4f , legacy_fade_duration , Easing . Out ) ;
}
2020-10-02 12:40:24 +08:00
}
2019-10-03 10:58:20 +08:00
2020-11-04 16:30:23 +08:00
break ;
}
2019-08-30 11:59:58 +08:00
}
}
}
}