diff --git a/osu-framework b/osu-framework index 61e676094d..0773d895d9 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 61e676094d25436bb9e8858946f65c43d15d8e01 +Subproject commit 0773d895d9aa0729995cd4a23efc28238e35ceed diff --git a/osu.Game.Tests/Visual/TestCaseBeatmapInfoWedge.cs b/osu.Game.Tests/Visual/TestCaseBeatmapInfoWedge.cs index 51a8bacd2e..886c1120d4 100644 --- a/osu.Game.Tests/Visual/TestCaseBeatmapInfoWedge.cs +++ b/osu.Game.Tests/Visual/TestCaseBeatmapInfoWedge.cs @@ -52,6 +52,9 @@ namespace osu.Game.Tests.Visual infoWedge.UpdateBeatmap(beatmap); }); + // select part is redundant, but wait for load isn't + selectBeatmap(beatmap.Value.Beatmap); + AddWaitStep(3); AddStep("hide", () => { infoWedge.State = Visibility.Hidden; }); @@ -63,10 +66,11 @@ namespace osu.Game.Tests.Visual foreach (var rulesetInfo in rulesets.AvailableRulesets) { var ruleset = rulesetInfo.CreateInstance(); - beatmaps.Add(createTestBeatmap(rulesetInfo)); + var testBeatmap = createTestBeatmap(rulesetInfo); - var name = rulesetInfo.ShortName; - selectBeatmap(name); + beatmaps.Add(testBeatmap); + + selectBeatmap(testBeatmap); // TODO: adjust cases once more info is shown for other gamemodes switch (ruleset) @@ -108,16 +112,14 @@ namespace osu.Game.Tests.Visual AddAssert("check no infolabels", () => !infoWedge.Info.InfoLabelContainer.Children.Any()); } - private void selectBeatmap(string name) + private void selectBeatmap(Beatmap b) { BeatmapInfoWedge.BufferedWedgeInfo infoBefore = null; - AddStep($"select {name} beatmap", () => + AddStep($"select {b.Metadata.Title} beatmap", () => { infoBefore = infoWedge.Info; - WorkingBeatmap bm = new TestWorkingBeatmap(beatmaps.First(b => b.BeatmapInfo.Ruleset.ShortName == name)); - beatmap.Value = bm; - infoWedge.UpdateBeatmap(beatmap); + infoWedge.UpdateBeatmap(beatmap.Value = new TestWorkingBeatmap(b)); }); AddUntilStep(() => infoWedge.Info != infoBefore, "wait for async load"); diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs index 366b4f163f..655355913c 100644 --- a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs @@ -373,17 +373,18 @@ namespace osu.Game.Beatmaps.Formats if (parser == null) parser = new Rulesets.Objects.Legacy.Osu.ConvertHitObjectParser(); - var obj = parser.Parse(line); + var obj = parser.Parse(line, getOffsetTime()); if (obj != null) { - obj.StartTime = getOffsetTime(obj.StartTime); beatmap.HitObjects.Add(obj); } } private int getOffsetTime(int time) => time + (ApplyOffsets ? offset : 0); + private double getOffsetTime() => ApplyOffsets ? offset : 0; + private double getOffsetTime(double time) => time + (ApplyOffsets ? offset : 0); } } diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index 3efaa02a31..509622c2fe 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -60,6 +60,9 @@ namespace osu.Game.Configuration Set(OsuSetting.ShowFpsDisplay, false); Set(OsuSetting.ShowStoryboard, true); + Set(OsuSetting.BeatmapSkins, true); + Set(OsuSetting.BeatmapHitsounds, true); + Set(OsuSetting.CursorRotation, true); Set(OsuSetting.MenuParallax, true); @@ -133,6 +136,8 @@ namespace osu.Game.Configuration Skin, ScreenshotFormat, ScreenshotCaptureMenuCursor, - SongSelectRightMouseScroll + SongSelectRightMouseScroll, + BeatmapSkins, + BeatmapHitsounds } } diff --git a/osu.Game/Overlays/Chat/ChatTabControl.cs b/osu.Game/Overlays/Chat/ChatTabControl.cs index 77a30e6389..91b790ece4 100644 --- a/osu.Game/Overlays/Chat/ChatTabControl.cs +++ b/osu.Game/Overlays/Chat/ChatTabControl.cs @@ -307,6 +307,8 @@ namespace osu.Game.Overlays.Chat { public override bool IsRemovable => false; + public override bool IsSwitchable => false; + public ChannelSelectorTabItem(Channel value) : base(value) { Depth = float.MaxValue; diff --git a/osu.Game/Overlays/UserProfileOverlay.cs b/osu.Game/Overlays/UserProfileOverlay.cs index a4dd0c9ec3..d8f858b95e 100644 --- a/osu.Game/Overlays/UserProfileOverlay.cs +++ b/osu.Game/Overlays/UserProfileOverlay.cs @@ -71,6 +71,7 @@ namespace osu.Game.Overlays { base.PopOut(); FadeEdgeEffectTo(0, WaveContainer.DISAPPEAR_DURATION, Easing.Out); + cleanup(); } public void ShowUser(long userId) @@ -83,9 +84,7 @@ namespace osu.Game.Overlays public void ShowUser(User user, bool fetchOnline = true) { - userReq?.Cancel(); - Clear(); - lastSection = null; + cleanup(); sections = new ProfileSection[] { @@ -165,6 +164,13 @@ namespace osu.Game.Overlays sectionsContainer.ScrollToTop(); } + private void cleanup() + { + userReq?.Cancel(); + Clear(); + lastSection = null; + } + private void userLoadComplete(User user) { Header.User = user; diff --git a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs index 95abc4edb3..9edd0f1f34 100644 --- a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs @@ -19,6 +19,11 @@ namespace osu.Game.Rulesets.Objects.Legacy public abstract class ConvertHitObjectParser : HitObjectParser { public override HitObject Parse(string text) + { + return Parse(text, 0); + } + + public HitObject Parse(string text, double offset) { try { @@ -146,7 +151,7 @@ namespace osu.Game.Rulesets.Objects.Legacy } else if ((type & ConvertHitObjectType.Spinner) > 0) { - result = CreateSpinner(new Vector2(512, 384) / 2, Convert.ToDouble(split[5], CultureInfo.InvariantCulture)); + result = CreateSpinner(new Vector2(512, 384) / 2, Convert.ToDouble(split[5], CultureInfo.InvariantCulture) + offset); if (split.Length > 6) readCustomSampleBanks(split[6], bankInfo); @@ -164,13 +169,13 @@ namespace osu.Game.Rulesets.Objects.Legacy readCustomSampleBanks(string.Join(":", ss.Skip(1)), bankInfo); } - result = CreateHold(new Vector2(int.Parse(split[0]), int.Parse(split[1])), combo, endTime); + result = CreateHold(new Vector2(int.Parse(split[0]), int.Parse(split[1])), combo, endTime + offset); } if (result == null) throw new InvalidOperationException($@"Unknown hit object type {type}."); - result.StartTime = Convert.ToDouble(split[2], CultureInfo.InvariantCulture); + result.StartTime = Convert.ToDouble(split[2], CultureInfo.InvariantCulture) + offset; result.Samples = convertSoundType(soundType, bankInfo); return result; diff --git a/osu.Game/Screens/Play/PlayerSettings/VisualSettings.cs b/osu.Game/Screens/Play/PlayerSettings/VisualSettings.cs index 92d069a224..439e344020 100644 --- a/osu.Game/Screens/Play/PlayerSettings/VisualSettings.cs +++ b/osu.Game/Screens/Play/PlayerSettings/VisualSettings.cs @@ -15,6 +15,8 @@ namespace osu.Game.Screens.Play.PlayerSettings private readonly PlayerSliderBar dimSliderBar; private readonly PlayerSliderBar blurSliderBar; private readonly PlayerCheckbox showStoryboardToggle; + private readonly PlayerCheckbox beatmapSkinsToggle; + private readonly PlayerCheckbox beatmapHitsoundsToggle; public VisualSettings() { @@ -34,7 +36,9 @@ namespace osu.Game.Screens.Play.PlayerSettings { Text = "Toggles:" }, - showStoryboardToggle = new PlayerCheckbox { LabelText = "Storyboards" } + showStoryboardToggle = new PlayerCheckbox { LabelText = "Storyboards" }, + beatmapSkinsToggle = new PlayerCheckbox { LabelText = "Beatmap skins" }, + beatmapHitsoundsToggle = new PlayerCheckbox { LabelText = "Beatmap hitsounds" } }; } @@ -44,6 +48,8 @@ namespace osu.Game.Screens.Play.PlayerSettings dimSliderBar.Bindable = config.GetBindable(OsuSetting.DimLevel); blurSliderBar.Bindable = config.GetBindable(OsuSetting.BlurLevel); showStoryboardToggle.Bindable = config.GetBindable(OsuSetting.ShowStoryboard); + beatmapSkinsToggle.Bindable = config.GetBindable(OsuSetting.BeatmapSkins); + beatmapHitsoundsToggle.Bindable = config.GetBindable(OsuSetting.BeatmapHitsounds); } } } diff --git a/osu.Game/Screens/Select/Carousel/CarouselGroup.cs b/osu.Game/Screens/Select/Carousel/CarouselGroup.cs index a1f44763d6..2118cfdc78 100644 --- a/osu.Game/Screens/Select/Carousel/CarouselGroup.cs +++ b/osu.Game/Screens/Select/Carousel/CarouselGroup.cs @@ -27,6 +27,11 @@ namespace osu.Game.Screens.Select.Carousel get { var drawables = base.Drawables; + + // if we are explicitly not present, don't ever present children. + // without this check, children drawables can potentially be presented without their group header. + if (DrawableRepresentation.Value?.IsPresent == false) return drawables; + foreach (var c in InternalChildren) drawables.AddRange(c.Drawables); return drawables; diff --git a/osu.Game/Screens/Select/Carousel/CarouselItem.cs b/osu.Game/Screens/Select/Carousel/CarouselItem.cs index 0de32c12f1..c0781f09c0 100644 --- a/osu.Game/Screens/Select/Carousel/CarouselItem.cs +++ b/osu.Game/Screens/Select/Carousel/CarouselItem.cs @@ -24,7 +24,7 @@ namespace osu.Game.Screens.Select.Carousel { var items = new List(); - var self = drawableRepresentation.Value; + var self = DrawableRepresentation.Value; if (self?.IsPresent == true) items.Add(self); return items; @@ -35,7 +35,7 @@ namespace osu.Game.Screens.Select.Carousel protected CarouselItem() { - drawableRepresentation = new Lazy(CreateDrawableRepresentation); + DrawableRepresentation = new Lazy(CreateDrawableRepresentation); Filtered.ValueChanged += v => { @@ -44,13 +44,16 @@ namespace osu.Game.Screens.Select.Carousel }; } - private readonly Lazy drawableRepresentation; + protected readonly Lazy DrawableRepresentation; /// /// Used as a default sort method for s of differing types. /// internal ulong ChildID; + /// + /// Create a fresh drawable version of this item. If you wish to consume the current representation, use instead. + /// protected abstract DrawableCarouselItem CreateDrawableRepresentation(); public virtual void Filter(FilterCriteria criteria) diff --git a/osu.Game/Skinning/LocalSkinOverrideContainer.cs b/osu.Game/Skinning/LocalSkinOverrideContainer.cs index bfbb1719df..ad6a033936 100644 --- a/osu.Game/Skinning/LocalSkinOverrideContainer.cs +++ b/osu.Game/Skinning/LocalSkinOverrideContainer.cs @@ -4,9 +4,11 @@ using System; using osu.Framework.Allocation; using osu.Framework.Audio.Sample; +using osu.Framework.Configuration; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Textures; +using osu.Game.Configuration; namespace osu.Game.Skinning { @@ -14,17 +16,37 @@ namespace osu.Game.Skinning { public event Action SourceChanged; - public Drawable GetDrawableComponent(string componentName) => source.GetDrawableComponent(componentName) ?? fallbackSource?.GetDrawableComponent(componentName); + private Bindable beatmapSkins = new Bindable(); + private Bindable beatmapHitsounds = new Bindable(); - public Texture GetTexture(string componentName) => source.GetTexture(componentName) ?? fallbackSource.GetTexture(componentName); + public Drawable GetDrawableComponent(string componentName) + { + Drawable sourceDrawable; + if (beatmapSkins && (sourceDrawable = source.GetDrawableComponent(componentName)) != null) + return sourceDrawable; + return fallbackSource?.GetDrawableComponent(componentName); + } - public SampleChannel GetSample(string sampleName) => source.GetSample(sampleName) ?? fallbackSource?.GetSample(sampleName); + public Texture GetTexture(string componentName) + { + Texture sourceTexture; + if (beatmapSkins && (sourceTexture = source.GetTexture(componentName)) != null) + return sourceTexture; + return fallbackSource.GetTexture(componentName); + } + + public SampleChannel GetSample(string sampleName) + { + SampleChannel sourceChannel; + if (beatmapHitsounds && (sourceChannel = source.GetSample(sampleName)) != null) + return sourceChannel; + return fallbackSource?.GetSample(sampleName); + } 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) + if ((source as Skin)?.Configuration is TConfiguration conf) val = query?.Invoke(conf); return val ?? fallbackSource?.GetValue(query); @@ -33,8 +55,7 @@ namespace osu.Game.Skinning 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) + if ((source as Skin)?.Configuration is TConfiguration conf) val = query?.Invoke(conf); return val ?? fallbackSource?.GetValue(query); @@ -60,6 +81,18 @@ namespace osu.Game.Skinning return dependencies; } + [BackgroundDependencyLoader] + private void load(OsuConfigManager config) + { + beatmapSkins = config.GetBindable(OsuSetting.BeatmapSkins); + beatmapSkins.ValueChanged += val => onSourceChanged(); + beatmapSkins.TriggerChange(); + + beatmapHitsounds = config.GetBindable(OsuSetting.BeatmapHitsounds); + beatmapHitsounds.ValueChanged += val => onSourceChanged(); + beatmapHitsounds.TriggerChange(); + } + protected override void LoadComplete() { base.LoadComplete(); diff --git a/osu.Game/Users/UserStatus.cs b/osu.Game/Users/UserStatus.cs index 22bc9ed1a0..1584605166 100644 --- a/osu.Game/Users/UserStatus.cs +++ b/osu.Game/Users/UserStatus.cs @@ -12,12 +12,13 @@ namespace osu.Game.Users public abstract Color4 GetAppropriateColour(OsuColour colours); } - public abstract class UserStatusAvailable : UserStatus + public class UserStatusOnline : UserStatus { + public override string Message => @"Online"; public override Color4 GetAppropriateColour(OsuColour colours) => colours.BlueDarker; } - public abstract class UserStatusBusy : UserStatus + public abstract class UserStatusBusy : UserStatusOnline { public override Color4 GetAppropriateColour(OsuColour colours) => colours.YellowDark; } @@ -28,17 +29,12 @@ namespace osu.Game.Users public override Color4 GetAppropriateColour(OsuColour colours) => colours.Gray7; } - public class UserStatusOnline : UserStatusAvailable - { - public override string Message => @"Online"; - } - - public class UserStatusSpectating : UserStatusAvailable + public class UserStatusSpectating : UserStatusOnline { public override string Message => @"Spectating a game"; } - public class UserStatusInLobby : UserStatusAvailable + public class UserStatusInLobby : UserStatusOnline { public override string Message => @"in Multiplayer Lobby"; } @@ -53,13 +49,13 @@ namespace osu.Game.Users public override string Message => @"Multiplaying"; } - public class UserStatusModding : UserStatus + public class UserStatusModding : UserStatusOnline { public override string Message => @"Modding a map"; public override Color4 GetAppropriateColour(OsuColour colours) => colours.PurpleDark; } - public class UserStatusDoNotDisturb : UserStatus + public class UserStatusDoNotDisturb : UserStatusBusy { public override string Message => @"Do not disturb"; public override Color4 GetAppropriateColour(OsuColour colours) => colours.RedDark;