2019-08-21 14:11:33 +08:00
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
2019-01-24 16:43:03 +08:00
// See the LICENCE file in the repository root for full licence text.
2018-04-13 17:19:50 +08:00
2020-04-01 22:32:33 +08:00
using System ;
2019-09-03 16:57:34 +08:00
using System.Collections.Generic ;
2020-04-01 12:38:03 +08:00
using System.Diagnostics ;
2018-04-13 17:19:50 +08:00
using System.IO ;
using System.Linq ;
2019-09-04 14:59:09 +08:00
using JetBrains.Annotations ;
2018-04-13 17:19:50 +08:00
using osu.Framework.Audio.Sample ;
2019-09-03 16:57:34 +08:00
using osu.Framework.Bindables ;
2018-04-13 17:19:50 +08:00
using osu.Framework.Graphics ;
2020-07-17 15:54:30 +08:00
using osu.Framework.Graphics.OpenGL.Textures ;
2018-04-13 17:19:50 +08:00
using osu.Framework.Graphics.Textures ;
using osu.Framework.IO.Stores ;
2019-08-23 19:32:43 +08:00
using osu.Game.Audio ;
2020-04-02 16:56:12 +08:00
using osu.Game.Beatmaps.Formats ;
2019-09-10 06:43:30 +08:00
using osu.Game.IO ;
2019-08-30 14:12:03 +08:00
using osu.Game.Rulesets.Scoring ;
2021-05-17 17:26:15 +08:00
using osu.Game.Screens.Play ;
2020-10-14 16:21:56 +08:00
using osu.Game.Screens.Play.HUD ;
2021-05-18 14:50:40 +08:00
using osu.Game.Screens.Play.HUD.HitErrorMeters ;
2019-07-30 22:06:18 +08:00
using osuTK.Graphics ;
2018-04-13 17:19:50 +08:00
namespace osu.Game.Skinning
{
public class LegacySkin : Skin
{
2021-05-31 14:13:56 +08:00
private readonly bool fallbackToDefault ;
2019-09-04 14:59:09 +08:00
[CanBeNull]
2018-04-13 17:19:50 +08:00
protected TextureStore Textures ;
2019-09-04 14:59:09 +08:00
[CanBeNull]
2021-01-19 16:11:40 +08:00
protected ISampleStore Samples ;
2018-04-13 17:19:50 +08:00
2020-04-01 22:32:33 +08:00
/// <summary>
/// Whether texture for the keys exists.
/// Used to determine if the mania ruleset is skinned.
/// </summary>
private readonly Lazy < bool > hasKeyTexture ;
protected virtual bool AllowManiaSkin = > hasKeyTexture . Value ;
2020-03-31 09:14:36 +08:00
2020-07-29 05:52:09 +08:00
/// <summary>
/// Whether this skin can use samples with a custom bank (custom sample set in stable terminology).
/// Added in order to match sample lookup logic from stable (in stable, only the beatmap skin could use samples with a custom sample bank).
/// </summary>
protected virtual bool UseCustomSampleBanks = > false ;
2019-11-24 09:10:04 +08:00
public new LegacySkinConfiguration Configuration
2019-11-20 06:15:40 +08:00
{
get = > base . Configuration as LegacySkinConfiguration ;
set = > base . Configuration = value ;
}
2019-10-10 04:04:34 +08:00
2020-03-31 09:14:36 +08:00
private readonly Dictionary < int , LegacyManiaSkinConfiguration > maniaConfigurations = new Dictionary < int , LegacyManiaSkinConfiguration > ( ) ;
2021-05-31 14:13:56 +08:00
private readonly DefaultLegacySkin legacyDefaultFallback ;
2021-05-13 04:18:15 +08:00
[UsedImplicitly(ImplicitUseKindFlags.InstantiatedWithFixedConstructorSignature)]
2020-12-21 14:14:32 +08:00
public LegacySkin ( SkinInfo skin , IStorageResourceProvider resources )
2021-05-31 14:13:56 +08:00
: this ( skin , new LegacySkinResourceStore < SkinFileInfo > ( skin , resources . Files ) , resources , "skin.ini" , true )
2018-04-13 17:19:50 +08:00
{
}
2021-05-31 14:13:56 +08:00
/// <summary>
/// Construct a new legacy skin instance.
/// </summary>
/// <param name="skin">The model for this skin.</param>
/// <param name="storage">A storage for looking up files within this skin using user-facing filenames.</param>
/// <param name="resources">Access to raw game resources.</param>
/// <param name="configurationFilename">The user-facing filename of the configuration file to be parsed. Can accept an .osu or skin.ini file.</param>
/// <param name="fallbackToDefault">Whether lookups should fallback to the <see cref="DefaultLegacySkin"/> implementations if not provided locally.</param>
protected LegacySkin ( SkinInfo skin , [ CanBeNull ] IResourceStore < byte [ ] > storage , [ CanBeNull ] IStorageResourceProvider resources , string configurationFilename , bool fallbackToDefault = false )
2021-05-10 21:43:48 +08:00
: base ( skin , resources )
2018-04-13 17:19:50 +08:00
{
2021-05-31 14:13:56 +08:00
this . fallbackToDefault = fallbackToDefault ;
legacyDefaultFallback = new DefaultLegacySkin ( storage , resources ) ;
using ( var stream = storage ? . GetStream ( configurationFilename ) )
2019-11-11 19:53:22 +08:00
{
2020-03-31 09:14:36 +08:00
if ( stream ! = null )
{
using ( LineBufferedReader reader = new LineBufferedReader ( stream , true ) )
Configuration = new LegacySkinDecoder ( ) . Decode ( reader ) ;
stream . Seek ( 0 , SeekOrigin . Begin ) ;
using ( LineBufferedReader reader = new LineBufferedReader ( stream ) )
{
var maniaList = new LegacyManiaSkinDecoder ( ) . Decode ( reader ) ;
foreach ( var config in maniaList )
maniaConfigurations [ config . Keys ] = config ;
}
}
else
2020-04-06 18:36:04 +08:00
Configuration = new LegacySkinConfiguration ( ) ;
2019-11-11 19:53:22 +08:00
}
2018-04-13 17:19:50 +08:00
2019-09-04 14:59:09 +08:00
if ( storage ! = null )
{
2020-12-21 14:14:32 +08:00
var samples = resources ? . AudioManager ? . GetSampleStore ( storage ) ;
2020-03-22 01:16:28 +08:00
if ( samples ! = null )
samples . PlaybackConcurrency = OsuGameBase . SAMPLE_CONCURRENCY ;
Samples = samples ;
2020-12-21 14:14:32 +08:00
Textures = new TextureStore ( resources ? . CreateTextureLoaderStore ( storage ) ) ;
2020-02-18 12:21:55 +08:00
( storage as ResourceStore < byte [ ] > ) ? . AddExtension ( "ogg" ) ;
2019-09-04 14:59:09 +08:00
}
2020-04-01 22:32:33 +08:00
// todo: this shouldn't really be duplicated here (from ManiaLegacySkinTransformer). we need to come up with a better solution.
hasKeyTexture = new Lazy < bool > ( ( ) = > this . GetAnimation (
2020-04-07 15:53:29 +08:00
lookupForMania < string > ( new LegacyManiaSkinConfigurationLookup ( 4 , LegacyManiaSkinConfigurationLookups . KeyImage , 0 ) ) ? . Value ? ? "mania-key1" , true ,
true ) ! = null ) ;
2018-04-13 17:19:50 +08:00
}
2019-09-03 16:57:34 +08:00
public override IBindable < TValue > GetConfig < TLookup , TValue > ( TLookup lookup )
{
switch ( lookup )
{
2020-02-07 13:58:07 +08:00
case GlobalSkinColours colour :
switch ( colour )
2019-09-03 16:57:34 +08:00
{
2020-02-07 13:58:07 +08:00
case GlobalSkinColours . ComboColours :
2019-11-07 04:20:36 +08:00
var comboColours = Configuration . ComboColours ;
if ( comboColours ! = null )
2019-11-07 20:54:30 +08:00
return SkinUtils . As < TValue > ( new Bindable < IReadOnlyList < Color4 > > ( comboColours ) ) ;
2019-10-10 02:08:07 +08:00
break ;
2020-02-07 13:58:07 +08:00
default :
2020-04-02 16:56:12 +08:00
return SkinUtils . As < TValue > ( getCustomColour ( Configuration , colour . ToString ( ) ) ) ;
2019-09-03 16:57:34 +08:00
}
break ;
case SkinCustomColourLookup customColour :
2020-04-02 16:56:12 +08:00
return SkinUtils . As < TValue > ( getCustomColour ( Configuration , customColour . Lookup . ToString ( ) ) ) ;
2019-09-03 16:57:34 +08:00
2020-03-31 17:22:46 +08:00
case LegacyManiaSkinConfigurationLookup maniaLookup :
2020-03-31 09:14:36 +08:00
if ( ! AllowManiaSkin )
2021-05-31 14:27:14 +08:00
break ;
2020-03-31 09:14:36 +08:00
2020-04-01 22:46:50 +08:00
var result = lookupForMania < TValue > ( maniaLookup ) ;
if ( result ! = null )
return result ;
2020-03-31 09:14:36 +08:00
break ;
2020-07-30 12:09:40 +08:00
case LegacySkinConfiguration . LegacySetting legacy :
2020-08-03 01:50:17 +08:00
return legacySettingLookup < TValue > ( legacy ) ;
2020-07-29 15:34:09 +08:00
2019-09-03 16:57:34 +08:00
default :
2020-08-03 01:46:29 +08:00
return genericLookup < TLookup , TValue > ( lookup ) ;
2019-09-03 16:57:34 +08:00
}
2021-05-31 14:27:14 +08:00
return fallbackToDefault ? legacyDefaultFallback . GetConfig < TLookup , TValue > ( lookup ) : null ;
2019-09-03 16:57:34 +08:00
}
2020-04-01 22:46:50 +08:00
private IBindable < TValue > lookupForMania < TValue > ( LegacyManiaSkinConfigurationLookup maniaLookup )
{
if ( ! maniaConfigurations . TryGetValue ( maniaLookup . Keys , out var existing ) )
maniaConfigurations [ maniaLookup . Keys ] = existing = new LegacyManiaSkinConfiguration ( maniaLookup . Keys ) ;
switch ( maniaLookup . Lookup )
{
case LegacyManiaSkinConfigurationLookups . ColumnWidth :
Debug . Assert ( maniaLookup . TargetColumn ! = null ) ;
return SkinUtils . As < TValue > ( new Bindable < float > ( existing . ColumnWidth [ maniaLookup . TargetColumn . Value ] ) ) ;
case LegacyManiaSkinConfigurationLookups . ColumnSpacing :
Debug . Assert ( maniaLookup . TargetColumn ! = null ) ;
return SkinUtils . As < TValue > ( new Bindable < float > ( existing . ColumnSpacing [ maniaLookup . TargetColumn . Value ] ) ) ;
case LegacyManiaSkinConfigurationLookups . HitPosition :
return SkinUtils . As < TValue > ( new Bindable < float > ( existing . HitPosition ) ) ;
2020-12-14 00:00:46 +08:00
case LegacyManiaSkinConfigurationLookups . ScorePosition :
return SkinUtils . As < TValue > ( new Bindable < float > ( existing . ScorePosition ) ) ;
2020-04-01 22:46:50 +08:00
case LegacyManiaSkinConfigurationLookups . LightPosition :
return SkinUtils . As < TValue > ( new Bindable < float > ( existing . LightPosition ) ) ;
case LegacyManiaSkinConfigurationLookups . ShowJudgementLine :
return SkinUtils . As < TValue > ( new Bindable < bool > ( existing . ShowJudgementLine ) ) ;
2020-04-02 13:29:16 +08:00
2020-08-25 14:35:37 +08:00
case LegacyManiaSkinConfigurationLookups . ExplosionImage :
return SkinUtils . As < TValue > ( getManiaImage ( existing , "LightingN" ) ) ;
2020-04-02 13:29:16 +08:00
case LegacyManiaSkinConfigurationLookups . ExplosionScale :
Debug . Assert ( maniaLookup . TargetColumn ! = null ) ;
if ( GetConfig < LegacySkinConfiguration . LegacySetting , decimal > ( LegacySkinConfiguration . LegacySetting . Version ) ? . Value < 2.5 m )
return SkinUtils . As < TValue > ( new Bindable < float > ( 1 ) ) ;
if ( existing . ExplosionWidth [ maniaLookup . TargetColumn . Value ] ! = 0 )
return SkinUtils . As < TValue > ( new Bindable < float > ( existing . ExplosionWidth [ maniaLookup . TargetColumn . Value ] / LegacyManiaSkinConfiguration . DEFAULT_COLUMN_SIZE ) ) ;
return SkinUtils . As < TValue > ( new Bindable < float > ( existing . ColumnWidth [ maniaLookup . TargetColumn . Value ] / LegacyManiaSkinConfiguration . DEFAULT_COLUMN_SIZE ) ) ;
2020-04-02 22:57:03 +08:00
2020-04-02 17:10:17 +08:00
case LegacyManiaSkinConfigurationLookups . ColumnLineColour :
return SkinUtils . As < TValue > ( getCustomColour ( existing , "ColourColumnLine" ) ) ;
2020-04-07 15:50:08 +08:00
case LegacyManiaSkinConfigurationLookups . JudgementLineColour :
return SkinUtils . As < TValue > ( getCustomColour ( existing , "ColourJudgementLine" ) ) ;
2020-04-07 15:53:29 +08:00
case LegacyManiaSkinConfigurationLookups . ColumnBackgroundColour :
Debug . Assert ( maniaLookup . TargetColumn ! = null ) ;
2020-04-07 16:11:32 +08:00
return SkinUtils . As < TValue > ( getCustomColour ( existing , $"Colour{maniaLookup.TargetColumn + 1}" ) ) ;
2020-04-07 15:53:29 +08:00
case LegacyManiaSkinConfigurationLookups . ColumnLightColour :
Debug . Assert ( maniaLookup . TargetColumn ! = null ) ;
2020-04-07 16:11:32 +08:00
return SkinUtils . As < TValue > ( getCustomColour ( existing , $"ColourLight{maniaLookup.TargetColumn + 1}" ) ) ;
2020-04-07 22:36:42 +08:00
2020-04-07 15:07:18 +08:00
case LegacyManiaSkinConfigurationLookups . MinimumColumnWidth :
return SkinUtils . As < TValue > ( new Bindable < float > ( existing . MinimumColumnWidth ) ) ;
2020-04-07 21:41:22 +08:00
2020-04-06 18:04:02 +08:00
case LegacyManiaSkinConfigurationLookups . NoteImage :
Debug . Assert ( maniaLookup . TargetColumn ! = null ) ;
return SkinUtils . As < TValue > ( getManiaImage ( existing , $"NoteImage{maniaLookup.TargetColumn}" ) ) ;
case LegacyManiaSkinConfigurationLookups . HoldNoteHeadImage :
Debug . Assert ( maniaLookup . TargetColumn ! = null ) ;
return SkinUtils . As < TValue > ( getManiaImage ( existing , $"NoteImage{maniaLookup.TargetColumn}H" ) ) ;
case LegacyManiaSkinConfigurationLookups . HoldNoteTailImage :
Debug . Assert ( maniaLookup . TargetColumn ! = null ) ;
return SkinUtils . As < TValue > ( getManiaImage ( existing , $"NoteImage{maniaLookup.TargetColumn}T" ) ) ;
case LegacyManiaSkinConfigurationLookups . HoldNoteBodyImage :
Debug . Assert ( maniaLookup . TargetColumn ! = null ) ;
return SkinUtils . As < TValue > ( getManiaImage ( existing , $"NoteImage{maniaLookup.TargetColumn}L" ) ) ;
2020-08-26 19:21:41 +08:00
case LegacyManiaSkinConfigurationLookups . HoldNoteLightImage :
return SkinUtils . As < TValue > ( getManiaImage ( existing , "LightingL" ) ) ;
case LegacyManiaSkinConfigurationLookups . HoldNoteLightScale :
Debug . Assert ( maniaLookup . TargetColumn ! = null ) ;
if ( GetConfig < LegacySkinConfiguration . LegacySetting , decimal > ( LegacySkinConfiguration . LegacySetting . Version ) ? . Value < 2.5 m )
return SkinUtils . As < TValue > ( new Bindable < float > ( 1 ) ) ;
if ( existing . HoldNoteLightWidth [ maniaLookup . TargetColumn . Value ] ! = 0 )
return SkinUtils . As < TValue > ( new Bindable < float > ( existing . HoldNoteLightWidth [ maniaLookup . TargetColumn . Value ] / LegacyManiaSkinConfiguration . DEFAULT_COLUMN_SIZE ) ) ;
return SkinUtils . As < TValue > ( new Bindable < float > ( existing . ColumnWidth [ maniaLookup . TargetColumn . Value ] / LegacyManiaSkinConfiguration . DEFAULT_COLUMN_SIZE ) ) ;
2020-04-06 18:04:02 +08:00
case LegacyManiaSkinConfigurationLookups . KeyImage :
Debug . Assert ( maniaLookup . TargetColumn ! = null ) ;
return SkinUtils . As < TValue > ( getManiaImage ( existing , $"KeyImage{maniaLookup.TargetColumn}" ) ) ;
case LegacyManiaSkinConfigurationLookups . KeyImageDown :
Debug . Assert ( maniaLookup . TargetColumn ! = null ) ;
return SkinUtils . As < TValue > ( getManiaImage ( existing , $"KeyImage{maniaLookup.TargetColumn}D" ) ) ;
2020-04-08 14:36:07 +08:00
case LegacyManiaSkinConfigurationLookups . LeftStageImage :
return SkinUtils . As < TValue > ( getManiaImage ( existing , "StageLeft" ) ) ;
case LegacyManiaSkinConfigurationLookups . RightStageImage :
return SkinUtils . As < TValue > ( getManiaImage ( existing , "StageRight" ) ) ;
2020-04-21 16:14:04 +08:00
2020-07-05 13:02:50 +08:00
case LegacyManiaSkinConfigurationLookups . BottomStageImage :
return SkinUtils . As < TValue > ( getManiaImage ( existing , "StageBottom" ) ) ;
case LegacyManiaSkinConfigurationLookups . LightImage :
return SkinUtils . As < TValue > ( getManiaImage ( existing , "StageLight" ) ) ;
case LegacyManiaSkinConfigurationLookups . HitTargetImage :
return SkinUtils . As < TValue > ( getManiaImage ( existing , "StageHint" ) ) ;
2020-04-21 16:14:04 +08:00
case LegacyManiaSkinConfigurationLookups . LeftLineWidth :
Debug . Assert ( maniaLookup . TargetColumn ! = null ) ;
return SkinUtils . As < TValue > ( new Bindable < float > ( existing . ColumnLineWidth [ maniaLookup . TargetColumn . Value ] ) ) ;
case LegacyManiaSkinConfigurationLookups . RightLineWidth :
Debug . Assert ( maniaLookup . TargetColumn ! = null ) ;
return SkinUtils . As < TValue > ( new Bindable < float > ( existing . ColumnLineWidth [ maniaLookup . TargetColumn . Value + 1 ] ) ) ;
2020-06-12 21:22:22 +08:00
case LegacyManiaSkinConfigurationLookups . Hit0 :
case LegacyManiaSkinConfigurationLookups . Hit50 :
case LegacyManiaSkinConfigurationLookups . Hit100 :
case LegacyManiaSkinConfigurationLookups . Hit200 :
case LegacyManiaSkinConfigurationLookups . Hit300 :
case LegacyManiaSkinConfigurationLookups . Hit300g :
2020-06-13 20:19:06 +08:00
return SkinUtils . As < TValue > ( getManiaImage ( existing , maniaLookup . Lookup . ToString ( ) ) ) ;
2020-08-26 14:37:16 +08:00
case LegacyManiaSkinConfigurationLookups . KeysUnderNotes :
return SkinUtils . As < TValue > ( new Bindable < bool > ( existing . KeysUnderNotes ) ) ;
2020-04-01 22:46:50 +08:00
}
return null ;
}
2020-04-02 16:56:12 +08:00
private IBindable < Color4 > getCustomColour ( IHasCustomColours source , string lookup )
= > source . CustomColours . TryGetValue ( lookup , out var col ) ? new Bindable < Color4 > ( col ) : null ;
2019-09-03 16:57:34 +08:00
2020-04-06 18:04:02 +08:00
private IBindable < string > getManiaImage ( LegacyManiaSkinConfiguration source , string lookup )
= > source . ImageLookups . TryGetValue ( lookup , out var image ) ? new Bindable < string > ( image ) : null ;
2020-08-03 01:50:17 +08:00
[CanBeNull]
private IBindable < TValue > legacySettingLookup < TValue > ( LegacySkinConfiguration . LegacySetting legacySetting )
{
switch ( legacySetting )
{
case LegacySkinConfiguration . LegacySetting . Version :
return SkinUtils . As < TValue > ( new Bindable < decimal > ( Configuration . LegacyVersion ? ? LegacySkinConfiguration . LATEST_VERSION ) ) ;
default :
return genericLookup < LegacySkinConfiguration . LegacySetting , TValue > ( legacySetting ) ;
}
}
2020-08-03 01:46:29 +08:00
[CanBeNull]
private IBindable < TValue > genericLookup < TLookup , TValue > ( TLookup lookup )
{
try
{
if ( Configuration . ConfigDictionary . TryGetValue ( lookup . ToString ( ) , out var val ) )
{
// special case for handling skins which use 1 or 0 to signify a boolean state.
if ( typeof ( TValue ) = = typeof ( bool ) )
val = val = = "1" ? "true" : "false" ;
var bindable = new Bindable < TValue > ( ) ;
if ( val ! = null )
bindable . Parse ( val ) ;
return bindable ;
}
}
catch
{
}
2021-05-31 14:27:14 +08:00
return fallbackToDefault ? legacyDefaultFallback . GetConfig < TLookup , TValue > ( lookup ) : null ;
2020-08-03 01:46:29 +08:00
}
2019-08-30 13:39:02 +08:00
public override Drawable GetDrawableComponent ( ISkinComponent component )
2018-04-13 17:19:50 +08:00
{
2021-05-10 21:43:48 +08:00
if ( base . GetDrawableComponent ( component ) is Drawable c )
return c ;
2019-08-30 14:12:03 +08:00
switch ( component )
2018-04-13 17:19:50 +08:00
{
2021-05-10 21:43:48 +08:00
case SkinnableTargetComponent target :
switch ( target . Target )
{
case SkinnableTarget . MainHUDComponents :
2021-05-13 17:51:23 +08:00
var skinnableTargetWrapper = new SkinnableTargetComponentsContainer ( container = >
2021-05-11 12:12:24 +08:00
{
var score = container . OfType < LegacyScoreCounter > ( ) . FirstOrDefault ( ) ;
var accuracy = container . OfType < GameplayAccuracyCounter > ( ) . FirstOrDefault ( ) ;
2021-05-23 15:46:32 +08:00
var combo = container . OfType < LegacyComboCounter > ( ) . FirstOrDefault ( ) ;
2021-05-11 12:12:24 +08:00
if ( score ! = null & & accuracy ! = null )
{
accuracy . Y = container . ToLocalSpace ( score . ScreenSpaceDrawQuad . BottomRight ) . Y ;
}
2021-05-18 14:50:40 +08:00
var songProgress = container . OfType < SongProgress > ( ) . FirstOrDefault ( ) ;
var hitError = container . OfType < HitErrorMeter > ( ) . FirstOrDefault ( ) ;
if ( hitError ! = null )
{
hitError . Anchor = Anchor . BottomCentre ;
hitError . Origin = Anchor . CentreLeft ;
hitError . Rotation = - 90 ;
2021-05-23 15:46:32 +08:00
}
2021-05-18 14:50:40 +08:00
2021-05-23 15:46:32 +08:00
if ( songProgress ! = null )
{
if ( hitError ! = null ) hitError . Y - = SongProgress . MAX_HEIGHT ;
if ( combo ! = null ) combo . Y - = SongProgress . MAX_HEIGHT ;
2021-05-18 14:50:40 +08:00
}
2021-05-11 12:12:24 +08:00
} )
2021-05-10 21:43:48 +08:00
{
Children = new [ ]
{
// TODO: these should fallback to the osu!classic skin.
GetDrawableComponent ( new HUDSkinComponent ( HUDSkinComponents . ComboCounter ) ) ? ? new DefaultComboCounter ( ) ,
GetDrawableComponent ( new HUDSkinComponent ( HUDSkinComponents . ScoreCounter ) ) ? ? new DefaultScoreCounter ( ) ,
GetDrawableComponent ( new HUDSkinComponent ( HUDSkinComponents . AccuracyCounter ) ) ? ? new DefaultAccuracyCounter ( ) ,
GetDrawableComponent ( new HUDSkinComponent ( HUDSkinComponents . HealthDisplay ) ) ? ? new DefaultHealthDisplay ( ) ,
2021-05-17 17:26:15 +08:00
GetDrawableComponent ( new HUDSkinComponent ( HUDSkinComponents . SongProgress ) ) ? ? new SongProgress ( ) ,
2021-05-18 14:50:40 +08:00
GetDrawableComponent ( new HUDSkinComponent ( HUDSkinComponents . BarHitErrorMeter ) ) ? ? new BarHitErrorMeter ( ) ,
2021-05-10 21:43:48 +08:00
}
} ;
2021-05-11 12:12:24 +08:00
return skinnableTargetWrapper ;
2021-05-10 21:43:48 +08:00
}
return null ;
2020-10-14 16:21:56 +08:00
case HUDSkinComponent hudComponent :
{
2021-03-07 07:30:16 +08:00
if ( ! this . HasFont ( LegacyFont . Score ) )
2020-10-15 16:48:50 +08:00
return null ;
2020-10-14 16:21:56 +08:00
switch ( hudComponent . Component )
{
case HUDSkinComponents . ComboCounter :
return new LegacyComboCounter ( ) ;
2020-10-14 16:51:03 +08:00
2020-10-15 15:32:20 +08:00
case HUDSkinComponents . ScoreCounter :
2021-05-10 21:36:20 +08:00
return new LegacyScoreCounter ( ) ;
2020-10-15 16:48:50 +08:00
case HUDSkinComponents . AccuracyCounter :
2021-05-10 21:36:20 +08:00
return new LegacyAccuracyCounter ( ) ;
2020-10-16 13:39:45 +08:00
case HUDSkinComponents . HealthDisplay :
2021-05-10 21:36:20 +08:00
return new LegacyHealthDisplay ( ) ;
2020-10-14 16:21:56 +08:00
}
return null ;
}
2019-08-30 14:10:11 +08:00
case GameplaySkinComponent < HitResult > resultComponent :
2020-11-18 14:38:26 +08:00
Func < Drawable > createDrawable = ( ) = > getJudgementAnimation ( resultComponent . Component ) ;
2020-11-18 16:15:45 +08:00
// kind of wasteful that we throw this away, but should do for now.
2020-11-18 14:38:26 +08:00
if ( createDrawable ( ) ! = null )
{
2021-01-15 13:51:26 +08:00
var particle = getParticleTexture ( resultComponent . Component ) ;
if ( particle ! = null )
return new LegacyJudgementPieceNew ( resultComponent . Component , createDrawable , particle ) ;
2020-11-18 14:38:26 +08:00
else
return new LegacyJudgementPieceOld ( resultComponent . Component , createDrawable ) ;
}
2019-04-01 11:16:05 +08:00
2020-11-17 14:44:15 +08:00
break ;
}
2019-04-01 11:16:05 +08:00
2020-11-17 14:44:15 +08:00
return this . GetAnimation ( component . LookupName , false , false ) ;
}
2019-04-01 11:16:05 +08:00
2020-11-19 14:47:02 +08:00
private Texture getParticleTexture ( HitResult result )
2020-11-18 14:38:26 +08:00
{
switch ( result )
{
case HitResult . Meh :
2020-11-19 14:47:02 +08:00
return GetTexture ( "particle50" ) ;
2020-11-18 14:38:26 +08:00
case HitResult . Ok :
2020-11-19 14:47:02 +08:00
return GetTexture ( "particle100" ) ;
2020-11-18 14:38:26 +08:00
case HitResult . Great :
2020-11-19 14:47:02 +08:00
return GetTexture ( "particle300" ) ;
2020-11-18 14:38:26 +08:00
}
return null ;
}
2020-11-17 14:44:15 +08:00
private Drawable getJudgementAnimation ( HitResult result )
{
switch ( result )
{
case HitResult . Miss :
return this . GetAnimation ( "hit0" , true , false ) ;
2019-08-30 14:12:03 +08:00
2020-11-17 14:44:15 +08:00
case HitResult . Meh :
return this . GetAnimation ( "hit50" , true , false ) ;
case HitResult . Ok :
return this . GetAnimation ( "hit100" , true , false ) ;
case HitResult . Great :
return this . GetAnimation ( "hit300" , true , false ) ;
2018-04-13 17:19:50 +08:00
}
2020-11-17 14:44:15 +08:00
return null ;
2019-08-19 18:23:54 +08:00
}
2020-07-17 15:54:30 +08:00
public override Texture GetTexture ( string componentName , WrapMode wrapModeS , WrapMode wrapModeT )
2019-08-27 16:18:32 +08:00
{
2020-04-06 18:02:50 +08:00
foreach ( var name in getFallbackNames ( componentName ) )
{
float ratio = 2 ;
2020-07-17 15:54:30 +08:00
var texture = Textures ? . Get ( $"{name}@2x" , wrapModeS , wrapModeT ) ;
2019-08-27 16:18:32 +08:00
2020-04-06 18:02:50 +08:00
if ( texture = = null )
{
ratio = 1 ;
2020-07-17 15:54:30 +08:00
texture = Textures ? . Get ( name , wrapModeS , wrapModeT ) ;
2020-04-06 18:02:50 +08:00
}
2019-08-27 16:18:32 +08:00
2020-04-08 04:50:25 +08:00
if ( texture = = null )
continue ;
2019-08-27 16:18:32 +08:00
2020-04-08 04:50:25 +08:00
texture . ScaleAdjust = ratio ;
2020-04-06 18:02:50 +08:00
return texture ;
2019-08-27 16:18:32 +08:00
}
2020-04-06 18:02:50 +08:00
return null ;
2019-08-27 16:18:32 +08:00
}
2021-02-18 17:32:28 +08:00
public override ISample GetSample ( ISampleInfo sampleInfo )
2019-08-22 17:50:47 +08:00
{
2020-10-30 11:28:40 +08:00
IEnumerable < string > lookupNames ;
2020-07-29 05:52:09 +08:00
if ( sampleInfo is HitSampleInfo hitSample )
lookupNames = getLegacyLookupNames ( hitSample ) ;
2020-10-30 10:14:08 +08:00
else
{
lookupNames = sampleInfo . LookupNames . SelectMany ( getFallbackNames ) ;
}
2020-07-29 05:52:09 +08:00
foreach ( var lookup in lookupNames )
2019-08-22 17:50:47 +08:00
{
2020-01-02 13:07:22 +08:00
var sample = Samples ? . Get ( lookup ) ;
2019-08-23 19:32:43 +08:00
if ( sample ! = null )
return sample ;
2019-08-22 17:50:47 +08:00
}
2021-05-31 14:27:14 +08:00
return fallbackToDefault ? legacyDefaultFallback . GetSample ( sampleInfo ) : null ;
2019-08-22 17:50:47 +08:00
}
2019-08-27 16:18:32 +08:00
2020-07-29 05:52:09 +08:00
private IEnumerable < string > getLegacyLookupNames ( HitSampleInfo hitSample )
{
2020-10-30 10:14:08 +08:00
var lookupNames = hitSample . LookupNames . SelectMany ( getFallbackNames ) ;
2020-07-29 05:52:09 +08:00
if ( ! UseCustomSampleBanks & & ! string . IsNullOrEmpty ( hitSample . Suffix ) )
2020-10-30 10:14:08 +08:00
{
2020-07-29 05:52:09 +08:00
// for compatibility with stable, exclude the lookup names with the custom sample bank suffix, if they are not valid for use in this skin.
// using .EndsWith() is intentional as it ensures parity in all edge cases
// (see LegacyTaikoSampleInfo for an example of one - prioritising the taiko prefix should still apply, but the sample bank should not).
2020-10-30 21:33:05 +08:00
lookupNames = lookupNames . Where ( name = > ! name . EndsWith ( hitSample . Suffix , StringComparison . Ordinal ) ) ;
2020-10-30 10:14:08 +08:00
}
2020-07-29 05:52:09 +08:00
2020-10-30 21:33:05 +08:00
foreach ( var l in lookupNames )
yield return l ;
2020-07-31 04:07:07 +08:00
// also for compatibility, try falling back to non-bank samples (so-called "universal" samples) as the last resort.
// going forward specifying banks shall always be required, even for elements that wouldn't require it on stable,
// which is why this is done locally here.
2020-10-30 10:14:08 +08:00
yield return hitSample . Name ;
}
private IEnumerable < string > getFallbackNames ( string componentName )
{
// May be something like "Gameplay/osu/approachcircle" from lazer, or "Arrows/note1" from a user skin.
yield return componentName ;
2020-07-31 04:07:07 +08:00
2020-10-30 10:14:08 +08:00
// Fall back to using the last piece for components coming from lazer (e.g. "Gameplay/osu/approachcircle" -> "approachcircle").
string lastPiece = componentName . Split ( '/' ) . Last ( ) ;
yield return componentName . StartsWith ( "Gameplay/taiko/" , StringComparison . Ordinal ) ? "taiko-" + lastPiece : lastPiece ;
2020-07-29 05:52:09 +08:00
}
2021-02-22 17:34:05 +08:00
protected override void Dispose ( bool isDisposing )
{
base . Dispose ( isDisposing ) ;
Textures ? . Dispose ( ) ;
Samples ? . Dispose ( ) ;
}
2021-05-31 16:04:38 +08:00
ISkin ISkin . FindProvider ( Func < ISkin , bool > lookupFunction )
{
if ( lookupFunction ( this ) )
return this ;
if ( ! fallbackToDefault )
return null ;
return ( legacyDefaultFallback as ISkin ) ? . FindProvider ( lookupFunction ) ;
}
2018-04-13 17:19:50 +08:00
}
}