Skip to content

Commit

Permalink
Merge pull request #2254 from peppy/skin--completion
Browse files Browse the repository at this point in the history
Add skin/beatmap lookup hierarchy
  • Loading branch information
smoogipoo committed Mar 22, 2018
2 parents 242ee8f + 2d08cee commit 61ef635
Show file tree
Hide file tree
Showing 20 changed files with 228 additions and 34 deletions.
10 changes: 10 additions & 0 deletions osu.Game.Rulesets.Catch/Objects/Drawable/DrawableCatchHitObject.cs
Expand Up @@ -8,6 +8,8 @@
using osu.Game.Rulesets.Objects.Types;
using OpenTK;
using osu.Game.Rulesets.Scoring;
using osu.Game.Skinning;
using OpenTK.Graphics;

namespace osu.Game.Rulesets.Catch.Objects.Drawable
{
Expand Down Expand Up @@ -57,6 +59,14 @@ protected override void CheckForJudgements(bool userTriggered, double timeOffset
AddJudgement(new Judgement { Result = CheckPosition.Invoke(HitObject) ? HitResult.Perfect : HitResult.Miss });
}

protected override void SkinChanged(ISkinSource skin, bool allowFallback)
{
base.SkinChanged(skin, allowFallback);

if (HitObject is IHasComboInformation combo)
AccentColour = skin.GetValue<SkinConfiguration, Color4>(s => s.ComboColours.Count > 0 ? s.ComboColours[combo.ComboIndex % s.ComboColours.Count] : (Color4?)null) ?? Color4.White;
}

private const float preempt = 1000;

protected override void UpdateState(ArmedState state)
Expand Down
11 changes: 11 additions & 0 deletions osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs
Expand Up @@ -5,6 +5,9 @@
using osu.Game.Rulesets.Objects.Drawables;
using osu.Framework.Graphics;
using System.Linq;
using osu.Game.Rulesets.Objects.Types;
using osu.Game.Skinning;
using OpenTK.Graphics;

namespace osu.Game.Rulesets.Osu.Objects.Drawables
{
Expand Down Expand Up @@ -34,6 +37,14 @@ protected sealed override void UpdateState(ArmedState state)
}
}

protected override void SkinChanged(ISkinSource skin, bool allowFallback)
{
base.SkinChanged(skin, allowFallback);

if (HitObject is IHasComboInformation combo)
AccentColour = skin.GetValue<SkinConfiguration, Color4>(s => s.ComboColours.Count > 0 ? s.ComboColours[combo.ComboIndex % s.ComboColours.Count] : (Color4?)null) ?? Color4.White;
}

protected virtual void UpdatePreemptState() => this.FadeIn(HitObject.TimeFadein);

