mirror of
https://github.com/ppy/osu.git
synced 2025-01-27 11:12:59 +08:00
Merge branch 'legacy-skin-default-fallback' into fix-skin-sample-lookup
This commit is contained in:
commit
e0f568aa8f
@ -14,18 +14,21 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
|||||||
{
|
{
|
||||||
private readonly Drawable animationContent;
|
private readonly Drawable animationContent;
|
||||||
|
|
||||||
|
private readonly ISkin skin;
|
||||||
|
|
||||||
private Sprite layerNd;
|
private Sprite layerNd;
|
||||||
private Sprite layerSpec;
|
private Sprite layerSpec;
|
||||||
|
|
||||||
public LegacySliderBall(Drawable animationContent)
|
public LegacySliderBall(Drawable animationContent, ISkin skin)
|
||||||
{
|
{
|
||||||
this.animationContent = animationContent;
|
this.animationContent = animationContent;
|
||||||
|
this.skin = skin;
|
||||||
|
|
||||||
AutoSizeAxes = Axes.Both;
|
AutoSizeAxes = Axes.Both;
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(ISkinSource skin)
|
private void load()
|
||||||
{
|
{
|
||||||
var ballColour = skin.GetConfig<OsuSkinColour, Color4>(OsuSkinColour.SliderBall)?.Value ?? Color4.White;
|
var ballColour = skin.GetConfig<OsuSkinColour, Color4>(OsuSkinColour.SliderBall)?.Value ?? Color4.White;
|
||||||
|
|
||||||
|
@ -49,13 +49,16 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
|||||||
return followCircle;
|
return followCircle;
|
||||||
|
|
||||||
case OsuSkinComponents.SliderBall:
|
case OsuSkinComponents.SliderBall:
|
||||||
var sliderBallContent = this.GetAnimation("sliderb", true, true, animationSeparator: "");
|
// specular and nd layers must come from the same source as the ball texure.
|
||||||
|
var ballProvider = Source.FindProvider(s => s.GetTexture("sliderb") != null || s.GetTexture("sliderb0") != null);
|
||||||
|
|
||||||
|
var sliderBallContent = ballProvider.GetAnimation("sliderb", true, true, animationSeparator: "");
|
||||||
|
|
||||||
// todo: slider ball has a custom frame delay based on velocity
|
// todo: slider ball has a custom frame delay based on velocity
|
||||||
// Math.Max((150 / Velocity) * GameBase.SIXTY_FRAME_TIME, GameBase.SIXTY_FRAME_TIME);
|
// Math.Max((150 / Velocity) * GameBase.SIXTY_FRAME_TIME, GameBase.SIXTY_FRAME_TIME);
|
||||||
|
|
||||||
if (sliderBallContent != null)
|
if (sliderBallContent != null)
|
||||||
return new LegacySliderBall(sliderBallContent);
|
return new LegacySliderBall(sliderBallContent, ballProvider);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
|
@ -85,8 +85,12 @@ namespace osu.Game.Rulesets.Taiko.UI
|
|||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(ISkinSource skin)
|
private void load(ISkinSource source)
|
||||||
{
|
{
|
||||||
|
ISkin skin = source.FindProvider(s => getAnimationFrame(s, state, 0) != null);
|
||||||
|
|
||||||
|
if (skin == null) return;
|
||||||
|
|
||||||
for (int frameIndex = 0; true; frameIndex++)
|
for (int frameIndex = 0; true; frameIndex++)
|
||||||
{
|
{
|
||||||
var texture = getAnimationFrame(skin, state, frameIndex);
|
var texture = getAnimationFrame(skin, state, frameIndex);
|
||||||
@ -112,8 +116,12 @@ namespace osu.Game.Rulesets.Taiko.UI
|
|||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(ISkinSource skin)
|
private void load(ISkinSource source)
|
||||||
{
|
{
|
||||||
|
ISkin skin = source.FindProvider(s => getAnimationFrame(s, TaikoMascotAnimationState.Clear, 0) != null);
|
||||||
|
|
||||||
|
if (skin == null) return;
|
||||||
|
|
||||||
foreach (var frameIndex in clear_animation_sequence)
|
foreach (var frameIndex in clear_animation_sequence)
|
||||||
{
|
{
|
||||||
var texture = getAnimationFrame(skin, TaikoMascotAnimationState.Clear, frameIndex);
|
var texture = getAnimationFrame(skin, TaikoMascotAnimationState.Clear, frameIndex);
|
||||||
|
@ -31,8 +31,6 @@ namespace osu.Game.Skinning
|
|||||||
Configuration.LegacyVersion = 2.7m;
|
Configuration.LegacyVersion = 2.7m;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override DefaultLegacySkin CreateFallbackSkin(IResourceStore<byte[]> storage, IStorageResourceProvider resources) => null;
|
|
||||||
|
|
||||||
public static SkinInfo Info { get; } = new SkinInfo
|
public static SkinInfo Info { get; } = new SkinInfo
|
||||||
{
|
{
|
||||||
ID = SkinInfo.CLASSIC_SKIN, // this is temporary until database storage is decided upon.
|
ID = SkinInfo.CLASSIC_SKIN, // this is temporary until database storage is decided upon.
|
||||||
|
@ -70,14 +70,6 @@ namespace osu.Game.Skinning
|
|||||||
return base.GetSample(sampleInfo);
|
return base.GetSample(sampleInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override DefaultLegacySkin CreateFallbackSkin(IResourceStore<byte[]> storage, IStorageResourceProvider resources)
|
|
||||||
{
|
|
||||||
// for simplicity, beatmap skins don't do lookups on the default skin.
|
|
||||||
// this will mean that fallback always occurs to the user (then default) skin.
|
|
||||||
// this may not offer perfect behaviour, but helps keep things simple.
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static SkinInfo createSkinInfo(BeatmapInfo beatmap) =>
|
private static SkinInfo createSkinInfo(BeatmapInfo beatmap) =>
|
||||||
new SkinInfo { Name = beatmap.ToString(), Creator = beatmap.Metadata?.AuthorString };
|
new SkinInfo { Name = beatmap.ToString(), Creator = beatmap.Metadata?.AuthorString };
|
||||||
}
|
}
|
||||||
|
@ -20,9 +20,6 @@ namespace osu.Game.Skinning
|
|||||||
{
|
{
|
||||||
private const double epic_cutoff = 0.5;
|
private const double epic_cutoff = 0.5;
|
||||||
|
|
||||||
[Resolved]
|
|
||||||
private ISkinSource skin { get; set; }
|
|
||||||
|
|
||||||
private LegacyHealthPiece fill;
|
private LegacyHealthPiece fill;
|
||||||
private LegacyHealthPiece marker;
|
private LegacyHealthPiece marker;
|
||||||
|
|
||||||
@ -31,14 +28,14 @@ namespace osu.Game.Skinning
|
|||||||
private bool isNewStyle;
|
private bool isNewStyle;
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load(ISkinSource source)
|
||||||
{
|
{
|
||||||
AutoSizeAxes = Axes.Both;
|
AutoSizeAxes = Axes.Both;
|
||||||
|
|
||||||
var backgroundSource = skin.FindProvider(s => getTexture(s, "bg") != null);
|
var skin = source.FindProvider(s => getTexture(s, "bg") != null);
|
||||||
|
|
||||||
// the marker lookup to decide which display style must be performed on the source of the bg, which is the most common element.
|
// the marker lookup to decide which display style must be performed on the source of the bg, which is the most common element.
|
||||||
isNewStyle = getTexture(backgroundSource, "marker") != null;
|
isNewStyle = getTexture(skin, "marker") != null;
|
||||||
|
|
||||||
// background implementation is the same for both versions.
|
// background implementation is the same for both versions.
|
||||||
AddInternal(new Sprite { Texture = getTexture(skin, "bg") });
|
AddInternal(new Sprite { Texture = getTexture(skin, "bg") });
|
||||||
@ -98,7 +95,7 @@ namespace osu.Game.Skinning
|
|||||||
private readonly Texture dangerTexture;
|
private readonly Texture dangerTexture;
|
||||||
private readonly Texture superDangerTexture;
|
private readonly Texture superDangerTexture;
|
||||||
|
|
||||||
public LegacyOldStyleMarker(ISkinSource skin)
|
public LegacyOldStyleMarker(ISkin skin)
|
||||||
{
|
{
|
||||||
normalTexture = getTexture(skin, "ki");
|
normalTexture = getTexture(skin, "ki");
|
||||||
dangerTexture = getTexture(skin, "kidanger");
|
dangerTexture = getTexture(skin, "kidanger");
|
||||||
@ -129,9 +126,9 @@ namespace osu.Game.Skinning
|
|||||||
|
|
||||||
public class LegacyNewStyleMarker : LegacyMarker
|
public class LegacyNewStyleMarker : LegacyMarker
|
||||||
{
|
{
|
||||||
private readonly ISkinSource skin;
|
private readonly ISkin skin;
|
||||||
|
|
||||||
public LegacyNewStyleMarker(ISkinSource skin)
|
public LegacyNewStyleMarker(ISkin skin)
|
||||||
{
|
{
|
||||||
this.skin = skin;
|
this.skin = skin;
|
||||||
}
|
}
|
||||||
@ -153,7 +150,7 @@ namespace osu.Game.Skinning
|
|||||||
|
|
||||||
internal class LegacyOldStyleFill : LegacyHealthPiece
|
internal class LegacyOldStyleFill : LegacyHealthPiece
|
||||||
{
|
{
|
||||||
public LegacyOldStyleFill(ISkinSource skin)
|
public LegacyOldStyleFill(ISkin skin)
|
||||||
{
|
{
|
||||||
// required for sizing correctly..
|
// required for sizing correctly..
|
||||||
var firstFrame = getTexture(skin, "colour-0");
|
var firstFrame = getTexture(skin, "colour-0");
|
||||||
@ -176,7 +173,7 @@ namespace osu.Game.Skinning
|
|||||||
|
|
||||||
internal class LegacyNewStyleFill : LegacyHealthPiece
|
internal class LegacyNewStyleFill : LegacyHealthPiece
|
||||||
{
|
{
|
||||||
public LegacyNewStyleFill(ISkinSource skin)
|
public LegacyNewStyleFill(ISkin skin)
|
||||||
{
|
{
|
||||||
InternalChild = new Sprite
|
InternalChild = new Sprite
|
||||||
{
|
{
|
||||||
|
@ -109,9 +109,6 @@ namespace osu.Game.Skinning
|
|||||||
true) != null);
|
true) != null);
|
||||||
}
|
}
|
||||||
|
|
||||||
[CanBeNull]
|
|
||||||
protected virtual DefaultLegacySkin CreateFallbackSkin(IResourceStore<byte[]> storage, IStorageResourceProvider resources) => new DefaultLegacySkin(resources);
|
|
||||||
|
|
||||||
public override IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup)
|
public override IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup)
|
||||||
{
|
{
|
||||||
switch (lookup)
|
switch (lookup)
|
||||||
|
@ -27,6 +27,18 @@ namespace osu.Game.Skinning
|
|||||||
{
|
{
|
||||||
Texture texture;
|
Texture texture;
|
||||||
|
|
||||||
|
// find the first source which provides either the animated or non-animated version.
|
||||||
|
ISkin skin = (source as ISkinSource)?.FindProvider(s =>
|
||||||
|
{
|
||||||
|
if (animatable && s.GetTexture(getFrameName(0)) != null)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return s.GetTexture(componentName, wrapModeS, wrapModeT) != null;
|
||||||
|
}) ?? source;
|
||||||
|
|
||||||
|
if (skin == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
if (animatable)
|
if (animatable)
|
||||||
{
|
{
|
||||||
var textures = getTextures().ToArray();
|
var textures = getTextures().ToArray();
|
||||||
@ -35,7 +47,7 @@ namespace osu.Game.Skinning
|
|||||||
{
|
{
|
||||||
var animation = new SkinnableTextureAnimation(startAtCurrentTime)
|
var animation = new SkinnableTextureAnimation(startAtCurrentTime)
|
||||||
{
|
{
|
||||||
DefaultFrameLength = frameLength ?? getFrameLength(source, applyConfigFrameRate, textures),
|
DefaultFrameLength = frameLength ?? getFrameLength(skin, applyConfigFrameRate, textures),
|
||||||
Loop = looping,
|
Loop = looping,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -47,7 +59,7 @@ namespace osu.Game.Skinning
|
|||||||
}
|
}
|
||||||
|
|
||||||
// if an animation was not allowed or not found, fall back to a sprite retrieval.
|
// if an animation was not allowed or not found, fall back to a sprite retrieval.
|
||||||
if ((texture = source.GetTexture(componentName, wrapModeS, wrapModeT)) != null)
|
if ((texture = skin.GetTexture(componentName, wrapModeS, wrapModeT)) != null)
|
||||||
return new Sprite { Texture = texture };
|
return new Sprite { Texture = texture };
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
@ -56,12 +68,14 @@ namespace osu.Game.Skinning
|
|||||||
{
|
{
|
||||||
for (int i = 0; true; i++)
|
for (int i = 0; true; i++)
|
||||||
{
|
{
|
||||||
if ((texture = source.GetTexture($"{componentName}{animationSeparator}{i}", wrapModeS, wrapModeT)) == null)
|
if ((texture = skin.GetTexture(getFrameName(i), wrapModeS, wrapModeT)) == null)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
yield return texture;
|
yield return texture;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string getFrameName(int frameIndex) => $"{componentName}{animationSeparator}{frameIndex}";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool HasFont(this ISkin source, LegacyFont font)
|
public static bool HasFont(this ISkin source, LegacyFont font)
|
||||||
|
@ -16,7 +16,7 @@ namespace osu.Game.Skinning
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Transformer used to handle support of legacy features for individual rulesets.
|
/// Transformer used to handle support of legacy features for individual rulesets.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class LegacySkinTransformer : ISkin
|
public abstract class LegacySkinTransformer : ISkinSource
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Source of the <see cref="ISkin"/> which is being transformed.
|
/// Source of the <see cref="ISkin"/> which is being transformed.
|
||||||
@ -50,5 +50,11 @@ namespace osu.Game.Skinning
|
|||||||
public abstract IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup);
|
public abstract IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup);
|
||||||
|
|
||||||
public ISkin FindProvider(Func<ISkin, bool> lookupFunction) => Source.FindProvider(lookupFunction);
|
public ISkin FindProvider(Func<ISkin, bool> lookupFunction) => Source.FindProvider(lookupFunction);
|
||||||
|
|
||||||
|
public event Action SourceChanged
|
||||||
|
{
|
||||||
|
add { throw new NotSupportedException(); }
|
||||||
|
remove { }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -48,6 +48,8 @@ namespace osu.Game.Skinning
|
|||||||
|
|
||||||
protected override string ImportFromStablePath => "Skins";
|
protected override string ImportFromStablePath => "Skins";
|
||||||
|
|
||||||
|
private readonly Skin defaultLegacySkin;
|
||||||
|
|
||||||
public SkinManager(Storage storage, DatabaseContextFactory contextFactory, GameHost host, IResourceStore<byte[]> resources, AudioManager audio)
|
public SkinManager(Storage storage, DatabaseContextFactory contextFactory, GameHost host, IResourceStore<byte[]> resources, AudioManager audio)
|
||||||
: base(storage, contextFactory, new SkinStore(contextFactory, storage), host)
|
: base(storage, contextFactory, new SkinStore(contextFactory, storage), host)
|
||||||
{
|
{
|
||||||
@ -55,6 +57,8 @@ namespace osu.Game.Skinning
|
|||||||
this.host = host;
|
this.host = host;
|
||||||
this.resources = resources;
|
this.resources = resources;
|
||||||
|
|
||||||
|
defaultLegacySkin = new DefaultLegacySkin(this);
|
||||||
|
|
||||||
CurrentSkinInfo.ValueChanged += skin => CurrentSkin.Value = GetSkin(skin.NewValue);
|
CurrentSkinInfo.ValueChanged += skin => CurrentSkin.Value = GetSkin(skin.NewValue);
|
||||||
|
|
||||||
CurrentSkin.Value = new DefaultSkin(this);
|
CurrentSkin.Value = new DefaultSkin(this);
|
||||||
@ -214,9 +218,16 @@ namespace osu.Game.Skinning
|
|||||||
|
|
||||||
public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) => lookupWithFallback(s => s.GetConfig<TLookup, TValue>(lookup));
|
public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) => lookupWithFallback(s => s.GetConfig<TLookup, TValue>(lookup));
|
||||||
|
|
||||||
public ISkin FindProvider(Func<ISkin, bool> lookupFunction) => lookupFunction(CurrentSkin.Value) ? CurrentSkin.Value : null;
|
public ISkin FindProvider(Func<ISkin, bool> lookupFunction)
|
||||||
|
{
|
||||||
|
if (lookupFunction(CurrentSkin.Value))
|
||||||
|
return CurrentSkin.Value;
|
||||||
|
|
||||||
private Skin defaultLegacySkin;
|
if (CurrentSkin.Value is LegacySkin && lookupFunction(defaultLegacySkin))
|
||||||
|
return defaultLegacySkin;
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
private T lookupWithFallback<T>(Func<ISkin, T> func)
|
private T lookupWithFallback<T>(Func<ISkin, T> func)
|
||||||
where T : class
|
where T : class
|
||||||
@ -226,8 +237,9 @@ namespace osu.Game.Skinning
|
|||||||
if (selectedSkin != null)
|
if (selectedSkin != null)
|
||||||
return selectedSkin;
|
return selectedSkin;
|
||||||
|
|
||||||
defaultLegacySkin ??= new DefaultLegacySkin(this);
|
// 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)
|
if (CurrentSkin.Value is LegacySkin)
|
||||||
return func(defaultLegacySkin);
|
return func(defaultLegacySkin);
|
||||||
|
|
||||||
|
@ -46,8 +46,16 @@ namespace osu.Game.Skinning
|
|||||||
|
|
||||||
public ISkin FindProvider(Func<ISkin, bool> lookupFunction)
|
public ISkin FindProvider(Func<ISkin, bool> lookupFunction)
|
||||||
{
|
{
|
||||||
if (skin != null && lookupFunction(skin))
|
if (skin is ISkinSource source)
|
||||||
return skin;
|
{
|
||||||
|
if (source.FindProvider(lookupFunction) is ISkin found)
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
else if (skin != null)
|
||||||
|
{
|
||||||
|
if (lookupFunction(skin))
|
||||||
|
return skin;
|
||||||
|
}
|
||||||
|
|
||||||
return fallbackSource?.FindProvider(lookupFunction);
|
return fallbackSource?.FindProvider(lookupFunction);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user