1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-11 14:17:26 +08:00

Merge pull request #17421 from peppy/skin-nullable

Apply `nullable` to skin classes
This commit is contained in:
Dean Herbert 2022-03-25 19:39:04 +09:00 committed by GitHub
commit ed239d7016
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 66 additions and 52 deletions

View File

@ -1,7 +1,8 @@
// 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 JetBrains.Annotations;
#nullable enable
using osu.Framework.Audio.Sample;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
@ -21,16 +22,14 @@ namespace osu.Game.Skinning
/// </summary>
/// <param name="component">The requested component.</param>
/// <returns>A drawable representation for the requested component, or null if unavailable.</returns>
[CanBeNull]
Drawable GetDrawableComponent(ISkinComponent component);
Drawable? GetDrawableComponent(ISkinComponent component);
/// <summary>
/// Retrieve a <see cref="Texture"/>.
/// </summary>
/// <param name="componentName">The requested texture.</param>
/// <returns>A matching texture, or null if unavailable.</returns>
[CanBeNull]
Texture GetTexture(string componentName) => GetTexture(componentName, default, default);
Texture? GetTexture(string componentName) => GetTexture(componentName, default, default);
/// <summary>
/// Retrieve a <see cref="Texture"/>.
@ -39,23 +38,22 @@ namespace osu.Game.Skinning
/// <param name="wrapModeS">The texture wrap mode in horizontal direction.</param>
/// <param name="wrapModeT">The texture wrap mode in vertical direction.</param>
/// <returns>A matching texture, or null if unavailable.</returns>
[CanBeNull]
Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT);
Texture? GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT);
/// <summary>
/// Retrieve a <see cref="SampleChannel"/>.
/// </summary>
/// <param name="sampleInfo">The requested sample.</param>
/// <returns>A matching sample channel, or null if unavailable.</returns>
[CanBeNull]
ISample GetSample(ISampleInfo sampleInfo);
ISample? GetSample(ISampleInfo sampleInfo);
/// <summary>
/// Retrieve a configuration value.
/// </summary>
/// <param name="lookup">The requested configuration value.</param>
/// <returns>A matching value boxed in an <see cref="IBindable{TValue}"/>, or null if unavailable.</returns>
[CanBeNull]
IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup);
IBindable<TValue>? GetConfig<TLookup, TValue>(TLookup lookup)
where TLookup : notnull
where TValue : notnull;
}
}

View File