protected virtual void UpdateCurrentState(ArmedState state)
Expand Down
Expand Up @@ -25,7 +25,7 @@ public ExplodePiece()
Blending = BlendingMode.Additive,
RelativeSizeAxes = Axes.Both,
Alpha = 0.2f,
}, false);
}, s => s.GetTexture("Play/osu/hitcircle") == null);
}
}
}
Expand Up @@ -29,7 +29,7 @@ public FlashPiece()
{
RelativeSizeAxes = Axes.Both
}
}, false);
}, s => s.GetTexture("Play/osu/hitcircle") == null);
}
}
}
Expand Up @@ -29,7 +29,7 @@ private void load(TextureStore textures)
Texture = textures.Get(name),
Blending = BlendingMode.Additive,
Alpha = 0.5f
}, false);
}, s => s.GetTexture("Play/osu/hitcircle") == null);
}
}
}
Expand Up @@ -40,7 +40,7 @@ public NumberPiece()
Colour = Color4.White.Opacity(0.5f),
},
Child = new Box()
}, false),
}, s => s.GetTexture("Play/osu/hitcircle") == null),
number = new OsuSpriteText
{
Text = @"1",
Expand Down
1 change: 1 addition & 0 deletions osu.Game/OsuGameBase.cs
Expand Up @@ -105,6 +105,7 @@ private void load()
runMigrations();

dependencies.Cache(SkinManager = new SkinManager(Host.Storage, contextFactory, Host, Audio));
dependencies.CacheAs<ISkinSource>(SkinManager);

var api = new APIAccess(LocalConfig);

Expand Down
3 changes: 1 addition & 2 deletions osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs
Expand Up @@ -6,7 +6,6 @@
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Configuration;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Primitives;
using osu.Game.Audio;
using osu.Game.Graphics;
Expand All @@ -19,7 +18,7 @@

namespace osu.Game.Rulesets.Objects.Drawables
{
public abstract class DrawableHitObject : CompositeDrawable, IHasAccentColour
public abstract class DrawableHitObject : SkinReloadableDrawable, IHasAccentColour
{
public readonly HitObject HitObject;

Expand Down
26 changes: 26 additions & 0 deletions osu.Game/Rulesets/Objects/Types/IHasComboIndex.cs
@@ -0,0 +1,26 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE

namespace osu.Game.Rulesets.Objects.Types
{
/// <summary>
/// A HitObject that is part of a combo and has extended information about its position relative to other combo objects.
/// </summary>
public interface IHasComboIndex : IHasCombo
{
/// <summary>
/// The offset of this hitobject in the current combo.
/// </summary>
int IndexInCurrentCombo { get; set; }

/// <summary>
/// The offset of this hitobject in the current combo.
/// </summary>
int ComboIndex { get; set; }

/// <summary>
/// Whether this is the last object in the current combo.
/// </summary>
bool LastInCombo { get; set; }
}
}
7 changes: 6 additions & 1 deletion osu.Game/Screens/Play/Player.cs
Expand Up @@ -26,6 +26,7 @@
using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.UI;
using osu.Game.Screens.Ranking;
using osu.Game.Skinning;
using osu.Game.Storyboards.Drawables;

namespace osu.Game.Screens.Play
Expand Down Expand Up @@ -163,7 +164,11 @@ private void load(AudioManager audio, APIAccess api, OsuConfigManager config)
RelativeSizeAxes = Axes.Both,
Alpha = 0,
},
RulesetContainer,
new LocalSkinOverrideContainer(working.Skin)
{
RelativeSizeAxes = Axes.Both,
Child = RulesetContainer
},
new SkipOverlay(firstObjectTime)
{
Clock = Clock, // skip button doesn't want to use the audio clock directly
Expand Down
25 changes: 16 additions & 9 deletions osu.Game/Skinning/DefaultSkin.cs
Expand Up @@ -3,6 +3,8 @@

using osu.Framework.Audio.Sample;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Textures;
using OpenTK.Graphics;

namespace osu.Game.Skinning
{
Expand All @@ -11,17 +13,22 @@ public class DefaultSkin : Skin
public DefaultSkin()
: base(SkinInfo.Default)
{
Configuration = new SkinConfiguration();
Configuration = new SkinConfiguration
{
ComboColours =
{
new Color4(17, 136, 170, 255),
new Color4(102, 136, 0, 255),
new Color4(204, 102, 0, 255),
new Color4(121, 9, 13, 255)
}
};
}

public override Drawable GetDrawableComponent(string componentName)
{
return null;
}
public override Drawable GetDrawableComponent(string componentName) => null;

public override SampleChannel GetSample(string sampleName)
{
return null;
}
public override Texture GetTexture(string componentName) => null;

public override SampleChannel GetSample(string sampleName) => null;
}
}
28 changes: 28 additions & 0 deletions osu.Game/Skinning/ISkinSource.cs
@@ -0,0 +1,28 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE

using System;
using osu.Framework.Audio.Sample;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Textures;

namespace osu.Game.Skinning
{
/// <summary>
/// Provides access to skinnable elements.
/// </summary>
public interface ISkinSource
{
event Action SourceChanged;

Drawable GetDrawableComponent(string componentName);

Texture GetTexture(string componentName);

SampleChannel GetSample(string sampleName);

TValue GetValue<TConfiguration, TValue>(Func<TConfiguration, TValue> query) where TConfiguration : SkinConfiguration where TValue : class;

TValue? GetValue<TConfiguration, TValue>(Func<TConfiguration, TValue?> query) where TConfiguration : SkinConfiguration where TValue : struct;
}
}
4 changes: 3 additions & 1 deletion osu.Game/Skinning/LegacySkin.cs
Expand Up @@ -56,12 +56,14 @@ public override Drawable GetDrawableComponent(string componentName)
break;
}

var texture = Textures.Get(componentName);
var texture = GetTexture(componentName);
if (texture == null) return null;

return new Sprite { Texture = texture };
}

public override Texture GetTexture(string componentName) => Textures.Get(componentName);

public override SampleChannel GetSample(string sampleName) => Samples.Get(sampleName);

protected class LegacySkinResourceStore<T> : IResourceStore<byte[]>
Expand Down
72 changes: 72 additions & 0 deletions osu.Game/Skinning/LocalSkinOverrideContainer.cs
@@ -0,0 +1,72 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE

using System;
using osu.Framework.Allocation;
using osu.Framework.Audio.Sample;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Textures;

