// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. using System.Collections.Generic; using System.IO; using System.Linq; using JetBrains.Annotations; using osu.Framework.Audio; using osu.Framework.Audio.Sample; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Textures; using osu.Framework.IO.Stores; using osu.Game.Audio; using osu.Game.IO; using osu.Game.Rulesets.Scoring; using osuTK.Graphics; namespace osu.Game.Skinning { public class LegacySkin : Skin { [CanBeNull] protected TextureStore Textures; [CanBeNull] protected IResourceStore Samples; public new LegacySkinConfiguration Configuration { get => base.Configuration as LegacySkinConfiguration; set => base.Configuration = value; } public LegacySkin(SkinInfo skin, IResourceStore storage, AudioManager audioManager) : this(skin, new LegacySkinResourceStore(skin, storage), audioManager, "skin.ini") { } protected LegacySkin(SkinInfo skin, IResourceStore storage, AudioManager audioManager, string filename) : base(skin) { Stream stream = storage?.GetStream(filename); if (stream != null) { using (LineBufferedReader reader = new LineBufferedReader(stream)) Configuration = new LegacySkinDecoder().Decode(reader); } else Configuration = new LegacySkinConfiguration { LegacyVersion = LegacySkinConfiguration.LATEST_VERSION }; if (storage != null) { Samples = audioManager?.GetSampleStore(storage); Textures = new TextureStore(new TextureLoaderStore(storage)); } } protected override void Dispose(bool isDisposing) { base.Dispose(isDisposing); Textures?.Dispose(); Samples?.Dispose(); } public override IBindable GetConfig(TLookup lookup) { switch (lookup) { case GlobalSkinColours colour: switch (colour) { case GlobalSkinColours.ComboColours: var comboColours = Configuration.ComboColours; if (comboColours != null) return SkinUtils.As(new Bindable>(comboColours)); break; default: return SkinUtils.As(getCustomColour(colour.ToString())); } break; case LegacySkinConfiguration.LegacySetting legacy: switch (legacy) { case LegacySkinConfiguration.LegacySetting.Version: if (Configuration.LegacyVersion is decimal version) return SkinUtils.As(new Bindable(version)); break; } break; case SkinCustomColourLookup customColour: return SkinUtils.As(getCustomColour(customColour.Lookup.ToString())); default: // handles lookups like GlobalSkinConfiguration 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(); if (val != null) bindable.Parse(val); return bindable; } } catch { } break; } return null; } private IBindable getCustomColour(string lookup) => Configuration.CustomColours.TryGetValue(lookup, out var col) ? new Bindable(col) : null; public override Drawable GetDrawableComponent(ISkinComponent component) { switch (component) { case GameplaySkinComponent resultComponent: switch (resultComponent.Component) { case HitResult.Miss: return this.GetAnimation("hit0", true, false); case HitResult.Meh: return this.GetAnimation("hit50", true, false); case HitResult.Good: return this.GetAnimation("hit100", true, false); case HitResult.Great: return this.GetAnimation("hit300", true, false); } break; } return this.GetAnimation(component.LookupName, false, false); } public override Texture GetTexture(string componentName) { componentName = getFallbackName(componentName); float ratio = 2; var texture = Textures?.Get($"{componentName}@2x"); if (texture == null) { ratio = 1; texture = Textures?.Get(componentName); } if (texture != null) texture.ScaleAdjust = ratio; return texture; } public override SampleChannel GetSample(ISampleInfo sampleInfo) { foreach (var lookup in sampleInfo.LookupNames) { var sample = Samples?.Get(lookup); if (sample != null) return sample; } if (sampleInfo is HitSampleInfo hsi) // Try fallback to non-bank samples. return Samples?.Get(hsi.Name); return null; } private string getFallbackName(string componentName) { string lastPiece = componentName.Split('/').Last(); return componentName.StartsWith("Gameplay/taiko/") ? "taiko-" + lastPiece : lastPiece; } } }