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 System;
|
|
|
|
using osu.Framework.Audio.Sample;
|
2019-09-03 16:57:34 +08:00
|
|
|
using osu.Framework.Bindables;
|
2019-08-30 11:59:58 +08:00
|
|
|
using osu.Framework.Graphics;
|
|
|
|
using osu.Framework.Graphics.Textures;
|
|
|
|
using osu.Game.Audio;
|
|
|
|
using osu.Game.Skinning;
|
|
|
|
using osuTK;
|
|
|
|
|
|
|
|
namespace osu.Game.Rulesets.Osu.Skinning
|
|
|
|
{
|
2019-09-03 16:57:34 +08:00
|
|
|
public class OsuLegacySkinTransformer : ISkin
|
2019-08-30 11:59:58 +08:00
|
|
|
{
|
|
|
|
private readonly ISkin source;
|
|
|
|
|
|
|
|
private Lazy<bool> hasHitCircle;
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// On osu-stable, hitcircles have 5 pixels of transparent padding on each side to allow for shadows etc.
|
|
|
|
/// Their hittable area is 128px, but the actual circle portion is 118px.
|
|
|
|
/// We must account for some gameplay elements such as slider bodies, where this padding is not present.
|
|
|
|
/// </summary>
|
|
|
|
private const float legacy_circle_radius = 64 - 5;
|
|
|
|
|
2019-09-03 16:57:34 +08:00
|
|
|
public OsuLegacySkinTransformer(ISkinSource source)
|
2019-08-30 11:59:58 +08:00
|
|
|
{
|
|
|
|
this.source = source;
|
|
|
|
|
|
|
|
source.SourceChanged += sourceChanged;
|
|
|
|
sourceChanged();
|
|
|
|
}
|
|
|
|
|
|
|
|
private void sourceChanged()
|
|
|
|
{
|
|
|
|
hasHitCircle = new Lazy<bool>(() => source.GetTexture("hitcircle") != null);
|
|
|
|
}
|
|
|
|
|
2019-08-30 13:39:02 +08:00
|
|
|
public Drawable GetDrawableComponent(ISkinComponent component)
|
2019-08-30 11:59:58 +08:00
|
|
|
{
|
2019-08-30 13:39:02 +08:00
|
|
|
if (!(component is OsuSkinComponent osuComponent))
|
|
|
|
return null;
|
|
|
|
|
|
|
|
switch (osuComponent.Component)
|
2019-08-30 11:59:58 +08:00
|
|
|
{
|
2019-09-11 13:57:42 +08:00
|
|
|
case OsuSkinComponents.FollowPoint:
|
|
|
|
return this.GetAnimation(component.LookupName, true, false);
|
|
|
|
|
2019-08-30 13:39:02 +08:00
|
|
|
case OsuSkinComponents.SliderFollowCircle:
|
2019-12-06 13:40:45 +08:00
|
|
|
var followCircle = this.GetAnimation("sliderfollowcircle", true, true);
|
2019-12-06 17:53:30 +08:00
|
|
|
if (followCircle != null)
|
2019-12-06 17:54:54 +08:00
|
|
|
// follow circles are 2x the hitcircle resolution in legacy skins (since they are scaled down from >1x
|
2019-12-06 17:53:30 +08:00
|
|
|
followCircle.Scale *= 0.5f;
|
2019-12-06 13:40:45 +08:00
|
|
|
return followCircle;
|
2019-08-30 13:40:36 +08:00
|
|
|
|
2019-08-30 13:39:02 +08:00
|
|
|
case OsuSkinComponents.SliderBall:
|
2019-08-30 11:59:58 +08:00
|
|
|
var sliderBallContent = this.GetAnimation("sliderb", true, true, "");
|
|
|
|
|
|
|
|
if (sliderBallContent != null)
|
|
|
|
{
|
|
|
|
var size = sliderBallContent.Size;
|
|
|
|
|
|
|
|
sliderBallContent.RelativeSizeAxes = Axes.Both;
|
|
|
|
sliderBallContent.Size = Vector2.One;
|
|
|
|
|
|
|
|
return new LegacySliderBall(sliderBallContent)
|
|
|
|
{
|
|
|
|
Size = size
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
2019-08-30 13:39:02 +08:00
|
|
|
case OsuSkinComponents.HitCircle:
|
2019-08-30 11:59:58 +08:00
|
|
|
if (hasHitCircle.Value)
|
|
|
|
return new LegacyMainCirclePiece();
|
|
|
|
|
|
|
|
return null;
|
2019-08-30 12:42:29 +08:00
|
|
|
|
2019-08-30 13:39:02 +08:00
|
|
|
case OsuSkinComponents.Cursor:
|
2019-08-30 12:58:17 +08:00
|
|
|
if (source.GetTexture("cursor") != null)
|
2019-08-30 12:42:29 +08:00
|
|
|
return new LegacyCursor();
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
2019-09-09 16:53:51 +08:00
|
|
|
case OsuSkinComponents.CursorTrail:
|
|
|
|
if (source.GetTexture("cursortrail") != null)
|
|
|
|
return new LegacyCursorTrail();
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
2019-08-30 13:39:02 +08:00
|
|
|
case OsuSkinComponents.HitCircleText:
|
2019-09-10 17:06:24 +08:00
|
|
|
var font = GetConfig<OsuSkinConfiguration, string>(OsuSkinConfiguration.HitCirclePrefix)?.Value ?? "default";
|
2019-09-03 16:57:34 +08:00
|
|
|
var overlap = GetConfig<OsuSkinConfiguration, float>(OsuSkinConfiguration.HitCircleOverlap)?.Value ?? 0;
|
2019-08-30 12:42:29 +08:00
|
|
|
|
|
|
|
return !hasFont(font)
|
|
|
|
? null
|
2019-08-31 11:23:15 +08:00
|
|
|
: new LegacySpriteText(source, font)
|
2019-08-30 12:42:29 +08:00
|
|
|
{
|
2019-09-11 12:39:21 +08:00
|
|
|
// stable applies a blanket 0.8x scale to hitcircle fonts
|
|
|
|
Scale = new Vector2(0.8f),
|
|
|
|
Spacing = new Vector2(-overlap, 0)
|
2019-08-30 12:42:29 +08:00
|
|
|
};
|
2019-08-30 11:59:58 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2019-08-31 15:56:32 +08:00
|
|
|
public Texture GetTexture(string componentName) => source.GetTexture(componentName);
|
2019-08-30 11:59:58 +08:00
|
|
|
|
2019-08-31 15:56:32 +08:00
|
|
|
public SampleChannel GetSample(ISampleInfo sample) => source.GetSample(sample);
|
2019-08-30 11:59:58 +08:00
|
|
|
|
2019-09-03 16:57:34 +08:00
|
|
|
public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup)
|
2019-09-02 11:36:08 +08:00
|
|
|
{
|
2019-09-03 16:57:34 +08:00
|
|
|
switch (lookup)
|
|
|
|
{
|
|
|
|
case OsuSkinColour colour:
|
|
|
|
return source.GetConfig<SkinCustomColourLookup, TValue>(new SkinCustomColourLookup(colour));
|
|
|
|
|
|
|
|
case OsuSkinConfiguration osuLookup:
|
|
|
|
switch (osuLookup)
|
|
|
|
{
|
|
|
|
case OsuSkinConfiguration.SliderPathRadius:
|
|
|
|
if (hasHitCircle.Value)
|
2019-09-05 15:39:58 +08:00
|
|
|
return SkinUtils.As<TValue>(new BindableFloat(legacy_circle_radius));
|
2019-09-03 16:57:34 +08:00
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
2019-09-02 11:36:08 +08:00
|
|
|
|
2019-09-03 16:57:34 +08:00
|
|
|
return source.GetConfig<TLookup, TValue>(lookup);
|
2019-09-02 11:36:08 +08:00
|
|
|
}
|
2019-08-30 12:42:29 +08:00
|
|
|
|
2019-08-31 11:23:15 +08:00
|
|
|
private bool hasFont(string fontName) => source.GetTexture($"{fontName}-0") != null;
|
2019-08-30 11:59:58 +08:00
|
|
|
}
|
|
|
|
}
|