namespace osu.Game.Skinning
{
public class LocalSkinOverrideContainer : Container, ISkinSource
{
public event Action SourceChanged;

public Drawable GetDrawableComponent(string componentName) => source.GetDrawableComponent(componentName) ?? fallbackSource?.GetDrawableComponent(componentName);

public Texture GetTexture(string componentName) => source.GetTexture(componentName) ?? fallbackSource.GetTexture(componentName);

public SampleChannel GetSample(string sampleName) => source.GetSample(sampleName) ?? fallbackSource?.GetSample(sampleName);

public TValue? GetValue<TConfiguration, TValue>(Func<TConfiguration, TValue?> query) where TConfiguration : SkinConfiguration where TValue : struct
{
TValue? val = null;
var conf = (source as Skin)?.Configuration as TConfiguration;
if (conf != null)
val = query?.Invoke(conf);

return val ?? fallbackSource?.GetValue(query);
}

public TValue GetValue<TConfiguration, TValue>(Func<TConfiguration, TValue> query) where TConfiguration : SkinConfiguration where TValue : class
{
TValue val = null;
var conf = (source as Skin)?.Configuration as TConfiguration;
if (conf != null)
val = query?.Invoke(conf);

return val ?? fallbackSource?.GetValue(query);
}

private readonly ISkinSource source;
private ISkinSource fallbackSource;

public LocalSkinOverrideContainer(ISkinSource source)
{
this.source = source;
}

protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent)
{
var dependencies = new DependencyContainer(base.CreateLocalDependencies(parent));

fallbackSource = dependencies.Get<ISkinSource>();
if (fallbackSource != null)
fallbackSource.SourceChanged += () => SourceChanged?.Invoke();

dependencies.CacheAs<ISkinSource>(this);

return dependencies;
}

protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);

if (fallbackSource != null)
fallbackSource.SourceChanged -= SourceChanged;
}
}
}
13 changes: 12 additions & 1 deletion osu.Game/Skinning/Skin.cs
Expand Up @@ -4,19 +4,30 @@
using System;
using osu.Framework.Audio.Sample;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Textures;

namespace osu.Game.Skinning
{
public abstract class Skin : IDisposable
public abstract class Skin : IDisposable, ISkinSource
{
public readonly SkinInfo SkinInfo;

public virtual SkinConfiguration Configuration { get; protected set; }

public event Action SourceChanged;

public abstract Drawable GetDrawableComponent(string componentName);

public abstract SampleChannel GetSample(string sampleName);

public abstract Texture GetTexture(string componentName);

public TValue GetValue<TConfiguration, TValue>(Func<TConfiguration, TValue> query) where TConfiguration : SkinConfiguration where TValue : class
=> Configuration is TConfiguration conf ? query?.Invoke(conf) : null;

public TValue? GetValue<TConfiguration, TValue>(Func<TConfiguration, TValue?> query) where TConfiguration : SkinConfiguration where TValue : struct
=> Configuration is TConfiguration conf ? query?.Invoke(conf) : null;

protected Skin(SkinInfo skin)
{
SkinInfo = skin;
Expand Down
19 changes: 18 additions & 1 deletion osu.Game/Skinning/SkinManager.cs
Expand Up @@ -7,14 +7,17 @@
using System.Linq.Expressions;
using Microsoft.EntityFrameworkCore;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
using osu.Framework.Configuration;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Textures;
using osu.Framework.Platform;
using osu.Game.Database;
using osu.Game.IO.Archives;

namespace osu.Game.Skinning
{
public class SkinManager : ArchiveModelManager<SkinInfo, SkinFileInfo>
public class SkinManager : ArchiveModelManager<SkinInfo, SkinFileInfo>, ISkinSource
{
private readonly AudioManager audio;

Expand Down Expand Up @@ -89,6 +92,8 @@ public SkinManager(Storage storage, DatabaseContextFactory contextFactory, IIpcH
{
if (skin.SkinInfo != CurrentSkinInfo.Value)
throw new InvalidOperationException($"Setting {nameof(CurrentSkin)}'s value directly is not supported. Use {nameof(CurrentSkinInfo)} instead.");
SourceChanged?.Invoke();
};

// migrate older imports which didn't have access to skin.ini
Expand All @@ -108,5 +113,17 @@ public SkinManager(Storage storage, DatabaseContextFactory contextFactory, IIpcH
/// <param name="query">The query.</param>
/// <returns>The first result for the provided query, or null if no results were found.</returns>
public SkinInfo Query(Expression<Func<SkinInfo, bool>> query) => ModelStore.ConsumableItems.AsNoTracking().FirstOrDefault(query);

public event Action SourceChanged;

public Drawable GetDrawableComponent(string componentName) => CurrentSkin.Value.GetDrawableComponent(componentName);

public Texture GetTexture(string componentName) => CurrentSkin.Value.GetTexture(componentName);

public SampleChannel GetSample(string sampleName) => CurrentSkin.Value.GetSample(sampleName);

public TValue GetValue<TConfiguration, TValue>(Func<TConfiguration, TValue> query) where TConfiguration : SkinConfiguration where TValue : class => CurrentSkin.Value.GetValue(query);

public TValue? GetValue<TConfiguration, TValue>(Func<TConfiguration, TValue?> query) where TConfiguration : SkinConfiguration where TValue : struct => CurrentSkin.Value.GetValue(query);
}
}

0 comments on commit 61ef635

Please sign in to comment.