@ -1,9 +1,11 @@
// 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 JetBrains.Annotations;
#nullable enable
using osu.Framework.Audio.Sample;
using osu.Framework.Bindables;
using osu.Framework.Extensions.ObjectExtensions;
using osu.Framework.Graphics;
using osu.Framework.IO.Stores;
using osu.Game.Audio;
@ -26,14 +28,14 @@ namespace osu.Game.Skinning
/// </summary>
/// <param name="beatmapInfo">The model for this beatmap.</param>
/// <param name="resources">Access to raw game resources.</param>
public LegacyBeatmapSkin(BeatmapInfo beatmapInfo, [CanBeNull] IStorageResourceProvider resources)
: base(createSkinInfo(beatmapInfo), resources, createRealmBackedStore(beatmapInfo, resources), beatmapInfo.Path)
public LegacyBeatmapSkin(BeatmapInfo beatmapInfo, IStorageResourceProvider? resources)
: base(createSkinInfo(beatmapInfo), resources, createRealmBackedStore(beatmapInfo, resources), beatmapInfo.Path.AsNonNull())
{
// Disallow default colours fallback on beatmap skins to allow using parent skin combo colours. (via SkinProvidingContainer)
Configuration.AllowDefaultComboColoursFallback = false;
}
private static IResourceStore<byte[]> createRealmBackedStore(BeatmapInfo beatmapInfo, [CanBeNull] IStorageResourceProvider resources)
private static IResourceStore<byte[]> createRealmBackedStore(BeatmapInfo beatmapInfo, IStorageResourceProvider? resources)
{
if (resources == null)
// should only ever be used in tests.
@ -42,7 +44,7 @@ namespace osu.Game.Skinning
return new RealmBackedResourceStore(beatmapInfo.BeatmapSet, resources.Files, new[] { @"ogg" });
}
public override Drawable GetDrawableComponent(ISkinComponent component)
public override Drawable? GetDrawableComponent(ISkinComponent component)
{
if (component is SkinnableTargetComponent targetComponent)
{
@ -61,7 +63,7 @@ namespace osu.Game.Skinning
return base.GetDrawableComponent(component);
}
public override IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup)
public override IBindable<TValue>? GetConfig<TLookup, TValue>(TLookup lookup)
{
switch (lookup)
{
@ -77,10 +79,10 @@ namespace osu.Game.Skinning
return base.GetConfig<TLookup, TValue>(lookup);
}
protected override IBindable<Color4> GetComboColour(IHasComboColours source, int comboIndex, IHasComboInformation combo)
protected override IBindable<Color4>? GetComboColour(IHasComboColours source, int comboIndex, IHasComboInformation combo)
=> base.GetComboColour(source, combo.ComboIndexWithOffsets, combo);
public override ISample GetSample(ISampleInfo sampleInfo)
public override ISample? GetSample(ISampleInfo sampleInfo)
{
if (sampleInfo is ConvertHitObjectParser.LegacyHitSampleInfo legacy && legacy.CustomSampleBank == 0)
{

View File

@ -1,6 +1,8 @@
// 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.
#nullable enable
using System;
using System.Collections.Generic;
using System.Diagnostics;
@ -57,7 +59,7 @@ namespace osu.Game.Skinning
/// <param name="resources">Access to raw game resources.</param>
/// <param name="storage">An optional store which will be used for looking up skin resources. If null, one will be created from realm <see cref="IHasRealmFiles"/> pattern.</param>
/// <param name="configurationFilename">The user-facing filename of the configuration file to be parsed. Can accept an .osu or skin.ini file.</param>
protected LegacySkin(SkinInfo skin, [CanBeNull] IStorageResourceProvider resources, [CanBeNull] IResourceStore<byte[]> storage, string configurationFilename = @"skin.ini")
protected LegacySkin(SkinInfo skin, IStorageResourceProvider? resources, IResourceStore<byte[]>? storage, string configurationFilename = @"skin.ini")
: base(skin, resources, storage, configurationFilename)
{
// todo: this shouldn't really be duplicated here (from ManiaLegacySkinTransformer). we need to come up with a better solution.
@ -81,7 +83,7 @@ namespace osu.Game.Skinning
}
}
public override IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup)
public override IBindable<TValue>? GetConfig<TLookup, TValue>(TLookup lookup)
{
switch (lookup)
{
@ -127,7 +129,7 @@ namespace osu.Game.Skinning
return null;
}
private IBindable<TValue> lookupForMania<TValue>(LegacyManiaSkinConfigurationLookup maniaLookup)
private IBindable<TValue>? lookupForMania<TValue>(LegacyManiaSkinConfigurationLookup maniaLookup)
{
if (!maniaConfigurations.TryGetValue(maniaLookup.Keys, out var existing))
maniaConfigurations[maniaLookup.Keys] = existing = new LegacyManiaSkinConfiguration(maniaLookup.Keys);
@ -267,20 +269,20 @@ namespace osu.Game.Skinning
/// <param name="source">The source to retrieve the combo colours from.</param>
/// <param name="colourIndex">The preferred index for retrieving the combo colour with.</param>
/// <param name="combo">Information on the combo whose using the returned colour.</param>
protected virtual IBindable<Color4> GetComboColour(IHasComboColours source, int colourIndex, IHasComboInformation combo)
protected virtual IBindable<Color4>? GetComboColour(IHasComboColours source, int colourIndex, IHasComboInformation combo)
{
var colour = source.ComboColours?[colourIndex % source.ComboColours.Count];
return colour.HasValue ? new Bindable<Color4>(colour.Value) : null;
}
private IBindable<Color4> getCustomColour(IHasCustomColours source, string lookup)
private IBindable<Color4>? getCustomColour(IHasCustomColours source, string lookup)
=> source.CustomColours.TryGetValue(lookup, out var col) ? new Bindable<Color4>(col) : null;
private IBindable<string> getManiaImage(LegacyManiaSkinConfiguration source, string lookup)
private IBindable<string>? getManiaImage(LegacyManiaSkinConfiguration source, string lookup)
=> source.ImageLookups.TryGetValue(lookup, out string image) ? new Bindable<string>(image) : null;
[CanBeNull]
private IBindable<TValue> legacySettingLookup<TValue>(SkinConfiguration.LegacySetting legacySetting)
private IBindable<TValue>? legacySettingLookup<TValue>(SkinConfiguration.LegacySetting legacySetting)
where TValue : notnull
{
switch (legacySetting)
{
@ -292,8 +294,9 @@ namespace osu.Game.Skinning
}
}
[CanBeNull]
private IBindable<TValue> genericLookup<TLookup, TValue>(TLookup lookup)
private IBindable<TValue>? genericLookup<TLookup, TValue>(TLookup lookup)
where TLookup : notnull
where TValue : notnull
{
try
{
@ -316,7 +319,7 @@ namespace osu.Game.Skinning
return null;
}
public override Drawable GetDrawableComponent(ISkinComponent component)
public override Drawable? GetDrawableComponent(ISkinComponent component)
{
if (base.GetDrawableComponent(component) is Drawable c)
return c;
@ -374,7 +377,7 @@ namespace osu.Game.Skinning
case GameplaySkinComponent<HitResult> resultComponent:
// TODO: this should be inside the judgement pieces.
Func<Drawable> createDrawable = () => getJudgementAnimation(resultComponent.Component);
Func<Drawable?> createDrawable = () => getJudgementAnimation(resultComponent.Component);
// kind of wasteful that we throw this away, but should do for now.
if (createDrawable() != null)
@ -393,7 +396,7 @@ namespace osu.Game.Skinning
return this.GetAnimation(component.LookupName, false, false);
}
private Texture getParticleTexture(HitResult result)
private Texture? getParticleTexture(HitResult result)
{
switch (result)
{
@ -410,7 +413,7 @@ namespace osu.Game.Skinning
return null;
}
private Drawable getJudgementAnimation(HitResult result)
private Drawable? getJudgementAnimation(HitResult result)
{
switch (result)
{
@ -430,7 +433,7 @@ namespace osu.Game.Skinning
return null;
}
public override Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT)
public override Texture? GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT)
{
foreach (string name in getFallbackNames(componentName))
{
@ -458,7 +461,7 @@ namespace osu.Game.Skinning
return null;
}
public override ISample GetSample(ISampleInfo sampleInfo)
public override ISample? GetSample(ISampleInfo sampleInfo)
{
IEnumerable<string> lookupNames;

View File

@ -46,7 +46,10 @@ namespace osu.Game.Skinning
return null;
}
public IBindable<TValue>? GetConfig<TLookup, TValue>(TLookup lookup) => null;
public IBindable<TValue>? GetConfig<TLookup, TValue>(TLookup lookup)
where TLookup : notnull
where TValue : notnull
=> null;
public void Dispose()
{

View File

@ -1,12 +1,14 @@
// 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.
#nullable enable
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using JetBrains.Annotations;
using Newtonsoft.Json;
using osu.Framework.Audio.Sample;
using osu.Framework.Bindables;
@ -27,14 +29,12 @@ namespace osu.Game.Skinning
/// <summary>
/// A texture store which can be used to perform user file lookups for this skin.
/// </summary>
[CanBeNull]
protected TextureStore Textures { get; }
protected TextureStore? Textures { get; }
/// <summary>
/// A sample store which can be used to perform user file lookups for this skin.
/// </summary>
[CanBeNull]
protected ISampleStore Samples { get; }
protected ISampleStore? Samples { get; }
public readonly Live<SkinInfo> SkinInfo;
@ -44,13 +44,15 @@ namespace osu.Game.Skinning
private readonly Dictionary<SkinnableTarget, SkinnableInfo[]> drawableComponentInfo = new Dictionary<SkinnableTarget, SkinnableInfo[]>();
public abstract ISample GetSample(ISampleInfo sampleInfo);
public abstract ISample? GetSample(ISampleInfo sampleInfo);
public Texture GetTexture(string componentName) => GetTexture(componentName, default, default);
public Texture? GetTexture(string componentName) => GetTexture(componentName, default, default);
public abstract Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT);
public abstract Texture? GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT);
public abstract IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup);
public abstract IBindable<TValue>? GetConfig<TLookup, TValue>(TLookup lookup)
where TLookup : notnull
where TValue : notnull;
/// <summary>
/// Construct a new skin.
@ -59,13 +61,11 @@ namespace osu.Game.Skinning
/// <param name="resources">Access to game-wide resources.</param>
/// <param name="storage">An optional store which will *replace* all file lookups that are usually sourced from <paramref name="skin"/>.</param>
/// <param name="configurationFilename">An optional filename to read the skin configuration from. If not provided, the configuration will be retrieved from the storage using "skin.ini".</param>
protected Skin(SkinInfo skin, [CanBeNull] IStorageResourceProvider resources, [CanBeNull] IResourceStore<byte[]> storage = null, [CanBeNull] string configurationFilename = @"skin.ini")
protected Skin(SkinInfo skin, IStorageResourceProvider? resources, IResourceStore<byte[]>? storage = null, string configurationFilename = @"skin.ini")
{
if (resources != null)
{
SkinInfo = resources.RealmAccess != null
? skin.ToLive(resources.RealmAccess)
: skin.ToLiveUnmanaged();
SkinInfo = skin.ToLive(resources.RealmAccess);
storage ??= new RealmBackedResourceStore(skin, resources.Files, new[] { @"ogg" });
@ -76,12 +76,20 @@ namespace osu.Game.Skinning
Samples = samples;
Textures = new TextureStore(resources.CreateTextureLoaderStore(storage));
}
else
{
// Generally only used for tests.
SkinInfo = skin.ToLiveUnmanaged();
}
var configurationStream = storage?.GetStream(configurationFilename);
if (configurationStream != null)
{
// stream will be closed after use by LineBufferedReader.
ParseConfigurationStream(configurationStream);
Debug.Assert(Configuration != null);
}
else
Configuration = new SkinConfiguration();
@ -90,7 +98,7 @@ namespace osu.Game.Skinning
{
string filename = $"{skinnableTarget}.json";
byte[] bytes = storage?.Get(filename);
byte[]? bytes = storage?.Get(filename);
if (bytes == null)
continue;
@ -136,7 +144,7 @@ namespace osu.Game.Skinning
DrawableComponentInfo[targetContainer.Target] = targetContainer.CreateSkinnableInfo().ToArray();
}
public virtual Drawable GetDrawableComponent(ISkinComponent component)
public virtual Drawable? GetDrawableComponent(ISkinComponent component)
{
switch (component)
{

View File

@ -96,7 +96,7 @@ namespace osu.Game.Tests.Visual
},
new OsuSpriteText
{
Text = skin?.SkinInfo?.Value.Name ?? "none",
Text = skin?.SkinInfo.Value.Name ?? "none",
Scale = new Vector2(1.5f),
Padding = new MarginPadding(5),
},