diff --git a/osu-framework b/osu-framework index 41e2a0a430..241133f0a6 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 41e2a0a4304544fb67779c21cad1435c105982d5 +Subproject commit 241133f0a65326a563ba23b7166167a882d1d5cb diff --git a/osu.Desktop/osu.nuspec b/osu.Desktop/osu.nuspec index bb7d382cee..316a5443ef 100644 --- a/osu.Desktop/osu.nuspec +++ b/osu.Desktop/osu.nuspec @@ -16,11 +16,9 @@ en-AU - - - - - + + + diff --git a/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs b/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs index a6ab18bbf7..1a0ccc9b1e 100644 --- a/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs +++ b/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs @@ -8,7 +8,7 @@ using osu.Game.Rulesets.Objects.Types; namespace osu.Game.Rulesets.Catch.Objects { - public abstract class CatchHitObject : HitObject, IHasXPosition, IHasComboIndex + public abstract class CatchHitObject : HitObject, IHasXPosition, IHasComboInformation { public const double OBJECT_RADIUS = 44; diff --git a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableCatchHitObject.cs b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableCatchHitObject.cs index 8d56fc1081..582946ff00 100644 --- a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableCatchHitObject.cs +++ b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableCatchHitObject.cs @@ -8,6 +8,8 @@ using osu.Game.Rulesets.Objects.Drawables; 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 { @@ -57,6 +59,14 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable 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(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) diff --git a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs index 1e4051c5aa..29ad3c3956 100644 --- a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs +++ b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs @@ -64,52 +64,57 @@ namespace osu.Game.Rulesets.Catch.Objects X = X }); - for (var span = 0; span < this.SpanCount(); span++) + double lastDropletTime = StartTime; + + for (int span = 0; span < this.SpanCount(); span++) { var spanStartTime = StartTime + span * spanDuration; var reversed = span % 2 == 1; - for (var d = tickDistance; d <= length; d += tickDistance) + for (double d = 0; d <= length; d += tickDistance) { - if (d > length - minDistanceFromEnd) - break; - var timeProgress = d / length; var distanceProgress = reversed ? 1 - timeProgress : timeProgress; - var lastTickTime = spanStartTime + timeProgress * spanDuration; - AddNested(new Droplet + double time = spanStartTime + timeProgress * spanDuration; + + double tinyTickInterval = time - lastDropletTime; + while (tinyTickInterval > 100) + tinyTickInterval /= 2; + + for (double t = lastDropletTime + tinyTickInterval; t < time; t += tinyTickInterval) { - StartTime = lastTickTime, - X = X + Curve.PositionAt(distanceProgress).X / CatchPlayfield.BASE_WIDTH, - Samples = new List(Samples.Select(s => new SampleInfo + double progress = reversed ? 1 - (t - spanStartTime) / spanDuration : (t - spanStartTime) / spanDuration; + + AddNested(new TinyDroplet { - Bank = s.Bank, - Name = @"slidertick", - Volume = s.Volume - })) - }); - } + StartTime = t, + X = X + Curve.PositionAt(progress).X / CatchPlayfield.BASE_WIDTH, + Samples = new List(Samples.Select(s => new SampleInfo + { + Bank = s.Bank, + Name = @"slidertick", + Volume = s.Volume + })) + }); + } - double tinyTickInterval = tickDistance / length * spanDuration; - while (tinyTickInterval > 100) - tinyTickInterval /= 2; - - for (double t = 0; t < spanDuration; t += tinyTickInterval) - { - double progress = reversed ? 1 - t / spanDuration : t / spanDuration; - - AddNested(new TinyDroplet + if (d > minDistanceFromEnd && Math.Abs(d - length) > minDistanceFromEnd) { - StartTime = spanStartTime + t, - X = X + Curve.PositionAt(progress).X / CatchPlayfield.BASE_WIDTH, - Samples = new List(Samples.Select(s => new SampleInfo + AddNested(new Droplet { - Bank = s.Bank, - Name = @"slidertick", - Volume = s.Volume - })) - }); + StartTime = time, + X = X + Curve.PositionAt(distanceProgress).X / CatchPlayfield.BASE_WIDTH, + Samples = new List(Samples.Select(s => new SampleInfo + { + Bank = s.Bank, + Name = @"slidertick", + Volume = s.Volume + })) + }); + } + + lastDropletTime = time; } AddNested(new Fruit diff --git a/osu.Game.Rulesets.Catch/Tests/CatchBeatmapConversionTest.cs b/osu.Game.Rulesets.Catch/Tests/CatchBeatmapConversionTest.cs index 826c900140..e40510b71b 100644 --- a/osu.Game.Rulesets.Catch/Tests/CatchBeatmapConversionTest.cs +++ b/osu.Game.Rulesets.Catch/Tests/CatchBeatmapConversionTest.cs @@ -18,7 +18,7 @@ namespace osu.Game.Rulesets.Catch.Tests { protected override string ResourceAssembly => "osu.Game.Rulesets.Catch"; - [TestCase("basic"), Ignore("See: https://github.com/ppy/osu/issues/2149")] + [TestCase("basic"), Ignore("See: https://github.com/ppy/osu/issues/2232")] public new void Test(string name) { base.Test(name); diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs index 2e59e2dc60..d4d89c2aa3 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs @@ -5,6 +5,9 @@ using System.ComponentModel; 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 { @@ -34,6 +37,14 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables } } + protected override void SkinChanged(ISkinSource skin, bool allowFallback) + { + base.SkinChanged(skin, allowFallback); + + if (HitObject is IHasComboInformation combo) + AccentColour = skin.GetValue(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) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBody.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBody.cs index 26186a0049..c59c22c771 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBody.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBody.cs @@ -42,7 +42,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces public double? SnakedStart { get; private set; } public double? SnakedEnd { get; private set; } - private Color4 accentColour; + private Color4 accentColour = Color4.White; /// /// Used to colour the path. /// diff --git a/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs b/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs index 5d1908fa6e..c00c30ced9 100644 --- a/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs +++ b/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs @@ -10,7 +10,7 @@ using osu.Game.Beatmaps.ControlPoints; namespace osu.Game.Rulesets.Osu.Objects { - public abstract class OsuHitObject : HitObject, IHasComboIndex, IHasPosition + public abstract class OsuHitObject : HitObject, IHasComboInformation, IHasPosition { public const double OBJECT_RADIUS = 64; diff --git a/osu.Game/Beatmaps/BeatmapManager_WorkingBeatmap.cs b/osu.Game/Beatmaps/BeatmapManager_WorkingBeatmap.cs index 58b51085a4..5874314f75 100644 --- a/osu.Game/Beatmaps/BeatmapManager_WorkingBeatmap.cs +++ b/osu.Game/Beatmaps/BeatmapManager_WorkingBeatmap.cs @@ -110,7 +110,7 @@ namespace osu.Game.Beatmaps Skin skin; try { - skin = new BeatmapSkin(BeatmapInfo, store, audioManager); + skin = new LegacyBeatmapSkin(BeatmapInfo, store, audioManager); } catch (Exception e) { diff --git a/osu.Game/Beatmaps/BeatmapProcessor.cs b/osu.Game/Beatmaps/BeatmapProcessor.cs index 83b2867df7..f2cc419043 100644 --- a/osu.Game/Beatmaps/BeatmapProcessor.cs +++ b/osu.Game/Beatmaps/BeatmapProcessor.cs @@ -23,9 +23,9 @@ namespace osu.Game.Beatmaps /// The Beatmap to process. public virtual void PostProcess(Beatmap beatmap) { - IHasComboIndex lastObj = null; + IHasComboInformation lastObj = null; - foreach (var obj in beatmap.HitObjects.OfType()) + foreach (var obj in beatmap.HitObjects.OfType()) { if (obj.NewCombo) { diff --git a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs index 67d497ba83..131c010c5c 100644 --- a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.IO; +using osu.Framework.Logging; using OpenTK.Graphics; namespace osu.Game.Beatmaps.Formats @@ -31,7 +32,11 @@ namespace osu.Game.Beatmaps.Formats if (line.StartsWith(@"[") && line.EndsWith(@"]")) { if (!Enum.TryParse(line.Substring(1, line.Length - 2), out section)) - throw new InvalidDataException($@"Unknown osu section {line}"); + { + Logger.Log($"Unknown section \"{line}\" in {beatmap}"); + section = Section.None; + } + continue; } diff --git a/osu.Game/Database/ArchiveModelManager.cs b/osu.Game/Database/ArchiveModelManager.cs index a65593ff82..f0e67a7185 100644 --- a/osu.Game/Database/ArchiveModelManager.cs +++ b/osu.Game/Database/ArchiveModelManager.cs @@ -13,6 +13,7 @@ using osu.Game.IO; using osu.Game.IO.Archives; using osu.Game.IPC; using osu.Game.Overlays.Notifications; +using SharpCompress.Common; using FileInfo = osu.Game.IO.FileInfo; namespace osu.Game.Database @@ -79,7 +80,6 @@ namespace osu.Game.Database var notification = new ProgressNotification { Text = "Import is initialising...", - CompletionText = "Import successful!", Progress = 0, State = ProgressNotificationState.Active, }; @@ -88,7 +88,8 @@ namespace osu.Game.Database List imported = new List(); - int i = 0; + int current = 0; + int errors = 0; foreach (string path in paths) { if (notification.State == ProgressNotificationState.Cancelled) @@ -97,11 +98,11 @@ namespace osu.Game.Database try { - notification.Text = $"Importing ({i} of {paths.Length})\n{Path.GetFileName(path)}"; + notification.Text = $"Importing ({++current} of {paths.Length})\n{Path.GetFileName(path)}"; using (ArchiveReader reader = getReaderFrom(path)) imported.Add(Import(reader)); - notification.Progress = (float)++i / paths.Length; + notification.Progress = (float)current / paths.Length; // We may or may not want to delete the file depending on where it is stored. // e.g. reconstructing/repairing database with items from default storage. @@ -121,9 +122,11 @@ namespace osu.Game.Database { e = e.InnerException ?? e; Logger.Error(e, $@"Could not import ({Path.GetFileName(path)})"); + errors++; } } + notification.Text = errors > 0 ? $"Import complete with {errors} errors" : "Import successful!"; notification.State = ProgressNotificationState.Completed; } @@ -218,9 +221,11 @@ namespace osu.Game.Database // user requested abort return; - notification.Text = $"Deleting ({i} of {items.Count})"; - notification.Progress = (float)++i / items.Count; + notification.Text = $"Deleting ({++i} of {items.Count})"; + Delete(b); + + notification.Progress = (float)i / items.Count; } } @@ -254,9 +259,11 @@ namespace osu.Game.Database // user requested abort return; - notification.Text = $"Restoring ({i} of {items.Count})"; - notification.Progress = (float)++i / items.Count; + notification.Text = $"Restoring ({++i} of {items.Count})"; + Undelete(item); + + notification.Progress = (float)i / items.Count; } } @@ -331,7 +338,9 @@ namespace osu.Game.Database { if (ZipFile.IsZipFile(path)) return new ZipArchiveReader(Files.Storage.GetStream(path), Path.GetFileName(path)); - return new LegacyFilesystemReader(path); + if (Directory.Exists(path)) + return new LegacyFilesystemReader(path); + throw new InvalidFormatException($"{path} is not a valid archive"); } } } diff --git a/osu.Game/Graphics/Backgrounds/Triangles.cs b/osu.Game/Graphics/Backgrounds/Triangles.cs index 6f9d83473f..89ed8044e6 100644 --- a/osu.Game/Graphics/Backgrounds/Triangles.cs +++ b/osu.Game/Graphics/Backgrounds/Triangles.cs @@ -242,7 +242,7 @@ namespace osu.Game.Graphics.Backgrounds triangle, colourInfo, null, - Shared.VertexBatch.Add, + Shared.VertexBatch.AddAction, Vector2.Divide(localInflationAmount, size)); } diff --git a/osu.Game/Graphics/UserInterface/FocusedTextBox.cs b/osu.Game/Graphics/UserInterface/FocusedTextBox.cs index 6d9bf231c3..33786252ab 100644 --- a/osu.Game/Graphics/UserInterface/FocusedTextBox.cs +++ b/osu.Game/Graphics/UserInterface/FocusedTextBox.cs @@ -30,6 +30,9 @@ namespace osu.Game.Graphics.UserInterface } } + // We may not be focused yet, but we need to handle keyboard input to be able to request focus + public override bool HandleKeyboardInput => HoldFocus || base.HandleKeyboardInput; + protected override void OnFocus(InputState state) { base.OnFocus(state); diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index 945cd928d4..348364a2bf 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -102,14 +102,6 @@ namespace osu.Game.Rulesets.Objects.Drawables } } - protected override void SkinChanged(ISkinSource skin, bool allowFallback) - { - base.SkinChanged(skin, allowFallback); - - if (HitObject is IHasComboIndex combo) - AccentColour = skin.GetComboColour(combo) ?? Color4.White; - } - protected override void LoadComplete() { base.LoadComplete(); diff --git a/osu.Game/Rulesets/Objects/Types/IHasComboInformation.cs b/osu.Game/Rulesets/Objects/Types/IHasComboInformation.cs new file mode 100644 index 0000000000..1d4f4e0f90 --- /dev/null +++ b/osu.Game/Rulesets/Objects/Types/IHasComboInformation.cs @@ -0,0 +1,26 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +namespace osu.Game.Rulesets.Objects.Types +{ + /// + /// A HitObject that is part of a combo and has extended information about its position relative to other combo objects. + /// + public interface IHasComboInformation : IHasCombo + { + /// + /// The offset of this hitobject in the current combo. + /// + int IndexInCurrentCombo { get; set; } + + /// + /// The offset of this combo in relation to the beatmap. + /// + int ComboIndex { get; set; } + + /// + /// Whether this is the last object in the current combo. + /// + bool LastInCombo { get; set; } + } +} diff --git a/osu.Game/Screens/Menu/LogoVisualisation.cs b/osu.Game/Screens/Menu/LogoVisualisation.cs index 3a3f3d4650..fc747acbb4 100644 --- a/osu.Game/Screens/Menu/LogoVisualisation.cs +++ b/osu.Game/Screens/Menu/LogoVisualisation.cs @@ -211,7 +211,7 @@ namespace osu.Game.Screens.Menu rectangle, colourInfo, null, - Shared.VertexBatch.Add, + Shared.VertexBatch.AddAction, //barSize by itself will make it smooth more in the X axis than in the Y axis, this reverts that. Vector2.Divide(inflation, barSize.Yx)); } diff --git a/osu.Game/Screens/Menu/OsuLogo.cs b/osu.Game/Screens/Menu/OsuLogo.cs index 3fcb885655..b7d2ed2e1f 100644 --- a/osu.Game/Screens/Menu/OsuLogo.cs +++ b/osu.Game/Screens/Menu/OsuLogo.cs @@ -337,12 +337,10 @@ namespace osu.Game.Screens.Menu } } - private bool interactive => Action != null && Alpha > 0.2f; + public override bool HandleMouseInput => base.HandleMouseInput && Action != null && Alpha > 0.2f; protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) { - if (!interactive) return false; - logoBounceContainer.ScaleTo(0.9f, 1000, Easing.Out); return true; } @@ -355,8 +353,6 @@ namespace osu.Game.Screens.Menu protected override bool OnClick(InputState state) { - if (!interactive) return false; - if (Action?.Invoke() ?? true) sampleClick.Play(); @@ -368,8 +364,6 @@ namespace osu.Game.Screens.Menu protected override bool OnHover(InputState state) { - if (!interactive) return false; - logoHoverContainer.ScaleTo(1.1f, 500, Easing.OutElastic); return true; } diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index ca8a1cae41..f01616ade2 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -259,6 +259,8 @@ namespace osu.Game.Screens.Select private void workingBeatmapChanged(WorkingBeatmap beatmap) { + if (beatmap is DummyWorkingBeatmap) return; + if (IsCurrentScreen && !Carousel.SelectBeatmap(beatmap?.BeatmapInfo, false)) // If selecting new beatmap without bypassing filters failed, there's possibly a ruleset mismatch if (beatmap?.BeatmapInfo?.Ruleset != null && beatmap.BeatmapInfo.Ruleset != Ruleset.Value) diff --git a/osu.Game/Skinning/BeatmapSkin.cs b/osu.Game/Skinning/BeatmapSkin.cs deleted file mode 100644 index 815aac2f64..0000000000 --- a/osu.Game/Skinning/BeatmapSkin.cs +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) 2007-2018 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using System.IO; -using osu.Framework.Audio; -using osu.Framework.Graphics.Textures; -using osu.Framework.IO.Stores; -using osu.Game.Beatmaps; - -namespace osu.Game.Skinning -{ - public class BeatmapSkin : LegacySkin - { - public BeatmapSkin(BeatmapInfo beatmap, IResourceStore storage, AudioManager audioManager) - : base(new SkinInfo { Name = beatmap.ToString(), Creator = beatmap.Metadata.Author.ToString() }) - { - storage = new LegacySkinResourceStore(beatmap.BeatmapSet, storage); - - Samples = audioManager.GetSampleManager(storage); - - Textures = new TextureStore(new RawTextureLoaderStore(storage)); - - var decoder = new LegacySkinDecoder(); - - using (StreamReader reader = new StreamReader(storage.GetStream(beatmap.Path))) - { - Configuration = decoder.Decode(reader); - } - } - } -} diff --git a/osu.Game/Skinning/ISkinSource.cs b/osu.Game/Skinning/ISkinSource.cs index 924fdbd8c1..d8f259b4ea 100644 --- a/osu.Game/Skinning/ISkinSource.cs +++ b/osu.Game/Skinning/ISkinSource.cs @@ -5,8 +5,6 @@ using System; using osu.Framework.Audio.Sample; using osu.Framework.Graphics; using osu.Framework.Graphics.Textures; -using osu.Game.Rulesets.Objects.Types; -using OpenTK.Graphics; namespace osu.Game.Skinning { @@ -23,6 +21,8 @@ namespace osu.Game.Skinning SampleChannel GetSample(string sampleName); - Color4? GetComboColour(IHasComboIndex comboObject); + TValue GetValue(Func query) where TConfiguration : SkinConfiguration where TValue : class; + + TValue? GetValue(Func query) where TConfiguration : SkinConfiguration where TValue : struct; } } diff --git a/osu.Game/Skinning/LegacyBeatmapSkin.cs b/osu.Game/Skinning/LegacyBeatmapSkin.cs new file mode 100644 index 0000000000..01beb8db32 --- /dev/null +++ b/osu.Game/Skinning/LegacyBeatmapSkin.cs @@ -0,0 +1,20 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Audio; +using osu.Framework.IO.Stores; +using osu.Game.Beatmaps; + +namespace osu.Game.Skinning +{ + public class LegacyBeatmapSkin : LegacySkin + { + public LegacyBeatmapSkin(BeatmapInfo beatmap, IResourceStore storage, AudioManager audioManager) + : base(createSkinInfo(beatmap), new LegacySkinResourceStore(beatmap.BeatmapSet, storage), audioManager, beatmap.Path) + { + } + + private static SkinInfo createSkinInfo(BeatmapInfo beatmap) => + new SkinInfo { Name = beatmap.ToString(), Creator = beatmap.Metadata.Author.ToString() }; + } +} diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs index a361fa2b8a..66e8cb8f9f 100644 --- a/osu.Game/Skinning/LegacySkin.cs +++ b/osu.Game/Skinning/LegacySkin.cs @@ -22,23 +22,21 @@ namespace osu.Game.Skinning protected SampleManager Samples; public LegacySkin(SkinInfo skin, IResourceStore storage, AudioManager audioManager) - : this(skin) + : this(skin, new LegacySkinResourceStore(skin, storage), audioManager, "skin.ini") { - storage = new LegacySkinResourceStore(skin, storage); - Samples = audioManager.GetSampleManager(storage); - Textures = new TextureStore(new RawTextureLoaderStore(storage)); + } - Stream stream = storage.GetStream("skin.ini"); + protected LegacySkin(SkinInfo skin, IResourceStore storage, AudioManager audioManager, string filename) : base(skin) + { + Stream stream = storage.GetStream(filename); if (stream != null) using (StreamReader reader = new StreamReader(stream)) Configuration = new LegacySkinDecoder().Decode(reader); else Configuration = new SkinConfiguration(); - } - protected LegacySkin(SkinInfo skin) - : base(skin) - { + Samples = audioManager.GetSampleManager(storage); + Textures = new TextureStore(new RawTextureLoaderStore(storage)); } public override Drawable GetDrawableComponent(string componentName) diff --git a/osu.Game/Skinning/LegacySkinDecoder.cs b/osu.Game/Skinning/LegacySkinDecoder.cs index 9a881f9241..853abceddf 100644 --- a/osu.Game/Skinning/LegacySkinDecoder.cs +++ b/osu.Game/Skinning/LegacySkinDecoder.cs @@ -29,7 +29,7 @@ namespace osu.Game.Skinning break; } - return; + break; } base.ParseLine(output, section, line); diff --git a/osu.Game/Skinning/LocalSkinOverrideContainer.cs b/osu.Game/Skinning/LocalSkinOverrideContainer.cs index a0cc11a324..b7e2bd0daf 100644 --- a/osu.Game/Skinning/LocalSkinOverrideContainer.cs +++ b/osu.Game/Skinning/LocalSkinOverrideContainer.cs @@ -7,8 +7,6 @@ using osu.Framework.Audio.Sample; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Textures; -using osu.Game.Rulesets.Objects.Types; -using OpenTK.Graphics; namespace osu.Game.Skinning { @@ -22,7 +20,25 @@ namespace osu.Game.Skinning public SampleChannel GetSample(string sampleName) => source.GetSample(sampleName) ?? fallbackSource?.GetSample(sampleName); - public Color4? GetComboColour(IHasComboIndex comboObject) => source.GetComboColour(comboObject) ?? fallbackSource?.GetComboColour(comboObject); + public TValue? GetValue(Func 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(Func 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; diff --git a/osu.Game/Skinning/Skin.cs b/osu.Game/Skinning/Skin.cs index 5d2c640244..02fb84a4a2 100644 --- a/osu.Game/Skinning/Skin.cs +++ b/osu.Game/Skinning/Skin.cs @@ -5,8 +5,6 @@ using System; using osu.Framework.Audio.Sample; using osu.Framework.Graphics; using osu.Framework.Graphics.Textures; -using osu.Game.Rulesets.Objects.Types; -using OpenTK.Graphics; namespace osu.Game.Skinning { @@ -24,8 +22,11 @@ namespace osu.Game.Skinning public abstract Texture GetTexture(string componentName); - public virtual Color4? GetComboColour(IHasComboIndex comboObject) => - Configuration.ComboColours.Count == 0 ? (Color4?)null : Configuration.ComboColours[comboObject.ComboIndex % Configuration.ComboColours.Count]; + public TValue GetValue(Func query) where TConfiguration : SkinConfiguration where TValue : class + => Configuration is TConfiguration conf ? query?.Invoke(conf) : null; + + public TValue? GetValue(Func query) where TConfiguration : SkinConfiguration where TValue : struct + => Configuration is TConfiguration conf ? query?.Invoke(conf) : null; protected Skin(SkinInfo skin) { diff --git a/osu.Game/Skinning/SkinManager.cs b/osu.Game/Skinning/SkinManager.cs index 9ae6eef49f..f965a77cce 100644 --- a/osu.Game/Skinning/SkinManager.cs +++ b/osu.Game/Skinning/SkinManager.cs @@ -14,8 +14,6 @@ using osu.Framework.Graphics.Textures; using osu.Framework.Platform; using osu.Game.Database; using osu.Game.IO.Archives; -using osu.Game.Rulesets.Objects.Types; -using OpenTK.Graphics; namespace osu.Game.Skinning { @@ -120,10 +118,12 @@ namespace osu.Game.Skinning public Drawable GetDrawableComponent(string componentName) => CurrentSkin.Value.GetDrawableComponent(componentName); - public Texture GetTexture(string componentName)=> CurrentSkin.Value.GetTexture(componentName); + public Texture GetTexture(string componentName) => CurrentSkin.Value.GetTexture(componentName); public SampleChannel GetSample(string sampleName) => CurrentSkin.Value.GetSample(sampleName); - public Color4? GetComboColour(IHasComboIndex comboObject) => CurrentSkin.Value.GetComboColour(comboObject); + public TValue GetValue(Func query) where TConfiguration : SkinConfiguration where TValue : class => CurrentSkin.Value.GetValue(query); + + public TValue? GetValue(Func query) where TConfiguration : SkinConfiguration where TValue : struct => CurrentSkin.Value.GetValue(query); } } diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 1c902a158f..6460de179d 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -374,7 +374,7 @@ - + @@ -872,7 +872,7 @@ - +