From b011edd85d7aefaa00b6d8fe83ca7d8def901149 Mon Sep 17 00:00:00 2001 From: WebFreak001 Date: Sun, 5 Aug 2018 13:12:31 +0200 Subject: [PATCH 01/88] added Overlays container to RulesetContainer this is required for mods such as flashlight which always want to draw objects above hitcircles. If just adding children to a RulesetContainer the hit circles would always be above the added children (no matter the Depth). --- osu.Game/Rulesets/UI/RulesetContainer.cs | 12 ++++++++++++ osu.Game/Screens/Play/Player.cs | 1 + 2 files changed, 13 insertions(+) diff --git a/osu.Game/Rulesets/UI/RulesetContainer.cs b/osu.Game/Rulesets/UI/RulesetContainer.cs index ee34e2df04..27dbc70164 100644 --- a/osu.Game/Rulesets/UI/RulesetContainer.cs +++ b/osu.Game/Rulesets/UI/RulesetContainer.cs @@ -69,6 +69,12 @@ namespace osu.Game.Rulesets.UI /// public Playfield Playfield => playfield.Value; + private readonly Container overlays; + /// + /// Place to put drawables above hit objects but below UI. + /// + public Container Overlays => overlays; + /// /// The cursor provided by this . May be null if no cursor is provided. /// @@ -88,6 +94,12 @@ namespace osu.Game.Rulesets.UI { Ruleset = ruleset; playfield = new Lazy(CreatePlayfield); + overlays = new Container + { + RelativeSizeAxes = Axes.Both, + Width = 1, + Height = 1 + }; IsPaused.ValueChanged += paused => { diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 2e23bb16f0..31c3e06705 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -178,6 +178,7 @@ namespace osu.Game.Screens.Play RelativeSizeAxes = Axes.Both, Child = RulesetContainer }, + RulesetContainer.Overlays, new BreakOverlay(beatmap.BeatmapInfo.LetterboxInBreaks, ScoreProcessor) { Anchor = Anchor.Centre, From b33954d9db69ec37ec6f70ec4c8dca60420df957 Mon Sep 17 00:00:00 2001 From: WebFreak001 Date: Sun, 5 Aug 2018 14:20:56 +0200 Subject: [PATCH 02/88] Implement blinds mod --- osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs | 29 ++++++ .../Objects/Drawables/DrawableOsuBlinds.cs | 96 +++++++++++++++++++ osu.Game.Rulesets.Osu/OsuRuleset.cs | 2 +- osu.Game/Rulesets/Mods/ModBlinds.cs | 24 +++++ 4 files changed, 150 insertions(+), 1 deletion(-) create mode 100644 osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs create mode 100644 osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuBlinds.cs create mode 100644 osu.Game/Rulesets/Mods/ModBlinds.cs diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs new file mode 100644 index 0000000000..cefaf02a17 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs @@ -0,0 +1,29 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Osu.Objects.Drawables; +using osu.Game.Rulesets.Scoring; +using osu.Game.Rulesets.UI; + +namespace osu.Game.Rulesets.Osu.Mods +{ + public class OsuModBlinds : ModBlinds + { + public override double ScoreMultiplier => 1.12; + private DrawableOsuBlinds flashlight; + + public override void ApplyToRulesetContainer(RulesetContainer rulesetContainer) + { + rulesetContainer.Overlays.Add(flashlight = new DrawableOsuBlinds(restrictTo: rulesetContainer.Playfield)); + } + + public override void ApplyToScoreProcessor(ScoreProcessor scoreProcessor) + { + scoreProcessor.Health.ValueChanged += val => { + flashlight.Value = (float)val; + }; + } + } +} diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuBlinds.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuBlinds.cs new file mode 100644 index 0000000000..ced5947ba6 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuBlinds.cs @@ -0,0 +1,96 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using OpenTK.Graphics; +using osu.Framework.Allocation; + +namespace osu.Game.Rulesets.Osu.Objects.Drawables +{ + /// + /// Element for the Blinds mod drawing 2 black boxes covering the whole screen which resize inside a restricted area with some leniency. + /// + public class DrawableOsuBlinds : Container + { + private Box box1, box2; + private float target = 1; + private readonly float easing = 1; + private readonly Container restrictTo; + + /// + /// + /// Percentage of playfield to extend blinds over. Basically moves the origin points where the blinds start. + /// + /// + /// -1 would mean the blinds always cover the whole screen no matter health. + /// 0 would mean the blinds will only ever be on the edge of the playfield on 0% health. + /// 1 would mean the blinds are fully outside the playfield on 50% health. + /// Infinity would mean the blinds are always outside the playfield except on 100% health. + /// + /// + private const float leniency = 0.2f; + + public DrawableOsuBlinds(Container restrictTo) + { + this.restrictTo = restrictTo; + } + + [BackgroundDependencyLoader] + private void load() + { + RelativeSizeAxes = Axes.Both; + Width = 1; + Height = 1; + + Add(box1 = new Box + { + Anchor = Anchor.TopLeft, + Origin = Anchor.TopLeft, + Colour = Color4.Black, + RelativeSizeAxes = Axes.Y, + Width = 0, + Height = 1 + }); + Add(box2 = new Box + { + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + Colour = Color4.Black, + RelativeSizeAxes = Axes.Y, + Width = 0, + Height = 1 + }); + } + + protected override void Update() + { + float start = Parent.ToLocalSpace(restrictTo.ScreenSpaceDrawQuad.TopLeft).X; + float end = Parent.ToLocalSpace(restrictTo.ScreenSpaceDrawQuad.TopRight).X; + float rawWidth = end - start; + start -= rawWidth * leniency * 0.5f; + end += rawWidth * leniency * 0.5f; + float width = (end - start) * 0.5f * easing; + // different values in case the playfield ever moves from center to somewhere else. + box1.Width = start + width; + box2.Width = DrawWidth - end + width; + } + + /// + /// Health between 0 and 1 for the blinds to base the width on. Will get animated for 200ms using out-quintic easing. + /// + public float Value + { + set + { + target = value; + this.TransformTo(nameof(easing), target, 200, Easing.OutQuint); + } + get + { + return target; + } + } + } +} diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs index fa6e9a018a..294078b0f3 100644 --- a/osu.Game.Rulesets.Osu/OsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs @@ -103,7 +103,7 @@ namespace osu.Game.Rulesets.Osu new MultiMod(new OsuModSuddenDeath(), new OsuModPerfect()), new MultiMod(new OsuModDoubleTime(), new OsuModNightcore()), new OsuModHidden(), - new OsuModFlashlight(), + new MultiMod(new OsuModFlashlight(), new OsuModBlinds()), }; case ModType.Conversion: return new Mod[] diff --git a/osu.Game/Rulesets/Mods/ModBlinds.cs b/osu.Game/Rulesets/Mods/ModBlinds.cs new file mode 100644 index 0000000000..1494b314c2 --- /dev/null +++ b/osu.Game/Rulesets/Mods/ModBlinds.cs @@ -0,0 +1,24 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Game.Graphics; +using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Scoring; +using osu.Game.Rulesets.UI; + +namespace osu.Game.Rulesets.Mods +{ + public abstract class ModBlinds : Mod, IApplicableToRulesetContainer, IApplicableToScoreProcessor + where T : HitObject + { + public override string Name => "Blinds"; + public override string ShortenedName => "BL"; + public override FontAwesome Icon => FontAwesome.fa_osu_mod_flashlight; + public override ModType Type => ModType.DifficultyIncrease; + public override string Description => "Play with blinds on your screen."; + public override bool Ranked => false; + + public abstract void ApplyToRulesetContainer(RulesetContainer rulesetContainer); + public abstract void ApplyToScoreProcessor(ScoreProcessor scoreProcessor); + } +} From 5f3c0549c99b17b9441b09df4f545b7ed3f029cf Mon Sep 17 00:00:00 2001 From: WebFreak001 Date: Sat, 15 Sep 2018 23:44:22 +0200 Subject: [PATCH 03/88] Sprites in blinds mod & gameplay improvements There are now skinnable actual blinds (shoji screen panels) The black overlay is still behind them to avoid cheating with skins The blinds don't open linearly anymore, they are health squared now When easy mod is on, there is always a little gap open --- osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs | 4 +- .../Objects/Drawables/DrawableOsuBlinds.cs | 74 ++++++++++++++++++- .../Drawables/Pieces/ModBlindsPanelSprite.cs | 26 +++++++ osu.Game/Rulesets/UI/RulesetContainer.cs | 2 + 4 files changed, 101 insertions(+), 5 deletions(-) create mode 100644 osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ModBlindsPanelSprite.cs diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs index cefaf02a17..a4441a2bdc 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs @@ -6,6 +6,7 @@ using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.UI; +using System.Linq; namespace osu.Game.Rulesets.Osu.Mods { @@ -16,7 +17,8 @@ namespace osu.Game.Rulesets.Osu.Mods public override void ApplyToRulesetContainer(RulesetContainer rulesetContainer) { - rulesetContainer.Overlays.Add(flashlight = new DrawableOsuBlinds(restrictTo: rulesetContainer.Playfield)); + bool hasEasy = rulesetContainer.ActiveMods.Count(mod => mod is ModEasy) > 0; + rulesetContainer.Overlays.Add(flashlight = new DrawableOsuBlinds(restrictTo: rulesetContainer.Playfield, hasEasy: hasEasy)); } public override void ApplyToScoreProcessor(ScoreProcessor scoreProcessor) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuBlinds.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuBlinds.cs index ced5947ba6..69fc4a1d57 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuBlinds.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuBlinds.cs @@ -6,6 +6,10 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using OpenTK.Graphics; using osu.Framework.Allocation; +using osu.Game.Skinning; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.Textures; +using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; namespace osu.Game.Rulesets.Osu.Objects.Drawables { @@ -14,10 +18,19 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables /// public class DrawableOsuBlinds : Container { + /// + /// Black background boxes behind blind panel textures. + /// private Box box1, box2; + private Sprite panelLeft, panelRight; + private Sprite bgPanelLeft, bgPanelRight; + private ISkinSource skin; + private float target = 1; private readonly float easing = 1; + private readonly Container restrictTo; + private readonly bool hasEasy; /// /// @@ -30,15 +43,21 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables /// Infinity would mean the blinds are always outside the playfield except on 100% health. /// /// - private const float leniency = 0.2f; + private const float leniency = 0.1f; - public DrawableOsuBlinds(Container restrictTo) + /// + /// Multiplier for adding a gap when the Easy mod is also currently applied. + /// + private const float easy_position_multiplier = 0.95f; + + public DrawableOsuBlinds(Container restrictTo, bool hasEasy) { this.restrictTo = restrictTo; + this.hasEasy = hasEasy; } [BackgroundDependencyLoader] - private void load() + private void load(ISkinSource skin, TextureStore textures) { RelativeSizeAxes = Axes.Both; Width = 1; @@ -62,6 +81,36 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables Width = 0, Height = 1 }); + + Add(bgPanelLeft = new ModBlindsPanelSprite { + Origin = Anchor.TopRight, + Colour = Color4.Gray + }); + Add(bgPanelRight = new ModBlindsPanelSprite { + Origin = Anchor.TopLeft, + Colour = Color4.Gray + }); + + Add(panelLeft = new ModBlindsPanelSprite { + Origin = Anchor.TopRight + }); + Add(panelRight = new ModBlindsPanelSprite { + Origin = Anchor.TopLeft + }); + + this.skin = skin; + skin.SourceChanged += skinChanged; + PanelTexture = textures.Get("Play/osu/blinds-panel"); + } + + private void skinChanged() + { + PanelTexture = skin.GetTexture("Play/osu/blinds-panel"); + } + + private static float applyAdjustmentCurve(float value) + { + return value * value; } protected override void Update() @@ -71,10 +120,16 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables float rawWidth = end - start; start -= rawWidth * leniency * 0.5f; end += rawWidth * leniency * 0.5f; - float width = (end - start) * 0.5f * easing; + + float width = (end - start) * 0.5f * applyAdjustmentCurve((hasEasy ? easy_position_multiplier : 1) * easing); // different values in case the playfield ever moves from center to somewhere else. box1.Width = start + width; box2.Width = DrawWidth - end + width; + + panelLeft.X = start + width; + panelRight.X = end - width; + bgPanelLeft.X = start; + bgPanelRight.X = end; } /// @@ -92,5 +147,16 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables return target; } } + + public Texture PanelTexture + { + set + { + panelLeft.Texture = value; + panelRight.Texture = value; + bgPanelLeft.Texture = value; + bgPanelRight.Texture = value; + } + } } } diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ModBlindsPanelSprite.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ModBlindsPanelSprite.cs new file mode 100644 index 0000000000..459ea920fa --- /dev/null +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ModBlindsPanelSprite.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 + +using osu.Framework.Graphics; +using osu.Framework.Graphics.Sprites; + +namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces +{ + public class ModBlindsPanelSprite : Sprite + { + public ModBlindsPanelSprite() + { + RelativeSizeAxes = Axes.None; + Anchor = Anchor.TopLeft; + } + + protected override void Update() + { + Height = Parent?.DrawHeight ?? 0; + if (Height == 0 || Texture is null) + Width = 0; + else + Width = Texture.Width / (float)Texture.Height * Height; + } + } +} diff --git a/osu.Game/Rulesets/UI/RulesetContainer.cs b/osu.Game/Rulesets/UI/RulesetContainer.cs index 02ec17e969..7b146f5b84 100644 --- a/osu.Game/Rulesets/UI/RulesetContainer.cs +++ b/osu.Game/Rulesets/UI/RulesetContainer.cs @@ -328,6 +328,8 @@ namespace osu.Game.Rulesets.UI Playfield.Size = GetAspectAdjustedSize() * PlayfieldArea; } + public IEnumerable ActiveMods { get => Mods; } + /// /// Computes the size of the in relative coordinate space after aspect adjustments. /// From 91b25870ef382039b7479ebdf3b4d4532c504701 Mon Sep 17 00:00:00 2001 From: WebFreak001 Date: Sun, 16 Sep 2018 12:48:36 +0200 Subject: [PATCH 04/88] Make fruit catcher enter and leave what's behind the blinds --- osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs | 17 +- .../Objects/Drawables/DrawableOsuBlinds.cs | 164 ++++++++++++++++-- 2 files changed, 164 insertions(+), 17 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs index a4441a2bdc..45c22b7153 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs @@ -6,7 +6,6 @@ using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.UI; -using System.Linq; namespace osu.Game.Rulesets.Osu.Mods { @@ -17,8 +16,16 @@ namespace osu.Game.Rulesets.Osu.Mods public override void ApplyToRulesetContainer(RulesetContainer rulesetContainer) { - bool hasEasy = rulesetContainer.ActiveMods.Count(mod => mod is ModEasy) > 0; - rulesetContainer.Overlays.Add(flashlight = new DrawableOsuBlinds(restrictTo: rulesetContainer.Playfield, hasEasy: hasEasy)); + bool hasEasy = false; + bool hasHardrock = false; + foreach (var mod in rulesetContainer.ActiveMods) + { + if (mod is ModEasy) + hasEasy = true; + if (mod is ModHardRock) + hasHardrock = true; + } + rulesetContainer.Overlays.Add(flashlight = new DrawableOsuBlinds(restrictTo: rulesetContainer.Playfield, hasEasy: hasEasy, hasHardrock: hasHardrock)); } public override void ApplyToScoreProcessor(ScoreProcessor scoreProcessor) @@ -26,6 +33,10 @@ namespace osu.Game.Rulesets.Osu.Mods scoreProcessor.Health.ValueChanged += val => { flashlight.Value = (float)val; }; + scoreProcessor.Combo.ValueChanged += val => { + if (val > 0 && val % 30 == 0) + flashlight.TriggerNPC(); + }; } } } diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuBlinds.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuBlinds.cs index 69fc4a1d57..7c539e0e94 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuBlinds.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuBlinds.cs @@ -10,6 +10,7 @@ using osu.Game.Skinning; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; +using System; namespace osu.Game.Rulesets.Osu.Objects.Drawables { @@ -24,13 +25,27 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables private Box box1, box2; private Sprite panelLeft, panelRight; private Sprite bgPanelLeft, bgPanelRight; + + private Drawable bgRandomNpc; + private Drawable randomNpc; + private const float npc_movement_start = 1.5f; + private float npcPosition = npc_movement_start; + private bool animatingNPC; + private Random random; + private ISkinSource skin; + private float targetClamp = 1; private float target = 1; private readonly float easing = 1; + private const float black_depth = 10; + private const float bg_panel_depth = 8; + private const float fg_panel_depth = 4; + private const float npc_depth = 6; + private readonly Container restrictTo; - private readonly bool hasEasy; + private readonly bool modEasy, modHardrock; /// /// @@ -50,10 +65,12 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables /// private const float easy_position_multiplier = 0.95f; - public DrawableOsuBlinds(Container restrictTo, bool hasEasy) + public DrawableOsuBlinds(Container restrictTo, bool hasEasy, bool hasHardrock) { this.restrictTo = restrictTo; - this.hasEasy = hasEasy; + + modEasy = hasEasy; + modHardrock = hasHardrock; } [BackgroundDependencyLoader] @@ -70,7 +87,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables Colour = Color4.Black, RelativeSizeAxes = Axes.Y, Width = 0, - Height = 1 + Height = 1, + Depth = black_depth }); Add(box2 = new Box { @@ -79,23 +97,56 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables Colour = Color4.Black, RelativeSizeAxes = Axes.Y, Width = 0, - Height = 1 + Height = 1, + Depth = black_depth }); Add(bgPanelLeft = new ModBlindsPanelSprite { Origin = Anchor.TopRight, - Colour = Color4.Gray + Colour = Color4.Gray, + Depth = bg_panel_depth + 1 }); - Add(bgPanelRight = new ModBlindsPanelSprite { - Origin = Anchor.TopLeft, - Colour = Color4.Gray + Add(panelLeft = new ModBlindsPanelSprite { + Origin = Anchor.TopRight, + Depth = bg_panel_depth }); - Add(panelLeft = new ModBlindsPanelSprite { - Origin = Anchor.TopRight + Add(bgPanelRight = new ModBlindsPanelSprite { + Origin = Anchor.TopLeft, + Colour = Color4.Gray, + Depth = fg_panel_depth + 1 }); Add(panelRight = new ModBlindsPanelSprite { - Origin = Anchor.TopLeft + Origin = Anchor.TopLeft, + Depth = fg_panel_depth + }); + + + random = new Random(); + Add(bgRandomNpc = new Box + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Colour = Color4.Black, + Width = 512 * 0.4f, + Height = 512 * 0.95f, + RelativePositionAxes = Axes.Y, + X = -512, + Y = 0, + Depth = black_depth + }); + Add(new SkinnableDrawable("Play/Catch/fruit-catcher-idle", name => randomNpc = new Sprite + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Texture = textures.Get(name), + Width = 512, + Height = 512, + RelativePositionAxes = Axes.Y, + X = -512, + Y = 0 + }) { + Depth = npc_depth }); this.skin = skin; @@ -108,9 +159,36 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables PanelTexture = skin.GetTexture("Play/osu/blinds-panel"); } + private float applyGap(float value) + { + float ret; + if (modEasy) + { + float multiplier = 0.95f; + ret = value * multiplier; + } + else if (modHardrock) + { + float multiplier = 1.1f; + ret = value * multiplier; + } + else + { + ret = value; + } + + if (ret > targetClamp) + return targetClamp; + else if (ret < 0) + return 0; + else + return ret; + } + private static float applyAdjustmentCurve(float value) { - return value * value; + // lagrange polinominal for (0,0) (0.5,0.35) (1,1) should make a good curve + return 0.6f * value * value + 0.4f * value; } protected override void Update() @@ -121,7 +199,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables start -= rawWidth * leniency * 0.5f; end += rawWidth * leniency * 0.5f; - float width = (end - start) * 0.5f * applyAdjustmentCurve((hasEasy ? easy_position_multiplier : 1) * easing); + float width = (end - start) * 0.5f * applyAdjustmentCurve(applyGap(easing)); // different values in case the playfield ever moves from center to somewhere else. box1.Width = start + width; box2.Width = DrawWidth - end + width; @@ -130,6 +208,64 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables panelRight.X = end - width; bgPanelLeft.X = start; bgPanelRight.X = end; + + float adjustedNpcPosition = npcPosition * rawWidth; + if (randomNpc != null) + randomNpc.X = adjustedNpcPosition; + bgRandomNpc.X = adjustedNpcPosition; + } + + public void TriggerNPC() + { + if (animatingNPC) + return; + + bool left = (random.Next() & 1) != 0; + bool exit = (random.Next() & 1) != 0; + float start, end; + + if (left) + { + start = -npc_movement_start; + end = npc_movement_start; + + randomNpc.Scale = new OpenTK.Vector2(1, 1); + } + else + { + start = npc_movement_start; + end = -npc_movement_start; + + randomNpc.Scale = new OpenTK.Vector2(-1, 1); + } + + // depths for exit from the left and entry from the right + if (left == exit) + { + ChangeChildDepth(bgPanelLeft, fg_panel_depth + 1); + ChangeChildDepth(panelLeft, fg_panel_depth); + + ChangeChildDepth(bgPanelRight, bg_panel_depth + 1); + ChangeChildDepth(panelRight, bg_panel_depth); + } + else // depths for entry from the left or exit from the right + { + ChangeChildDepth(bgPanelLeft, bg_panel_depth + 1); + ChangeChildDepth(panelLeft, bg_panel_depth); + + ChangeChildDepth(bgPanelRight, fg_panel_depth + 1); + ChangeChildDepth(panelRight, fg_panel_depth); + } + + animatingNPC = true; + npcPosition = start; + this.TransformTo(nameof(npcPosition), end, 3000, Easing.OutSine).Finally(_ => animatingNPC = false); + + targetClamp = 1; + this.Delay(600).TransformTo(nameof(targetClamp), 0.6f, 300).Delay(500).TransformTo(nameof(targetClamp), 1f, 300); + + randomNpc?.FadeIn(250).Delay(2000).FadeOut(500); + bgRandomNpc.FadeIn(250).Delay(2000).FadeOut(500); } /// From 633e8fafee41ada907889bd43f725ad08f95c25b Mon Sep 17 00:00:00 2001 From: WebFreak001 Date: Sun, 16 Sep 2018 12:57:54 +0200 Subject: [PATCH 05/88] Style & const fix --- osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs | 2 +- .../Objects/Drawables/DrawableOsuBlinds.cs | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs index 45c22b7153..9639dd5dd8 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs @@ -35,7 +35,7 @@ namespace osu.Game.Rulesets.Osu.Mods }; scoreProcessor.Combo.ValueChanged += val => { if (val > 0 && val % 30 == 0) - flashlight.TriggerNPC(); + flashlight.TriggerNpc(); }; } } diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuBlinds.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuBlinds.cs index 7c539e0e94..8c2a569e92 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuBlinds.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuBlinds.cs @@ -30,7 +30,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables private Drawable randomNpc; private const float npc_movement_start = 1.5f; private float npcPosition = npc_movement_start; - private bool animatingNPC; + private bool animatingNpc; private Random random; private ISkinSource skin; @@ -164,12 +164,12 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables float ret; if (modEasy) { - float multiplier = 0.95f; + const float multiplier = 0.95f; ret = value * multiplier; } else if (modHardrock) { - float multiplier = 1.1f; + const float multiplier = 1.1f; ret = value * multiplier; } else @@ -215,9 +215,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables bgRandomNpc.X = adjustedNpcPosition; } - public void TriggerNPC() + public void TriggerNpc() { - if (animatingNPC) + if (animatingNpc) return; bool left = (random.Next() & 1) != 0; @@ -257,9 +257,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables ChangeChildDepth(panelRight, fg_panel_depth); } - animatingNPC = true; + animatingNpc = true; npcPosition = start; - this.TransformTo(nameof(npcPosition), end, 3000, Easing.OutSine).Finally(_ => animatingNPC = false); + this.TransformTo(nameof(npcPosition), end, 3000, Easing.OutSine).Finally(_ => animatingNpc = false); targetClamp = 1; this.Delay(600).TransformTo(nameof(targetClamp), 0.6f, 300).Delay(500).TransformTo(nameof(targetClamp), 1f, 300); From c9ea5ce817fac5d860fefef7d2cf1fd7be459463 Mon Sep 17 00:00:00 2001 From: WebFreak001 Date: Sun, 16 Sep 2018 16:51:18 +0200 Subject: [PATCH 06/88] Made blinds open during breaks and start --- osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs | 2 +- .../Objects/Drawables/DrawableOsuBlinds.cs | 89 ++++++++++++------- .../Drawables/Pieces/ModBlindsPanelSprite.cs | 2 +- osu.Game/Rulesets/Mods/ModBlinds.cs | 2 +- 4 files changed, 62 insertions(+), 33 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs index 9639dd5dd8..4baea5d0c0 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs @@ -25,7 +25,7 @@ namespace osu.Game.Rulesets.Osu.Mods if (mod is ModHardRock) hasHardrock = true; } - rulesetContainer.Overlays.Add(flashlight = new DrawableOsuBlinds(restrictTo: rulesetContainer.Playfield, hasEasy: hasEasy, hasHardrock: hasHardrock)); + rulesetContainer.Overlays.Add(flashlight = new DrawableOsuBlinds(rulesetContainer.Playfield, hasEasy, hasHardrock, rulesetContainer.Beatmap)); } public override void ApplyToScoreProcessor(ScoreProcessor scoreProcessor) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuBlinds.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuBlinds.cs index 8c2a569e92..ae099cd589 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuBlinds.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuBlinds.cs @@ -11,6 +11,7 @@ using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; using System; +using osu.Game.Beatmaps; namespace osu.Game.Rulesets.Osu.Objects.Drawables { @@ -22,7 +23,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables /// /// Black background boxes behind blind panel textures. /// - private Box box1, box2; + private Box blackBoxLeft, blackBoxRight; private Sprite panelLeft, panelRight; private Sprite bgPanelLeft, bgPanelRight; @@ -30,12 +31,14 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables private Drawable randomNpc; private const float npc_movement_start = 1.5f; private float npcPosition = npc_movement_start; - private bool animatingNpc; + private bool animatingBlinds; + private Beatmap beatmap; private Random random; private ISkinSource skin; private float targetClamp = 1; + private float targetBreakMultiplier = 0; private float target = 1; private readonly float easing = 1; @@ -60,14 +63,10 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables /// private const float leniency = 0.1f; - /// - /// Multiplier for adding a gap when the Easy mod is also currently applied. - /// - private const float easy_position_multiplier = 0.95f; - - public DrawableOsuBlinds(Container restrictTo, bool hasEasy, bool hasHardrock) + public DrawableOsuBlinds(Container restrictTo, bool hasEasy, bool hasHardrock, Beatmap beatmap) { this.restrictTo = restrictTo; + this.beatmap = beatmap; modEasy = hasEasy; modHardrock = hasHardrock; @@ -80,7 +79,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables Width = 1; Height = 1; - Add(box1 = new Box + Add(blackBoxLeft = new Box { Anchor = Anchor.TopLeft, Origin = Anchor.TopLeft, @@ -90,7 +89,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables Height = 1, Depth = black_depth }); - Add(box2 = new Box + Add(blackBoxRight = new Box { Anchor = Anchor.TopRight, Origin = Anchor.TopRight, @@ -161,28 +160,22 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables private float applyGap(float value) { - float ret; + const float easy_multiplier = 0.95f; + const float hardrock_multiplier = 1.1f; + + float multiplier = 1; if (modEasy) { - const float multiplier = 0.95f; - ret = value * multiplier; + multiplier = easy_multiplier; + // TODO: include OD/CS } else if (modHardrock) { - const float multiplier = 1.1f; - ret = value * multiplier; - } - else - { - ret = value; + multiplier = hardrock_multiplier; + // TODO: include OD/CS } - if (ret > targetClamp) - return targetClamp; - else if (ret < 0) - return 0; - else - return ret; + return OpenTK.MathHelper.Clamp(value * multiplier, 0, targetClamp) * targetBreakMultiplier; } private static float applyAdjustmentCurve(float value) @@ -201,8 +194,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables float width = (end - start) * 0.5f * applyAdjustmentCurve(applyGap(easing)); // different values in case the playfield ever moves from center to somewhere else. - box1.Width = start + width; - box2.Width = DrawWidth - end + width; + blackBoxLeft.Width = start + width; + blackBoxRight.Width = DrawWidth - end + width; panelLeft.X = start + width; panelRight.X = end - width; @@ -215,9 +208,45 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables bgRandomNpc.X = adjustedNpcPosition; } + protected override void LoadComplete() + { + const float break_open_early = 500; + + base.LoadComplete(); + + var firstObj = beatmap.HitObjects[0]; + var startDelay = firstObj.StartTime - firstObj.TimePreempt - firstObj.TimeFadeIn; + + using (BeginAbsoluteSequence(startDelay, true)) + LeaveBreak(); + + foreach (var breakInfo in beatmap.Breaks) + { + if (breakInfo.HasEffect) + { + using (BeginAbsoluteSequence(breakInfo.StartTime - break_open_early, true)) + { + EnterBreak(); + using (BeginDelayedSequence(breakInfo.Duration + break_open_early, true)) + LeaveBreak(); + } + } + } + } + + public void EnterBreak() + { + this.TransformTo(nameof(targetBreakMultiplier), 0f, 1000, Easing.OutSine); + } + + public void LeaveBreak() + { + this.TransformTo(nameof(targetBreakMultiplier), 1f, 2500, Easing.OutBounce); + } + public void TriggerNpc() { - if (animatingNpc) + if (animatingBlinds) return; bool left = (random.Next() & 1) != 0; @@ -257,9 +286,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables ChangeChildDepth(panelRight, fg_panel_depth); } - animatingNpc = true; + animatingBlinds = true; npcPosition = start; - this.TransformTo(nameof(npcPosition), end, 3000, Easing.OutSine).Finally(_ => animatingNpc = false); + this.TransformTo(nameof(npcPosition), end, 3000, Easing.OutSine).Finally(_ => animatingBlinds = false); targetClamp = 1; this.Delay(600).TransformTo(nameof(targetClamp), 0.6f, 300).Delay(500).TransformTo(nameof(targetClamp), 1f, 300); diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ModBlindsPanelSprite.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ModBlindsPanelSprite.cs index 459ea920fa..c6e2db1842 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ModBlindsPanelSprite.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ModBlindsPanelSprite.cs @@ -17,7 +17,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces protected override void Update() { Height = Parent?.DrawHeight ?? 0; - if (Height == 0 || Texture is null) + if (Height == 0 || Texture == null) Width = 0; else Width = Texture.Width / (float)Texture.Height * Height; diff --git a/osu.Game/Rulesets/Mods/ModBlinds.cs b/osu.Game/Rulesets/Mods/ModBlinds.cs index 1494b314c2..bf68300cd6 100644 --- a/osu.Game/Rulesets/Mods/ModBlinds.cs +++ b/osu.Game/Rulesets/Mods/ModBlinds.cs @@ -13,7 +13,7 @@ namespace osu.Game.Rulesets.Mods { public override string Name => "Blinds"; public override string ShortenedName => "BL"; - public override FontAwesome Icon => FontAwesome.fa_osu_mod_flashlight; + public override FontAwesome Icon => FontAwesome.fa_adjust; public override ModType Type => ModType.DifficultyIncrease; public override string Description => "Play with blinds on your screen."; public override bool Ranked => false; From 2de3b33780ac0871188be90a29a703475f7576de Mon Sep 17 00:00:00 2001 From: WebFreak001 Date: Sun, 16 Sep 2018 16:57:43 +0200 Subject: [PATCH 07/88] Readonly fixes --- osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuBlinds.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuBlinds.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuBlinds.cs index ae099cd589..4fe5b4e4fb 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuBlinds.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuBlinds.cs @@ -32,13 +32,14 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables private const float npc_movement_start = 1.5f; private float npcPosition = npc_movement_start; private bool animatingBlinds; - private Beatmap beatmap; + + private readonly Beatmap beatmap; private Random random; private ISkinSource skin; private float targetClamp = 1; - private float targetBreakMultiplier = 0; + private readonly float targetBreakMultiplier = 0; private float target = 1; private readonly float easing = 1; From 8a01fc1bffa8c323da188aaa50a19c446ce2f61b Mon Sep 17 00:00:00 2001 From: WebFreak001 Date: Mon, 17 Sep 2018 20:31:50 +0200 Subject: [PATCH 08/88] Make random in blinds mod the same every replay --- .../Objects/Drawables/DrawableOsuBlinds.cs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuBlinds.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuBlinds.cs index 4fe5b4e4fb..15d394dbb4 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuBlinds.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuBlinds.cs @@ -121,8 +121,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables Depth = fg_panel_depth }); - - random = new Random(); + // seed with unique seed per map so NPC always comes from the same sides for a same map for reproducible replays. + random = new Random(beatmap.Metadata.ToString().GetHashCode()); Add(bgRandomNpc = new Box { Anchor = Anchor.Centre, @@ -133,7 +133,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables RelativePositionAxes = Axes.Y, X = -512, Y = 0, - Depth = black_depth + Depth = black_depth, + Alpha = 0 }); Add(new SkinnableDrawable("Play/Catch/fruit-catcher-idle", name => randomNpc = new Sprite { @@ -144,7 +145,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables Height = 512, RelativePositionAxes = Axes.Y, X = -512, - Y = 0 + Y = 0, + Alpha = 0 }) { Depth = npc_depth }); From 72e82b660d91eeae22a9d0d5acc8d25f274a8cf2 Mon Sep 17 00:00:00 2001 From: WebFreak001 Date: Sun, 28 Oct 2018 01:14:16 +0200 Subject: [PATCH 09/88] Adjust blinds animations based on player feedback --- .../Objects/Drawables/DrawableOsuBlinds.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuBlinds.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuBlinds.cs index 1ba18dacbc..2bbd31fc46 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuBlinds.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuBlinds.cs @@ -214,13 +214,14 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables protected override void LoadComplete() { const float break_open_early = 500; + const float break_close_late = 250; base.LoadComplete(); var firstObj = beatmap.HitObjects[0]; - var startDelay = firstObj.StartTime - firstObj.TimePreempt - firstObj.TimeFadeIn; + var startDelay = firstObj.StartTime - firstObj.TimePreempt; - using (BeginAbsoluteSequence(startDelay, true)) + using (BeginAbsoluteSequence(startDelay + break_close_late, true)) LeaveBreak(); foreach (var breakInfo in beatmap.Breaks) @@ -230,7 +231,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables using (BeginAbsoluteSequence(breakInfo.StartTime - break_open_early, true)) { EnterBreak(); - using (BeginDelayedSequence(breakInfo.Duration + break_open_early, true)) + using (BeginDelayedSequence(breakInfo.Duration + break_open_early + break_close_late, true)) LeaveBreak(); } } From 36b458bdee3dedaee369a05222d22631b6212cb0 Mon Sep 17 00:00:00 2001 From: Ivan Pavluk Date: Thu, 29 Nov 2018 08:56:19 +0700 Subject: [PATCH 10/88] Fixed #3777 --- .../Judgements/TaikoDrumRollJudgement.cs | 11 ++++++++++ .../Objects/Drawables/DrawableHit.cs | 4 ++-- osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs | 4 ++++ .../Scoring/TaikoScoreProcessor.cs | 22 ++++++++++++++++++- 4 files changed, 38 insertions(+), 3 deletions(-) create mode 100644 osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollJudgement.cs diff --git a/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollJudgement.cs b/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollJudgement.cs new file mode 100644 index 0000000000..b1ac49b939 --- /dev/null +++ b/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollJudgement.cs @@ -0,0 +1,11 @@ +using osu.Game.Rulesets.Scoring; + +namespace osu.Game.Rulesets.Taiko.Judgements +{ + class TaikoDrumRollJudgement : TaikoJudgement + { + public override bool AffectsCombo => false; + + protected override int NumericResultFor(HitResult result) => 0; + } +} diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs index 6f7264e23b..a1681b38f1 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs @@ -170,7 +170,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables ApplyResult(r => r.Type = HitResult.Miss); return; } - + if (!userTriggered) { if (timeOffset > second_hit_window) @@ -179,7 +179,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables } if (Math.Abs(MainObject.Result.TimeOffset - timeOffset) < second_hit_window) - ApplyResult(r => r.Type = HitResult.Great); + ApplyResult(r => r.Type = MainObject.Result.Type); } public override bool OnPressed(TaikoAction action) diff --git a/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs b/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs index 405ea85f0d..0dc460643a 100644 --- a/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs +++ b/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs @@ -5,11 +5,15 @@ using osu.Game.Rulesets.Objects.Types; using System; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Taiko.Judgements; namespace osu.Game.Rulesets.Taiko.Objects { public class DrumRoll : TaikoHitObject, IHasEndTime { + public override Judgement CreateJudgement() => new TaikoDrumRollJudgement(); + /// /// Drum roll distance that results in a duration of 1 speed-adjusted beat length. /// diff --git a/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs b/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs index cf33141027..cf974a6223 100644 --- a/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs +++ b/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs @@ -80,7 +80,27 @@ namespace osu.Game.Rulesets.Taiko.Scoring { base.ApplyResult(result); - bool isTick = result.Judgement is TaikoDrumRollTickJudgement; + bool isTick = false; + bool isRoll = false; + bool isStrong = false; + + isTick = result.Judgement is TaikoDrumRollTickJudgement; + if (!isTick) + { + isRoll = result.Judgement is TaikoDrumRollJudgement; + if (!isRoll) + { + isStrong = result.Judgement is TaikoStrongJudgement; + } + } + + //Don't change HP based on drum roll fullness for compatibility + if (isRoll) + return; + + //If the object is strong, HP change is already handled in MainObject + if (isStrong) + return; // Apply HP changes switch (result.Type) From 17337e05a1f857ebc583f8aa589f9cdac90b411e Mon Sep 17 00:00:00 2001 From: Ivan Pavluk Date: Thu, 29 Nov 2018 09:06:40 +0700 Subject: [PATCH 11/88] Fixed whitespace --- osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs index a1681b38f1..48731388cb 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs @@ -170,7 +170,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables ApplyResult(r => r.Type = HitResult.Miss); return; } - + if (!userTriggered) { if (timeOffset > second_hit_window) From 00a243f7f26e77e5987e8b798419f1fe0d4323ef Mon Sep 17 00:00:00 2001 From: Ivan Pavluk Date: Thu, 29 Nov 2018 09:19:41 +0700 Subject: [PATCH 12/88] Add license header --- .../Judgements/TaikoDrumRollJudgement.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollJudgement.cs b/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollJudgement.cs index b1ac49b939..48ccdb30e1 100644 --- a/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollJudgement.cs +++ b/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollJudgement.cs @@ -1,11 +1,14 @@ -using osu.Game.Rulesets.Scoring; +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Game.Rulesets.Scoring; namespace osu.Game.Rulesets.Taiko.Judgements { class TaikoDrumRollJudgement : TaikoJudgement { public override bool AffectsCombo => false; - + protected override int NumericResultFor(HitResult result) => 0; } } From ce1e6d93e47947e85487395d076b7754b604713c Mon Sep 17 00:00:00 2001 From: Ivan Pavluk Date: Thu, 29 Nov 2018 09:45:57 +0700 Subject: [PATCH 13/88] Update TaikoScoreProcessor.cs --- osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs b/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs index cf974a6223..a2a0251860 100644 --- a/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs +++ b/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs @@ -80,11 +80,10 @@ namespace osu.Game.Rulesets.Taiko.Scoring { base.ApplyResult(result); - bool isTick = false; bool isRoll = false; bool isStrong = false; + bool isTick = result.Judgement is TaikoDrumRollTickJudgement; - isTick = result.Judgement is TaikoDrumRollTickJudgement; if (!isTick) { isRoll = result.Judgement is TaikoDrumRollJudgement; From a378c5054428d00f0300d09ad2c92813f0a0dd90 Mon Sep 17 00:00:00 2001 From: Ivan Pavluk Date: Thu, 29 Nov 2018 09:47:12 +0700 Subject: [PATCH 14/88] Fix TaikoDrumRollJudgement visibilityy --- osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollJudgement.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollJudgement.cs b/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollJudgement.cs index 48ccdb30e1..8ef98c6dac 100644 --- a/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollJudgement.cs +++ b/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollJudgement.cs @@ -5,7 +5,7 @@ using osu.Game.Rulesets.Scoring; namespace osu.Game.Rulesets.Taiko.Judgements { - class TaikoDrumRollJudgement : TaikoJudgement + public class TaikoDrumRollJudgement : TaikoJudgement { public override bool AffectsCombo => false; From 2ca9864301f1676ce36041d4b27ca6c90bcfe9a6 Mon Sep 17 00:00:00 2001 From: Ivan Pavluk Date: Thu, 29 Nov 2018 22:05:13 +0700 Subject: [PATCH 15/88] Fixed taiko swell hp and scoring --- .../Judgements/TaikoDrumRollJudgement.cs | 2 ++ .../TaikoIntermediateSwellJudgement.cs | 21 ------------- .../Judgements/TaikoJudgement.cs | 5 ++++ .../Judgements/TaikoStrongJudgement.cs | 3 ++ .../Judgements/TaikoSwellJudgement.cs | 14 +++++++++ .../Judgements/TaikoSwellTickJudgement.cs | 25 ++++++++++++++++ .../Objects/Drawables/DrawableSwellTick.cs | 4 +-- osu.Game.Rulesets.Taiko/Objects/Swell.cs | 4 +++ osu.Game.Rulesets.Taiko/Objects/SwellTick.cs | 4 +++ .../Scoring/TaikoScoreProcessor.cs | 30 +++++++------------ 10 files changed, 69 insertions(+), 43 deletions(-) delete mode 100644 osu.Game.Rulesets.Taiko/Judgements/TaikoIntermediateSwellJudgement.cs create mode 100644 osu.Game.Rulesets.Taiko/Judgements/TaikoSwellJudgement.cs create mode 100644 osu.Game.Rulesets.Taiko/Judgements/TaikoSwellTickJudgement.cs diff --git a/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollJudgement.cs b/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollJudgement.cs index 8ef98c6dac..4663d00bdc 100644 --- a/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollJudgement.cs +++ b/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollJudgement.cs @@ -9,6 +9,8 @@ namespace osu.Game.Rulesets.Taiko.Judgements { public override bool AffectsCombo => false; + public override bool AffectsHP => false; + protected override int NumericResultFor(HitResult result) => 0; } } diff --git a/osu.Game.Rulesets.Taiko/Judgements/TaikoIntermediateSwellJudgement.cs b/osu.Game.Rulesets.Taiko/Judgements/TaikoIntermediateSwellJudgement.cs deleted file mode 100644 index 81a1bd1344..0000000000 --- a/osu.Game.Rulesets.Taiko/Judgements/TaikoIntermediateSwellJudgement.cs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) 2007-2018 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using osu.Game.Rulesets.Scoring; - -namespace osu.Game.Rulesets.Taiko.Judgements -{ - public class TaikoIntermediateSwellJudgement : TaikoJudgement - { - public override HitResult MaxResult => HitResult.Great; - - public override bool AffectsCombo => false; - - /// - /// Computes the numeric result value for the combo portion of the score. - /// - /// The result to compute the value for. - /// The numeric result value. - protected override int NumericResultFor(HitResult result) => 0; - } -} diff --git a/osu.Game.Rulesets.Taiko/Judgements/TaikoJudgement.cs b/osu.Game.Rulesets.Taiko/Judgements/TaikoJudgement.cs index 9b1f7a08b5..386495bf1b 100644 --- a/osu.Game.Rulesets.Taiko/Judgements/TaikoJudgement.cs +++ b/osu.Game.Rulesets.Taiko/Judgements/TaikoJudgement.cs @@ -10,6 +10,11 @@ namespace osu.Game.Rulesets.Taiko.Judgements { public override HitResult MaxResult => HitResult.Great; + /// + /// Whether this should affect user's hitpoints. + /// + public virtual bool AffectsHP => true; + /// /// Computes the numeric result value for the combo portion of the score. /// diff --git a/osu.Game.Rulesets.Taiko/Judgements/TaikoStrongJudgement.cs b/osu.Game.Rulesets.Taiko/Judgements/TaikoStrongJudgement.cs index ccfdeb5b0e..2665540d07 100644 --- a/osu.Game.Rulesets.Taiko/Judgements/TaikoStrongJudgement.cs +++ b/osu.Game.Rulesets.Taiko/Judgements/TaikoStrongJudgement.cs @@ -5,6 +5,9 @@ namespace osu.Game.Rulesets.Taiko.Judgements { public class TaikoStrongJudgement : TaikoJudgement { + // MainObject already changes the HP + public override bool AffectsHP => false; + public override bool AffectsCombo => false; } } diff --git a/osu.Game.Rulesets.Taiko/Judgements/TaikoSwellJudgement.cs b/osu.Game.Rulesets.Taiko/Judgements/TaikoSwellJudgement.cs new file mode 100644 index 0000000000..b913f5d730 --- /dev/null +++ b/osu.Game.Rulesets.Taiko/Judgements/TaikoSwellJudgement.cs @@ -0,0 +1,14 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Game.Rulesets.Scoring; + +namespace osu.Game.Rulesets.Taiko.Judgements +{ + public class TaikoSwellJudgement : TaikoJudgement + { + public override bool AffectsCombo => false; + + protected override int NumericResultFor(HitResult result) => 0; + } +} diff --git a/osu.Game.Rulesets.Taiko/Judgements/TaikoSwellTickJudgement.cs b/osu.Game.Rulesets.Taiko/Judgements/TaikoSwellTickJudgement.cs new file mode 100644 index 0000000000..8dd03796ea --- /dev/null +++ b/osu.Game.Rulesets.Taiko/Judgements/TaikoSwellTickJudgement.cs @@ -0,0 +1,25 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Game.Rulesets.Scoring; + +namespace osu.Game.Rulesets.Taiko.Judgements +{ + public class TaikoSwellTickJudgement : TaikoJudgement + { + public override bool AffectsCombo => false; + + public override bool AffectsHP => false; + + protected override int NumericResultFor(HitResult result) + { + switch (result) + { + default: + return 0; + case HitResult.Great: + return 300; + } + } + } +} diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwellTick.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwellTick.cs index 36c468c6d6..0a73474cf3 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwellTick.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwellTick.cs @@ -6,11 +6,11 @@ using osu.Game.Rulesets.Scoring; namespace osu.Game.Rulesets.Taiko.Objects.Drawables { - public class DrawableSwellTick : DrawableTaikoHitObject + public class DrawableSwellTick : DrawableTaikoHitObject { public override bool DisplayResult => false; - public DrawableSwellTick(TaikoHitObject hitObject) + public DrawableSwellTick(SwellTick hitObject) : base(hitObject) { } diff --git a/osu.Game.Rulesets.Taiko/Objects/Swell.cs b/osu.Game.Rulesets.Taiko/Objects/Swell.cs index 702bf63bf5..67e2cae5eb 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Swell.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Swell.cs @@ -3,11 +3,15 @@ using System; using osu.Game.Rulesets.Objects.Types; +using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Taiko.Judgements; namespace osu.Game.Rulesets.Taiko.Objects { public class Swell : TaikoHitObject, IHasEndTime { + public override Judgement CreateJudgement() => new TaikoSwellJudgement(); + public double EndTime => StartTime + Duration; public double Duration { get; set; } diff --git a/osu.Game.Rulesets.Taiko/Objects/SwellTick.cs b/osu.Game.Rulesets.Taiko/Objects/SwellTick.cs index 49eb6d2a15..38f77fa1e7 100644 --- a/osu.Game.Rulesets.Taiko/Objects/SwellTick.cs +++ b/osu.Game.Rulesets.Taiko/Objects/SwellTick.cs @@ -1,9 +1,13 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Taiko.Judgements; + namespace osu.Game.Rulesets.Taiko.Objects { public class SwellTick : TaikoHitObject { + public override Judgement CreateJudgement() => new TaikoSwellTickJudgement(); } } diff --git a/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs b/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs index a2a0251860..06d207695f 100644 --- a/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs +++ b/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs @@ -79,27 +79,15 @@ namespace osu.Game.Rulesets.Taiko.Scoring protected override void ApplyResult(JudgementResult result) { base.ApplyResult(result); + + if (!((TaikoJudgement)result.Judgement).AffectsHP) + return; - bool isRoll = false; - bool isStrong = false; + bool isSwell = false; bool isTick = result.Judgement is TaikoDrumRollTickJudgement; - if (!isTick) - { - isRoll = result.Judgement is TaikoDrumRollJudgement; - if (!isRoll) - { - isStrong = result.Judgement is TaikoStrongJudgement; - } - } - - //Don't change HP based on drum roll fullness for compatibility - if (isRoll) - return; - - //If the object is strong, HP change is already handled in MainObject - if (isStrong) - return; + if(!isTick) + isSwell = result.Judgement is TaikoSwellJudgement; // Apply HP changes switch (result.Type) @@ -110,12 +98,14 @@ namespace osu.Game.Rulesets.Taiko.Scoring Health.Value += hpIncreaseMiss; break; case HitResult.Good: - Health.Value += hpIncreaseGood; + // Swells shouldn't increase HP + if (!isSwell) + Health.Value += hpIncreaseGood; break; case HitResult.Great: if (isTick) Health.Value += hpIncreaseTick; - else + else if(!isSwell) Health.Value += hpIncreaseGreat; break; } From d30ab4f77cdc7a6b0e105438733dde02b0e1a613 Mon Sep 17 00:00:00 2001 From: Ivan Pavluk Date: Thu, 29 Nov 2018 22:12:01 +0700 Subject: [PATCH 16/88] fixed whitespace --- osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs b/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs index 06d207695f..7569edbdb7 100644 --- a/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs +++ b/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs @@ -79,7 +79,7 @@ namespace osu.Game.Rulesets.Taiko.Scoring protected override void ApplyResult(JudgementResult result) { base.ApplyResult(result); - + if (!((TaikoJudgement)result.Judgement).AffectsHP) return; From 13a166a6453714251c920513748cf88440627dc1 Mon Sep 17 00:00:00 2001 From: Ivan Pavluk Date: Thu, 29 Nov 2018 22:26:23 +0700 Subject: [PATCH 17/88] rename TaikoJudgement.AffectsHP to AffectsHp --- osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollJudgement.cs | 2 +- osu.Game.Rulesets.Taiko/Judgements/TaikoJudgement.cs | 2 +- osu.Game.Rulesets.Taiko/Judgements/TaikoStrongJudgement.cs | 2 +- osu.Game.Rulesets.Taiko/Judgements/TaikoSwellTickJudgement.cs | 2 +- osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollJudgement.cs b/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollJudgement.cs index 4663d00bdc..ca81b13053 100644 --- a/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollJudgement.cs +++ b/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollJudgement.cs @@ -9,7 +9,7 @@ namespace osu.Game.Rulesets.Taiko.Judgements { public override bool AffectsCombo => false; - public override bool AffectsHP => false; + public override bool AffectsHp => false; protected override int NumericResultFor(HitResult result) => 0; } diff --git a/osu.Game.Rulesets.Taiko/Judgements/TaikoJudgement.cs b/osu.Game.Rulesets.Taiko/Judgements/TaikoJudgement.cs index 386495bf1b..f4dd90e93b 100644 --- a/osu.Game.Rulesets.Taiko/Judgements/TaikoJudgement.cs +++ b/osu.Game.Rulesets.Taiko/Judgements/TaikoJudgement.cs @@ -13,7 +13,7 @@ namespace osu.Game.Rulesets.Taiko.Judgements /// /// Whether this should affect user's hitpoints. /// - public virtual bool AffectsHP => true; + public virtual bool AffectsHp => true; /// /// Computes the numeric result value for the combo portion of the score. diff --git a/osu.Game.Rulesets.Taiko/Judgements/TaikoStrongJudgement.cs b/osu.Game.Rulesets.Taiko/Judgements/TaikoStrongJudgement.cs index 2665540d07..67b113e795 100644 --- a/osu.Game.Rulesets.Taiko/Judgements/TaikoStrongJudgement.cs +++ b/osu.Game.Rulesets.Taiko/Judgements/TaikoStrongJudgement.cs @@ -6,7 +6,7 @@ namespace osu.Game.Rulesets.Taiko.Judgements public class TaikoStrongJudgement : TaikoJudgement { // MainObject already changes the HP - public override bool AffectsHP => false; + public override bool AffectsHp => false; public override bool AffectsCombo => false; } diff --git a/osu.Game.Rulesets.Taiko/Judgements/TaikoSwellTickJudgement.cs b/osu.Game.Rulesets.Taiko/Judgements/TaikoSwellTickJudgement.cs index 8dd03796ea..8a9a023c22 100644 --- a/osu.Game.Rulesets.Taiko/Judgements/TaikoSwellTickJudgement.cs +++ b/osu.Game.Rulesets.Taiko/Judgements/TaikoSwellTickJudgement.cs @@ -9,7 +9,7 @@ namespace osu.Game.Rulesets.Taiko.Judgements { public override bool AffectsCombo => false; - public override bool AffectsHP => false; + public override bool AffectsHp => false; protected override int NumericResultFor(HitResult result) { diff --git a/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs b/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs index 7569edbdb7..064a7d519b 100644 --- a/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs +++ b/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs @@ -80,7 +80,7 @@ namespace osu.Game.Rulesets.Taiko.Scoring { base.ApplyResult(result); - if (!((TaikoJudgement)result.Judgement).AffectsHP) + if (!((TaikoJudgement)result.Judgement).AffectsHp) return; bool isSwell = false; From 4184f1770939fe303d43ad2aa8a1f4d73744e986 Mon Sep 17 00:00:00 2001 From: Ivan Pavluk Date: Thu, 29 Nov 2018 23:12:02 +0700 Subject: [PATCH 18/88] ...Revert AffectsHP->AffectsHp, add HP abbrev --- osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollJudgement.cs | 2 +- osu.Game.Rulesets.Taiko/Judgements/TaikoJudgement.cs | 2 +- osu.Game.Rulesets.Taiko/Judgements/TaikoStrongJudgement.cs | 2 +- osu.Game.Rulesets.Taiko/Judgements/TaikoSwellTickJudgement.cs | 2 +- osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs | 2 +- osu.sln.DotSettings | 1 + 6 files changed, 6 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollJudgement.cs b/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollJudgement.cs index ca81b13053..4663d00bdc 100644 --- a/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollJudgement.cs +++ b/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollJudgement.cs @@ -9,7 +9,7 @@ namespace osu.Game.Rulesets.Taiko.Judgements { public override bool AffectsCombo => false; - public override bool AffectsHp => false; + public override bool AffectsHP => false; protected override int NumericResultFor(HitResult result) => 0; } diff --git a/osu.Game.Rulesets.Taiko/Judgements/TaikoJudgement.cs b/osu.Game.Rulesets.Taiko/Judgements/TaikoJudgement.cs index f4dd90e93b..386495bf1b 100644 --- a/osu.Game.Rulesets.Taiko/Judgements/TaikoJudgement.cs +++ b/osu.Game.Rulesets.Taiko/Judgements/TaikoJudgement.cs @@ -13,7 +13,7 @@ namespace osu.Game.Rulesets.Taiko.Judgements /// /// Whether this should affect user's hitpoints. /// - public virtual bool AffectsHp => true; + public virtual bool AffectsHP => true; /// /// Computes the numeric result value for the combo portion of the score. diff --git a/osu.Game.Rulesets.Taiko/Judgements/TaikoStrongJudgement.cs b/osu.Game.Rulesets.Taiko/Judgements/TaikoStrongJudgement.cs index 67b113e795..2665540d07 100644 --- a/osu.Game.Rulesets.Taiko/Judgements/TaikoStrongJudgement.cs +++ b/osu.Game.Rulesets.Taiko/Judgements/TaikoStrongJudgement.cs @@ -6,7 +6,7 @@ namespace osu.Game.Rulesets.Taiko.Judgements public class TaikoStrongJudgement : TaikoJudgement { // MainObject already changes the HP - public override bool AffectsHp => false; + public override bool AffectsHP => false; public override bool AffectsCombo => false; } diff --git a/osu.Game.Rulesets.Taiko/Judgements/TaikoSwellTickJudgement.cs b/osu.Game.Rulesets.Taiko/Judgements/TaikoSwellTickJudgement.cs index 8a9a023c22..8dd03796ea 100644 --- a/osu.Game.Rulesets.Taiko/Judgements/TaikoSwellTickJudgement.cs +++ b/osu.Game.Rulesets.Taiko/Judgements/TaikoSwellTickJudgement.cs @@ -9,7 +9,7 @@ namespace osu.Game.Rulesets.Taiko.Judgements { public override bool AffectsCombo => false; - public override bool AffectsHp => false; + public override bool AffectsHP => false; protected override int NumericResultFor(HitResult result) { diff --git a/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs b/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs index 064a7d519b..7569edbdb7 100644 --- a/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs +++ b/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs @@ -80,7 +80,7 @@ namespace osu.Game.Rulesets.Taiko.Scoring { base.ApplyResult(result); - if (!((TaikoJudgement)result.Judgement).AffectsHp) + if (!((TaikoJudgement)result.Judgement).AffectsHP) return; bool isSwell = false; diff --git a/osu.sln.DotSettings b/osu.sln.DotSettings index d6882282e6..38288bc912 100644 --- a/osu.sln.DotSettings +++ b/osu.sln.DotSettings @@ -200,6 +200,7 @@ GL GLSL HID + HP HUD ID IP From 6b07d4581a68f4f933f657e7186eb682eb52fad8 Mon Sep 17 00:00:00 2001 From: Ivan Pavluk Date: Fri, 30 Nov 2018 01:07:15 +0700 Subject: [PATCH 19/88] Fixed too strong HP drain --- osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs b/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs index 7569edbdb7..46706e5977 100644 --- a/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs +++ b/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs @@ -38,7 +38,7 @@ namespace osu.Game.Rulesets.Taiko.Scoring /// The maximum HP deducted for a . /// This occurs when HP Drain = 10. /// - private const double hp_miss_max = -0.12; + private const double hp_miss_max = -0.012; /// /// The HP awarded for a hit. From 743598a1acfe9fea9bd30aaab81d197eaa4b8192 Mon Sep 17 00:00:00 2001 From: Ivan Pavluk Date: Fri, 30 Nov 2018 01:33:04 +0700 Subject: [PATCH 20/88] Decrease taiko swell HP drain --- .../Scoring/TaikoScoreProcessor.cs | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs b/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs index 46706e5977..b791d889ee 100644 --- a/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs +++ b/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs @@ -40,6 +40,25 @@ namespace osu.Game.Rulesets.Taiko.Scoring /// private const double hp_miss_max = -0.012; + + /// + /// The minimum HP deducted for a swell . + /// This occurs when HP Drain = 0. + /// + private const double swell_hp_miss_min = -0.0012; + + /// + /// The median HP deducted for a swell . + /// This occurs when HP Drain = 5. + /// + private const double swell_hp_miss_mid = -0.0045; + + /// + /// The maximum HP deducted for a swell . + /// This occurs when HP Drain = 10. + /// + private const double swell_hp_miss_max = -0.0084; + /// /// The HP awarded for a hit. /// @@ -58,6 +77,7 @@ namespace osu.Game.Rulesets.Taiko.Scoring private double hpIncreaseGreat; private double hpIncreaseGood; private double hpIncreaseMiss; + private double hpIncreaseMissSwell; public TaikoScoreProcessor(RulesetContainer rulesetContainer) : base(rulesetContainer) @@ -74,6 +94,7 @@ namespace osu.Game.Rulesets.Taiko.Scoring hpIncreaseGreat = hpMultiplierNormal * hp_hit_great; hpIncreaseGood = hpMultiplierNormal * hp_hit_good; hpIncreaseMiss = BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.DrainRate, hp_miss_min, hp_miss_mid, hp_miss_max); + hpIncreaseMissSwell = BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.DrainRate, swell_hp_miss_min, swell_hp_miss_mid, swell_hp_miss_max); } protected override void ApplyResult(JudgementResult result) @@ -94,7 +115,9 @@ namespace osu.Game.Rulesets.Taiko.Scoring { case HitResult.Miss: // Missing ticks shouldn't drop HP - if (!isTick) + if (isSwell) + Health.Value += hpIncreaseMissSwell; + else if (!isTick) Health.Value += hpIncreaseMiss; break; case HitResult.Good: From 7d692939fc63e78f4787b552ff2cebc437b1659f Mon Sep 17 00:00:00 2001 From: Ivan Pavluk Date: Tue, 4 Dec 2018 21:20:44 +0700 Subject: [PATCH 21/88] Fixed being able to miss taiko objects by hitting them too early Revamped taiko HP system --- .../Judgements/TaikoDrumRollJudgement.cs | 4 +- .../Judgements/TaikoDrumRollTickJudgement.cs | 11 ++++ .../Judgements/TaikoJudgement.cs | 34 +++++++++--- .../Judgements/TaikoStrongJudgement.cs | 4 +- .../Judgements/TaikoSwellJudgement.cs | 11 +++- .../Judgements/TaikoSwellTickJudgement.cs | 13 +---- .../Objects/Drawables/DrawableHit.cs | 2 +- .../Scoring/TaikoScoreProcessor.cs | 53 +++++-------------- osu.sln.DotSettings | 1 - 9 files changed, 70 insertions(+), 63 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollJudgement.cs b/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollJudgement.cs index 4663d00bdc..e1a630e6b7 100644 --- a/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollJudgement.cs +++ b/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollJudgement.cs @@ -9,8 +9,8 @@ namespace osu.Game.Rulesets.Taiko.Judgements { public override bool AffectsCombo => false; - public override bool AffectsHP => false; - protected override int NumericResultFor(HitResult result) => 0; + + protected override double HealthIncreaseFor(HitResult result) => 0; } } diff --git a/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollTickJudgement.cs b/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollTickJudgement.cs index 446dd0d11b..b2adf45bab 100644 --- a/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollTickJudgement.cs +++ b/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollTickJudgement.cs @@ -19,5 +19,16 @@ namespace osu.Game.Rulesets.Taiko.Judgements return 200; } } + + protected override double HealthIncreaseFor(HitResult result) + { + switch(result) + { + default: + return 0; + case HitResult.Great: + return 0.0000003; + } + } } } diff --git a/osu.Game.Rulesets.Taiko/Judgements/TaikoJudgement.cs b/osu.Game.Rulesets.Taiko/Judgements/TaikoJudgement.cs index 386495bf1b..f43227ecca 100644 --- a/osu.Game.Rulesets.Taiko/Judgements/TaikoJudgement.cs +++ b/osu.Game.Rulesets.Taiko/Judgements/TaikoJudgement.cs @@ -9,12 +9,7 @@ namespace osu.Game.Rulesets.Taiko.Judgements public class TaikoJudgement : Judgement { public override HitResult MaxResult => HitResult.Great; - - /// - /// Whether this should affect user's hitpoints. - /// - public virtual bool AffectsHP => true; - + /// /// Computes the numeric result value for the combo portion of the score. /// @@ -32,5 +27,32 @@ namespace osu.Game.Rulesets.Taiko.Judgements return 300; } } + + /// + /// Retrieves the numeric health increase of a . + /// + /// The to find the numeric health increase for. + /// The numeric health increase of . + protected virtual double HealthIncreaseFor(HitResult result) + { + switch (result) + { + default: + return 0; + case HitResult.Miss: + return -1.0; + case HitResult.Good: + return 1.1; + case HitResult.Great: + return 3.0; + } + } + + /// + /// Retrieves the numeric health increase of a . + /// + /// The to find the numeric health increase for. + /// The numeric health increase of . + public double HealthIncreaseFor(JudgementResult result) => HealthIncreaseFor(result.Type); } } diff --git a/osu.Game.Rulesets.Taiko/Judgements/TaikoStrongJudgement.cs b/osu.Game.Rulesets.Taiko/Judgements/TaikoStrongJudgement.cs index 2665540d07..81dfaf4cc3 100644 --- a/osu.Game.Rulesets.Taiko/Judgements/TaikoStrongJudgement.cs +++ b/osu.Game.Rulesets.Taiko/Judgements/TaikoStrongJudgement.cs @@ -1,12 +1,14 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using osu.Game.Rulesets.Scoring; + namespace osu.Game.Rulesets.Taiko.Judgements { public class TaikoStrongJudgement : TaikoJudgement { // MainObject already changes the HP - public override bool AffectsHP => false; + protected override double HealthIncreaseFor(HitResult result) => 0; public override bool AffectsCombo => false; } diff --git a/osu.Game.Rulesets.Taiko/Judgements/TaikoSwellJudgement.cs b/osu.Game.Rulesets.Taiko/Judgements/TaikoSwellJudgement.cs index b913f5d730..ca89d4d0e5 100644 --- a/osu.Game.Rulesets.Taiko/Judgements/TaikoSwellJudgement.cs +++ b/osu.Game.Rulesets.Taiko/Judgements/TaikoSwellJudgement.cs @@ -9,6 +9,15 @@ namespace osu.Game.Rulesets.Taiko.Judgements { public override bool AffectsCombo => false; - protected override int NumericResultFor(HitResult result) => 0; + protected override double HealthIncreaseFor(HitResult result) + { + switch(result) + { + default: + return 0; + case HitResult.Miss: + return -0.65; + } + } } } diff --git a/osu.Game.Rulesets.Taiko/Judgements/TaikoSwellTickJudgement.cs b/osu.Game.Rulesets.Taiko/Judgements/TaikoSwellTickJudgement.cs index 8dd03796ea..448c16dad6 100644 --- a/osu.Game.Rulesets.Taiko/Judgements/TaikoSwellTickJudgement.cs +++ b/osu.Game.Rulesets.Taiko/Judgements/TaikoSwellTickJudgement.cs @@ -9,17 +9,8 @@ namespace osu.Game.Rulesets.Taiko.Judgements { public override bool AffectsCombo => false; - public override bool AffectsHP => false; + protected override int NumericResultFor(HitResult result) => 0; - protected override int NumericResultFor(HitResult result) - { - switch (result) - { - default: - return 0; - case HitResult.Great: - return 300; - } - } + protected override double HealthIncreaseFor(HitResult result) => 0; } } diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs index 48731388cb..8c19e64de6 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs @@ -42,7 +42,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables } var result = HitObject.HitWindows.ResultFor(timeOffset); - if (result == HitResult.None) + if (result <= HitResult.Miss) return; if (!validActionPressed) diff --git a/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs b/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs index b791d889ee..50989cef7c 100644 --- a/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs +++ b/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs @@ -73,11 +73,8 @@ namespace osu.Game.Rulesets.Taiko.Scoring /// protected override bool DefaultFailCondition => JudgedHits == MaxHits && Health.Value <= 0.5; - private double hpIncreaseTick; - private double hpIncreaseGreat; - private double hpIncreaseGood; - private double hpIncreaseMiss; - private double hpIncreaseMissSwell; + private double hpMultiplier; + private double hpMissMultiplier; public TaikoScoreProcessor(RulesetContainer rulesetContainer) : base(rulesetContainer) @@ -88,49 +85,25 @@ namespace osu.Game.Rulesets.Taiko.Scoring { base.ApplyBeatmap(beatmap); - double hpMultiplierNormal = 1 / (hp_hit_great * beatmap.HitObjects.FindAll(o => o is Hit).Count * BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.DrainRate, 0.5, 0.75, 0.98)); + hpMultiplier = 0.01 / (hp_hit_great * beatmap.HitObjects.FindAll(o => o is Hit).Count * BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.DrainRate, 0.5, 0.75, 0.98)); - hpIncreaseTick = hp_hit_tick; - hpIncreaseGreat = hpMultiplierNormal * hp_hit_great; - hpIncreaseGood = hpMultiplierNormal * hp_hit_good; - hpIncreaseMiss = BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.DrainRate, hp_miss_min, hp_miss_mid, hp_miss_max); - hpIncreaseMissSwell = BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.DrainRate, swell_hp_miss_min, swell_hp_miss_mid, swell_hp_miss_max); + hpMissMultiplier = BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.DrainRate, 0.0018, 0.0075, 0.0120); } protected override void ApplyResult(JudgementResult result) { base.ApplyResult(result); - if (!((TaikoJudgement)result.Judgement).AffectsHP) - return; - - bool isSwell = false; - bool isTick = result.Judgement is TaikoDrumRollTickJudgement; - - if(!isTick) - isSwell = result.Judgement is TaikoSwellJudgement; - - // Apply HP changes - switch (result.Type) + if (result.Judgement is TaikoJudgement taikoJudgement) { - case HitResult.Miss: - // Missing ticks shouldn't drop HP - if (isSwell) - Health.Value += hpIncreaseMissSwell; - else if (!isTick) - Health.Value += hpIncreaseMiss; - break; - case HitResult.Good: - // Swells shouldn't increase HP - if (!isSwell) - Health.Value += hpIncreaseGood; - break; - case HitResult.Great: - if (isTick) - Health.Value += hpIncreaseTick; - else if(!isSwell) - Health.Value += hpIncreaseGreat; - break; + double hpIncrease = taikoJudgement.HealthIncreaseFor(result); + + if (result.Type == HitResult.Miss) + hpIncrease *= hpMissMultiplier; + else + hpIncrease *= hpMultiplier; + + Health.Value += hpIncrease; } } diff --git a/osu.sln.DotSettings b/osu.sln.DotSettings index 38288bc912..d6882282e6 100644 --- a/osu.sln.DotSettings +++ b/osu.sln.DotSettings @@ -200,7 +200,6 @@ GL GLSL HID - HP HUD ID IP From 1975e11fcc8b075044c3f03f1fd3d2bf949136d2 Mon Sep 17 00:00:00 2001 From: Ivan Pavluk Date: Tue, 4 Dec 2018 21:28:36 +0700 Subject: [PATCH 22/88] Yet Another Whitespace Fix --- osu.Game.Rulesets.Taiko/Judgements/TaikoJudgement.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/Judgements/TaikoJudgement.cs b/osu.Game.Rulesets.Taiko/Judgements/TaikoJudgement.cs index f43227ecca..244a00ffb9 100644 --- a/osu.Game.Rulesets.Taiko/Judgements/TaikoJudgement.cs +++ b/osu.Game.Rulesets.Taiko/Judgements/TaikoJudgement.cs @@ -9,7 +9,7 @@ namespace osu.Game.Rulesets.Taiko.Judgements public class TaikoJudgement : Judgement { public override HitResult MaxResult => HitResult.Great; - + /// /// Computes the numeric result value for the combo portion of the score. /// From f2b806d3033509adedddaf57a130969297f299d3 Mon Sep 17 00:00:00 2001 From: Ivan Pavluk Date: Tue, 4 Dec 2018 21:36:43 +0700 Subject: [PATCH 23/88] Remove swell miss HP from TaikoScoreProcessor --- .../Scoring/TaikoScoreProcessor.cs | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs b/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs index 50989cef7c..40e7f3e12e 100644 --- a/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs +++ b/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs @@ -41,24 +41,6 @@ namespace osu.Game.Rulesets.Taiko.Scoring private const double hp_miss_max = -0.012; - /// - /// The minimum HP deducted for a swell . - /// This occurs when HP Drain = 0. - /// - private const double swell_hp_miss_min = -0.0012; - - /// - /// The median HP deducted for a swell . - /// This occurs when HP Drain = 5. - /// - private const double swell_hp_miss_mid = -0.0045; - - /// - /// The maximum HP deducted for a swell . - /// This occurs when HP Drain = 10. - /// - private const double swell_hp_miss_max = -0.0084; - /// /// The HP awarded for a hit. /// From 6c38db04eed786f67ffc1048073267c5351500d7 Mon Sep 17 00:00:00 2001 From: Ivan Pavluk Date: Tue, 4 Dec 2018 21:48:22 +0700 Subject: [PATCH 24/88] Fix switch statement order in taiko judgements --- .../Judgements/TaikoDrumRollTickJudgement.cs | 4 ++-- osu.Game.Rulesets.Taiko/Judgements/TaikoJudgement.cs | 4 ++-- osu.Game.Rulesets.Taiko/Judgements/TaikoSwellJudgement.cs | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollTickJudgement.cs b/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollTickJudgement.cs index b2adf45bab..0ccc66877c 100644 --- a/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollTickJudgement.cs +++ b/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollTickJudgement.cs @@ -24,10 +24,10 @@ namespace osu.Game.Rulesets.Taiko.Judgements { switch(result) { - default: - return 0; case HitResult.Great: return 0.0000003; + default: + return 0; } } } diff --git a/osu.Game.Rulesets.Taiko/Judgements/TaikoJudgement.cs b/osu.Game.Rulesets.Taiko/Judgements/TaikoJudgement.cs index 244a00ffb9..c3b603746b 100644 --- a/osu.Game.Rulesets.Taiko/Judgements/TaikoJudgement.cs +++ b/osu.Game.Rulesets.Taiko/Judgements/TaikoJudgement.cs @@ -19,12 +19,12 @@ namespace osu.Game.Rulesets.Taiko.Judgements { switch (result) { - default: - return 0; case HitResult.Good: return 100; case HitResult.Great: return 300; + default: + return 0; } } diff --git a/osu.Game.Rulesets.Taiko/Judgements/TaikoSwellJudgement.cs b/osu.Game.Rulesets.Taiko/Judgements/TaikoSwellJudgement.cs index ca89d4d0e5..7c525bba6c 100644 --- a/osu.Game.Rulesets.Taiko/Judgements/TaikoSwellJudgement.cs +++ b/osu.Game.Rulesets.Taiko/Judgements/TaikoSwellJudgement.cs @@ -13,10 +13,10 @@ namespace osu.Game.Rulesets.Taiko.Judgements { switch(result) { - default: - return 0; case HitResult.Miss: return -0.65; + default: + return 0; } } } From 6d7e71c003f6efb9fc79e740d9723b115f819d2a Mon Sep 17 00:00:00 2001 From: Ivan Pavluk Date: Wed, 5 Dec 2018 16:28:36 +0700 Subject: [PATCH 25/88] Fix switch stetement order 2 --- .../Judgements/TaikoDrumRollTickJudgement.cs | 4 ++-- osu.Game.Rulesets.Taiko/Judgements/TaikoJudgement.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollTickJudgement.cs b/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollTickJudgement.cs index 0ccc66877c..c2675a7fac 100644 --- a/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollTickJudgement.cs +++ b/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollTickJudgement.cs @@ -13,10 +13,10 @@ namespace osu.Game.Rulesets.Taiko.Judgements { switch (result) { - default: - return 0; case HitResult.Great: return 200; + default: + return 0; } } diff --git a/osu.Game.Rulesets.Taiko/Judgements/TaikoJudgement.cs b/osu.Game.Rulesets.Taiko/Judgements/TaikoJudgement.cs index c3b603746b..bbdc14c6d4 100644 --- a/osu.Game.Rulesets.Taiko/Judgements/TaikoJudgement.cs +++ b/osu.Game.Rulesets.Taiko/Judgements/TaikoJudgement.cs @@ -37,14 +37,14 @@ namespace osu.Game.Rulesets.Taiko.Judgements { switch (result) { - default: - return 0; case HitResult.Miss: return -1.0; case HitResult.Good: return 1.1; case HitResult.Great: return 3.0; + default: + return 0; } } From 68745b221e8f707b16f02cd86f21d239e45ddb9c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 5 Dec 2018 19:46:07 +0900 Subject: [PATCH 26/88] Update projects to target .NET core 2.2 --- osu.Desktop/osu.Desktop.csproj | 2 +- .../osu.Game.Rulesets.Catch.Tests.csproj | 2 +- .../osu.Game.Rulesets.Mania.Tests.csproj | 2 +- osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj | 2 +- .../osu.Game.Rulesets.Taiko.Tests.csproj | 2 +- osu.Game.Tests/osu.Game.Tests.csproj | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Desktop/osu.Desktop.csproj b/osu.Desktop/osu.Desktop.csproj index 09bfdc67d4..6b5fe501a7 100644 --- a/osu.Desktop/osu.Desktop.csproj +++ b/osu.Desktop/osu.Desktop.csproj @@ -1,7 +1,7 @@  - netcoreapp2.1 + netcoreapp2.2 WinExe AnyCPU true diff --git a/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj b/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj index b76f591239..21afc4141d 100644 --- a/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj +++ b/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj @@ -9,7 +9,7 @@ WinExe - netcoreapp2.1 + netcoreapp2.2 diff --git a/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj b/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj index 98ad086c66..c835b01b1c 100644 --- a/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj +++ b/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj @@ -9,7 +9,7 @@ WinExe - netcoreapp2.1 + netcoreapp2.2 diff --git a/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj b/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj index 6117812f45..84086a7c4d 100644 --- a/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj +++ b/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj @@ -9,7 +9,7 @@ WinExe - netcoreapp2.1 + netcoreapp2.2 diff --git a/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj b/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj index 3ba64398f3..36caae39c8 100644 --- a/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj +++ b/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj @@ -9,7 +9,7 @@ WinExe - netcoreapp2.1 + netcoreapp2.2 diff --git a/osu.Game.Tests/osu.Game.Tests.csproj b/osu.Game.Tests/osu.Game.Tests.csproj index c0f0695ff8..5387f209e3 100644 --- a/osu.Game.Tests/osu.Game.Tests.csproj +++ b/osu.Game.Tests/osu.Game.Tests.csproj @@ -10,7 +10,7 @@ WinExe - netcoreapp2.1 + netcoreapp2.2 From dbc33c45a63524b4c676215b18e9426d1b123f8d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 6 Dec 2018 00:14:21 +0900 Subject: [PATCH 27/88] Update nuget packages --- osu.Desktop/osu.Desktop.csproj | 4 ++-- .../osu.Game.Rulesets.Catch.Tests.csproj | 2 +- .../osu.Game.Rulesets.Mania.Tests.csproj | 2 +- .../osu.Game.Rulesets.Osu.Tests.csproj | 2 +- .../osu.Game.Rulesets.Taiko.Tests.csproj | 2 +- osu.Game.Tests/osu.Game.Tests.csproj | 4 ++-- osu.Game/osu.Game.csproj | 6 +++--- 7 files changed, 11 insertions(+), 11 deletions(-) diff --git a/osu.Desktop/osu.Desktop.csproj b/osu.Desktop/osu.Desktop.csproj index 6b5fe501a7..ad08f57c3a 100644 --- a/osu.Desktop/osu.Desktop.csproj +++ b/osu.Desktop/osu.Desktop.csproj @@ -28,8 +28,8 @@ - - + + diff --git a/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj b/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj index 21afc4141d..e875af5a30 100644 --- a/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj +++ b/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj @@ -4,7 +4,7 @@ - + diff --git a/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj b/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj index c835b01b1c..0c6fbfa7d3 100644 --- a/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj +++ b/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj @@ -4,7 +4,7 @@ - + diff --git a/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj b/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj index 84086a7c4d..35f137572d 100644 --- a/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj +++ b/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj @@ -4,7 +4,7 @@ - + diff --git a/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj b/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj index 36caae39c8..0fc01deed6 100644 --- a/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj +++ b/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj @@ -4,7 +4,7 @@ - + diff --git a/osu.Game.Tests/osu.Game.Tests.csproj b/osu.Game.Tests/osu.Game.Tests.csproj index 5387f209e3..6b751db9e6 100644 --- a/osu.Game.Tests/osu.Game.Tests.csproj +++ b/osu.Game.Tests/osu.Game.Tests.csproj @@ -2,10 +2,10 @@ - + - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 85eabb0350..30fb02b306 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -14,10 +14,10 @@ - + - - + + From b5277de3f4e5dfeb16bb7806b9a3c6b2350ad58a Mon Sep 17 00:00:00 2001 From: Ivan Pavluk Date: Thu, 6 Dec 2018 14:08:32 +0700 Subject: [PATCH 28/88] Remove extra newline --- osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs b/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs index 40e7f3e12e..84f87bf10c 100644 --- a/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs +++ b/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs @@ -40,7 +40,6 @@ namespace osu.Game.Rulesets.Taiko.Scoring /// private const double hp_miss_max = -0.012; - /// /// The HP awarded for a hit. /// From 1b6658f4eefac3454ff49a6c3f2007285ceacbe2 Mon Sep 17 00:00:00 2001 From: Ivan Pavluk Date: Thu, 6 Dec 2018 15:09:42 +0700 Subject: [PATCH 29/88] Move HealthIncreaseFor to Judgement --- .../Judgements/CatchBananaJudgement.cs | 2 +- .../Judgements/CatchDropletJudgement.cs | 2 +- .../Judgements/CatchJudgement.cs | 9 +-------- .../Judgements/CatchTinyDropletJudgement.cs | 2 +- .../Judgements/TaikoDrumRollJudgement.cs | 14 +++++++++++--- .../Judgements/TaikoDrumRollTickJudgement.cs | 2 +- .../Judgements/TaikoJudgement.cs | 19 +------------------ osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs | 4 ++-- osu.Game.Rulesets.Taiko/Objects/Swell.cs | 4 ++-- osu.Game/Rulesets/Judgements/Judgement.cs | 14 ++++++++++++++ 10 files changed, 35 insertions(+), 37 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Judgements/CatchBananaJudgement.cs b/osu.Game.Rulesets.Catch/Judgements/CatchBananaJudgement.cs index f38009263f..d89d987f95 100644 --- a/osu.Game.Rulesets.Catch/Judgements/CatchBananaJudgement.cs +++ b/osu.Game.Rulesets.Catch/Judgements/CatchBananaJudgement.cs @@ -21,7 +21,7 @@ namespace osu.Game.Rulesets.Catch.Judgements } } - protected override float HealthIncreaseFor(HitResult result) + protected override double HealthIncreaseFor(HitResult result) { switch (result) { diff --git a/osu.Game.Rulesets.Catch/Judgements/CatchDropletJudgement.cs b/osu.Game.Rulesets.Catch/Judgements/CatchDropletJudgement.cs index 0df2305339..1fbf1db7f7 100644 --- a/osu.Game.Rulesets.Catch/Judgements/CatchDropletJudgement.cs +++ b/osu.Game.Rulesets.Catch/Judgements/CatchDropletJudgement.cs @@ -18,7 +18,7 @@ namespace osu.Game.Rulesets.Catch.Judgements } } - protected override float HealthIncreaseFor(HitResult result) + protected override double HealthIncreaseFor(HitResult result) { switch (result) { diff --git a/osu.Game.Rulesets.Catch/Judgements/CatchJudgement.cs b/osu.Game.Rulesets.Catch/Judgements/CatchJudgement.cs index 8a51867899..30ba868f6e 100644 --- a/osu.Game.Rulesets.Catch/Judgements/CatchJudgement.cs +++ b/osu.Game.Rulesets.Catch/Judgements/CatchJudgement.cs @@ -27,7 +27,7 @@ namespace osu.Game.Rulesets.Catch.Judgements /// /// The to find the numeric health increase for. /// The numeric health increase of . - protected virtual float HealthIncreaseFor(HitResult result) + protected override double HealthIncreaseFor(HitResult result) { switch (result) { @@ -38,13 +38,6 @@ namespace osu.Game.Rulesets.Catch.Judgements } } - /// - /// Retrieves the numeric health increase of a . - /// - /// The to find the numeric health increase for. - /// The numeric health increase of . - public float HealthIncreaseFor(JudgementResult result) => HealthIncreaseFor(result.Type); - /// /// Whether fruit on the platter should explode or drop. /// Note that this is only checked if the owning object is also diff --git a/osu.Game.Rulesets.Catch/Judgements/CatchTinyDropletJudgement.cs b/osu.Game.Rulesets.Catch/Judgements/CatchTinyDropletJudgement.cs index 8b77351027..fc933020d3 100644 --- a/osu.Game.Rulesets.Catch/Judgements/CatchTinyDropletJudgement.cs +++ b/osu.Game.Rulesets.Catch/Judgements/CatchTinyDropletJudgement.cs @@ -20,7 +20,7 @@ namespace osu.Game.Rulesets.Catch.Judgements } } - protected override float HealthIncreaseFor(HitResult result) + protected override double HealthIncreaseFor(HitResult result) { switch (result) { diff --git a/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollJudgement.cs b/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollJudgement.cs index e1a630e6b7..b3a64cd579 100644 --- a/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollJudgement.cs +++ b/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollJudgement.cs @@ -9,8 +9,16 @@ namespace osu.Game.Rulesets.Taiko.Judgements { public override bool AffectsCombo => false; - protected override int NumericResultFor(HitResult result) => 0; - - protected override double HealthIncreaseFor(HitResult result) => 0; + protected override double HealthIncreaseFor(HitResult result) + { + //Drum rolls can be ignored with no health penalty + switch (result) + { + case HitResult.Miss: + return 0; + default: + return base.HealthIncreaseFor(result); + } + } } } diff --git a/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollTickJudgement.cs b/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollTickJudgement.cs index c2675a7fac..86b495ca08 100644 --- a/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollTickJudgement.cs +++ b/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollTickJudgement.cs @@ -25,7 +25,7 @@ namespace osu.Game.Rulesets.Taiko.Judgements switch(result) { case HitResult.Great: - return 0.0000003; + return 0.15; default: return 0; } diff --git a/osu.Game.Rulesets.Taiko/Judgements/TaikoJudgement.cs b/osu.Game.Rulesets.Taiko/Judgements/TaikoJudgement.cs index bbdc14c6d4..4f397cda09 100644 --- a/osu.Game.Rulesets.Taiko/Judgements/TaikoJudgement.cs +++ b/osu.Game.Rulesets.Taiko/Judgements/TaikoJudgement.cs @@ -10,11 +10,6 @@ namespace osu.Game.Rulesets.Taiko.Judgements { public override HitResult MaxResult => HitResult.Great; - /// - /// Computes the numeric result value for the combo portion of the score. - /// - /// The result to compute the value for. - /// The numeric result value. protected override int NumericResultFor(HitResult result) { switch (result) @@ -28,12 +23,7 @@ namespace osu.Game.Rulesets.Taiko.Judgements } } - /// - /// Retrieves the numeric health increase of a . - /// - /// The to find the numeric health increase for. - /// The numeric health increase of . - protected virtual double HealthIncreaseFor(HitResult result) + protected override double HealthIncreaseFor(HitResult result) { switch (result) { @@ -47,12 +37,5 @@ namespace osu.Game.Rulesets.Taiko.Judgements return 0; } } - - /// - /// Retrieves the numeric health increase of a . - /// - /// The to find the numeric health increase for. - /// The numeric health increase of . - public double HealthIncreaseFor(JudgementResult result) => HealthIncreaseFor(result.Type); } } diff --git a/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs b/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs index 0dc460643a..89d0512e9c 100644 --- a/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs +++ b/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs @@ -12,8 +12,6 @@ namespace osu.Game.Rulesets.Taiko.Objects { public class DrumRoll : TaikoHitObject, IHasEndTime { - public override Judgement CreateJudgement() => new TaikoDrumRollJudgement(); - /// /// Drum roll distance that results in a duration of 1 speed-adjusted beat length. /// @@ -85,5 +83,7 @@ namespace osu.Game.Rulesets.Taiko.Objects first = false; } } + + public override Judgement CreateJudgement() => new TaikoDrumRollJudgement(); } } diff --git a/osu.Game.Rulesets.Taiko/Objects/Swell.cs b/osu.Game.Rulesets.Taiko/Objects/Swell.cs index 67e2cae5eb..68433429c6 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Swell.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Swell.cs @@ -10,8 +10,6 @@ namespace osu.Game.Rulesets.Taiko.Objects { public class Swell : TaikoHitObject, IHasEndTime { - public override Judgement CreateJudgement() => new TaikoSwellJudgement(); - public double EndTime => StartTime + Duration; public double Duration { get; set; } @@ -30,5 +28,7 @@ namespace osu.Game.Rulesets.Taiko.Objects for (int i = 0; i < RequiredHits; i++) AddNested(new SwellTick()); } + + public override Judgement CreateJudgement() => new TaikoSwellJudgement(); } } diff --git a/osu.Game/Rulesets/Judgements/Judgement.cs b/osu.Game/Rulesets/Judgements/Judgement.cs index c679df5900..86a41a08ff 100644 --- a/osu.Game/Rulesets/Judgements/Judgement.cs +++ b/osu.Game/Rulesets/Judgements/Judgement.cs @@ -44,5 +44,19 @@ namespace osu.Game.Rulesets.Judgements /// The to find the numeric score representation for. /// The numeric score representation of . public int NumericResultFor(JudgementResult result) => NumericResultFor(result.Type); + + /// + /// Retrieves the numeric health increase of a . + /// + /// The to find the numeric health increase for. + /// The numeric health increase of . + protected virtual double HealthIncreaseFor(HitResult result) => 0; + + /// + /// Retrieves the numeric health increase of a . + /// + /// The to find the numeric health increase for. + /// The numeric health increase of . + public double HealthIncreaseFor(JudgementResult result) => HealthIncreaseFor(result.Type); } } From 8cae549541ee4f3d53c6cd1bdd7279c247844230 Mon Sep 17 00:00:00 2001 From: Ivan Pavluk Date: Thu, 6 Dec 2018 15:58:03 +0700 Subject: [PATCH 30/88] Remove unused TaikoScoreProcessor constants --- .../Scoring/TaikoScoreProcessor.cs | 32 ------------------- 1 file changed, 32 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs b/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs index 84f87bf10c..721d435780 100644 --- a/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs +++ b/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs @@ -17,38 +17,6 @@ namespace osu.Game.Rulesets.Taiko.Scoring /// private const double hp_hit_great = 0.03; - /// - /// The HP awarded for a hit. - /// - private const double hp_hit_good = 0.011; - - /// - /// The minimum HP deducted for a . - /// This occurs when HP Drain = 0. - /// - private const double hp_miss_min = -0.0018; - - /// - /// The median HP deducted for a . - /// This occurs when HP Drain = 5. - /// - private const double hp_miss_mid = -0.0075; - - /// - /// The maximum HP deducted for a . - /// This occurs when HP Drain = 10. - /// - private const double hp_miss_max = -0.012; - - /// - /// The HP awarded for a hit. - /// - /// hits award less HP as they're more spammable, although in hindsight - /// this probably awards too little HP and is kept at this value for now for compatibility. - /// - /// - private const double hp_hit_tick = 0.00000003; - /// /// Taiko fails at the end of the map if the player has not half-filled their HP bar. /// From 10b526504aa230642b5b7c708431126d8e142118 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 6 Dec 2018 19:29:18 +0900 Subject: [PATCH 31/88] Move ModOverlay to SongSelect --- osu.Game/Screens/Select/PlaySongSelect.cs | 21 +-------------------- osu.Game/Screens/Select/SongSelect.cs | 23 ++++++++++++++++++++++- 2 files changed, 23 insertions(+), 21 deletions(-) diff --git a/osu.Game/Screens/Select/PlaySongSelect.cs b/osu.Game/Screens/Select/PlaySongSelect.cs index 0e3dfcf284..8d37da0377 100644 --- a/osu.Game/Screens/Select/PlaySongSelect.cs +++ b/osu.Game/Screens/Select/PlaySongSelect.cs @@ -9,12 +9,10 @@ using osu.Framework.Audio; using osu.Framework.Audio.Sample; using osu.Framework.Configuration; using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; using osu.Framework.Screens; using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Overlays; -using osu.Game.Overlays.Mods; using osu.Game.Rulesets.Mods; using osu.Game.Screens.Play; using osu.Game.Screens.Ranking; @@ -25,19 +23,11 @@ namespace osu.Game.Screens.Select public class PlaySongSelect : SongSelect { private OsuScreen player; - private readonly ModSelectOverlay modSelect; protected readonly BeatmapDetailArea BeatmapDetails; private bool removeAutoModOnResume; public PlaySongSelect() { - FooterPanels.Add(modSelect = new ModSelectOverlay - { - RelativeSizeAxes = Axes.X, - Origin = Anchor.BottomCentre, - Anchor = Anchor.BottomCentre, - }); - LeftContent.Add(BeatmapDetails = new BeatmapDetailArea { RelativeSizeAxes = Axes.Both, @@ -60,8 +50,6 @@ namespace osu.Game.Screens.Select sampleConfirm = audio.Sample.Get(@"SongSelect/confirm-selection"); - Footer.AddButton(@"mods", colours.Yellow, modSelect, Key.F1, float.MaxValue); - BeatmapOptions.AddButton(@"Remove", @"from unplayed", FontAwesome.fa_times_circle_o, colours.Purple, null, Key.Number1); BeatmapOptions.AddButton(@"Clear", @"local scores", FontAwesome.fa_eraser, colours.Purple, null, Key.Number2); BeatmapOptions.AddButton(@"Edit", @"beatmap", FontAwesome.fa_pencil, colours.Yellow, () => @@ -115,7 +103,7 @@ namespace osu.Game.Screens.Select if (removeAutoModOnResume) { var autoType = Ruleset.Value.CreateInstance().GetAutoplayMod().GetType(); - modSelect.DeselectTypes(new[] { autoType }, true); + ModSelect.DeselectTypes(new[] { autoType }, true); removeAutoModOnResume = false; } @@ -126,13 +114,6 @@ namespace osu.Game.Screens.Select base.OnResuming(last); } - protected override void OnSuspending(Screen next) - { - modSelect.Hide(); - - base.OnSuspending(next); - } - protected override bool OnExiting(Screen next) { if (base.OnExiting(next)) diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 66540c6900..c7e999f7c7 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -21,6 +21,7 @@ using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Input.Bindings; using osu.Game.Overlays; +using osu.Game.Overlays.Mods; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Screens.Backgrounds; @@ -67,6 +68,8 @@ namespace osu.Game.Screens.Select private DialogOverlay dialogOverlay; private BeatmapManager beatmaps; + protected readonly ModSelectOverlay ModSelect; + private SampleChannel sampleChangeDifficulty; private SampleChannel sampleChangeBeatmap; @@ -194,7 +197,16 @@ namespace osu.Game.Screens.Select OnBack = ExitFromBack, }); - FooterPanels.Add(BeatmapOptions = new BeatmapOptionsOverlay()); + FooterPanels.AddRange(new Drawable[] + { + BeatmapOptions = new BeatmapOptionsOverlay(), + ModSelect = new ModSelectOverlay + { + RelativeSizeAxes = Axes.X, + Origin = Anchor.BottomCentre, + Anchor = Anchor.BottomCentre, + } + }); } } @@ -205,6 +217,7 @@ namespace osu.Game.Screens.Select { if (Footer != null) { + Footer.AddButton(@"mods", colours.Yellow, ModSelect, Key.F1); Footer.AddButton(@"random", colours.Green, triggerRandom, Key.F2); Footer.AddButton(@"options", colours.Blue, BeatmapOptions, Key.F3); @@ -438,6 +451,8 @@ namespace osu.Game.Screens.Select protected override void OnSuspending(Screen next) { + ModSelect.Hide(); + Content.ScaleTo(1.1f, 250, Easing.InSine); Content.FadeOut(250); @@ -448,6 +463,12 @@ namespace osu.Game.Screens.Select protected override bool OnExiting(Screen next) { + if (ModSelect.State == Visibility.Visible) + { + ModSelect.Hide(); + return true; + } + FinaliseSelection(performStartAction: false); beatmapInfoWedge.State = Visibility.Hidden; From 46b98702e1ce0149e6c0e70e1b8325559f644488 Mon Sep 17 00:00:00 2001 From: WebFreak001 Date: Thu, 6 Dec 2018 12:48:11 +0100 Subject: [PATCH 32/88] make target animation call more obvious --- osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs | 2 +- .../Objects/Drawables/DrawableOsuBlinds.cs | 18 ++++++++---------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs index 9f33653bc7..cfdc63a57e 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs @@ -31,7 +31,7 @@ namespace osu.Game.Rulesets.Osu.Mods public override void ApplyToScoreProcessor(ScoreProcessor scoreProcessor) { scoreProcessor.Health.ValueChanged += val => { - flashlight.Value = (float)val; + flashlight.AnimateTarget((float)val); }; scoreProcessor.Combo.ValueChanged += val => { if (val > 0 && val % 30 == 0) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuBlinds.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuBlinds.cs index 7e72c5c7bb..eb725e09db 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuBlinds.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuBlinds.cs @@ -305,17 +305,15 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables /// /// Health between 0 and 1 for the blinds to base the width on. Will get animated for 200ms using out-quintic easing. /// - public float Value + public void AnimateTarget(float value) { - set - { - target = value; - this.TransformTo(nameof(easing), target, 200, Easing.OutQuint); - } - get - { - return target; - } + target = value; + this.TransformTo(nameof(easing), target, 200, Easing.OutQuint); + } + + public float Target + { + get => target; } public Texture PanelTexture From a14de5bd1b9a3b38102cf5e8a060184ddbedc1af Mon Sep 17 00:00:00 2001 From: WebFreak001 Date: Thu, 6 Dec 2018 12:52:39 +0100 Subject: [PATCH 33/88] Remove blinds random NPC --- osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs | 4 - .../Objects/Drawables/DrawableOsuBlinds.cs | 92 ------------------- 2 files changed, 96 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs index cfdc63a57e..a9379c9133 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs @@ -33,10 +33,6 @@ namespace osu.Game.Rulesets.Osu.Mods scoreProcessor.Health.ValueChanged += val => { flashlight.AnimateTarget((float)val); }; - scoreProcessor.Combo.ValueChanged += val => { - if (val > 0 && val % 30 == 0) - flashlight.TriggerNpc(); - }; } } } diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuBlinds.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuBlinds.cs index eb725e09db..df7006da1d 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuBlinds.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuBlinds.cs @@ -12,7 +12,6 @@ using osu.Game.Skinning; using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; using osuTK; using osuTK.Graphics; -using System; namespace osu.Game.Rulesets.Osu.Objects.Drawables { @@ -28,14 +27,11 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables private Sprite panelLeft, panelRight; private Sprite bgPanelLeft, bgPanelRight; - private Drawable bgRandomNpc; - private Drawable randomNpc; private const float npc_movement_start = 1.5f; private float npcPosition = npc_movement_start; private bool animatingBlinds; private readonly Beatmap beatmap; - private Random random; private ISkinSource skin; @@ -122,36 +118,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables Depth = fg_panel_depth }); - // seed with unique seed per map so NPC always comes from the same sides for a same map for reproducible replays. - random = new Random(beatmap.Metadata.ToString().GetHashCode()); - Add(bgRandomNpc = new Box - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Colour = Color4.Black, - Width = 512 * 0.4f, - Height = 512 * 0.95f, - RelativePositionAxes = Axes.Y, - X = -512, - Y = 0, - Depth = black_depth, - Alpha = 0 - }); - Add(new SkinnableDrawable("Play/Catch/fruit-catcher-idle", name => randomNpc = new Sprite - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Texture = textures.Get(name), - Width = 512, - Height = 512, - RelativePositionAxes = Axes.Y, - X = -512, - Y = 0, - Alpha = 0 - }) { - Depth = npc_depth - }); - this.skin = skin; skin.SourceChanged += skinChanged; PanelTexture = textures.Get("Play/osu/blinds-panel"); @@ -205,11 +171,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables panelRight.X = end - width; bgPanelLeft.X = start; bgPanelRight.X = end; - - float adjustedNpcPosition = npcPosition * rawWidth; - if (randomNpc != null) - randomNpc.X = adjustedNpcPosition; - bgRandomNpc.X = adjustedNpcPosition; } protected override void LoadComplete() @@ -249,59 +210,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables this.TransformTo(nameof(targetBreakMultiplier), 1f, 2500, Easing.OutBounce); } - public void TriggerNpc() - { - if (animatingBlinds) - return; - - bool left = (random.Next() & 1) != 0; - bool exit = (random.Next() & 1) != 0; - float start, end; - - if (left) - { - start = -npc_movement_start; - end = npc_movement_start; - - randomNpc.Scale = new Vector2(1, 1); - } - else - { - start = npc_movement_start; - end = -npc_movement_start; - - randomNpc.Scale = new Vector2(-1, 1); - } - - // depths for exit from the left and entry from the right - if (left == exit) - { - ChangeChildDepth(bgPanelLeft, fg_panel_depth + 1); - ChangeChildDepth(panelLeft, fg_panel_depth); - - ChangeChildDepth(bgPanelRight, bg_panel_depth + 1); - ChangeChildDepth(panelRight, bg_panel_depth); - } - else // depths for entry from the left or exit from the right - { - ChangeChildDepth(bgPanelLeft, bg_panel_depth + 1); - ChangeChildDepth(panelLeft, bg_panel_depth); - - ChangeChildDepth(bgPanelRight, fg_panel_depth + 1); - ChangeChildDepth(panelRight, fg_panel_depth); - } - - animatingBlinds = true; - npcPosition = start; - this.TransformTo(nameof(npcPosition), end, 3000, Easing.OutSine).Finally(_ => animatingBlinds = false); - - targetClamp = 1; - this.Delay(600).TransformTo(nameof(targetClamp), 0.6f, 300).Delay(500).TransformTo(nameof(targetClamp), 1f, 300); - - randomNpc?.FadeIn(250).Delay(2000).FadeOut(500); - bgRandomNpc.FadeIn(250).Delay(2000).FadeOut(500); - } - /// /// Health between 0 and 1 for the blinds to base the width on. Will get animated for 200ms using out-quintic easing. /// From cb2444e01cd34e16d4e196581bc99698a4208c17 Mon Sep 17 00:00:00 2001 From: Ivan Pavluk Date: Thu, 6 Dec 2018 19:04:54 +0700 Subject: [PATCH 34/88] Remove Meh from TaikoHitWindows --- .../Objects/ManiaHitWindows.cs | 5 +-- .../Objects/Drawables/DrawableHit.cs | 6 +-- .../Objects/TaikoHitWindows.cs | 19 +++++++-- osu.Game/Rulesets/Objects/HitWindows.cs | 42 ++++++++++--------- 4 files changed, 43 insertions(+), 29 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Objects/ManiaHitWindows.cs b/osu.Game.Rulesets.Mania/Objects/ManiaHitWindows.cs index 063b626af1..ad0c04b4cc 100644 --- a/osu.Game.Rulesets.Mania/Objects/ManiaHitWindows.cs +++ b/osu.Game.Rulesets.Mania/Objects/ManiaHitWindows.cs @@ -20,11 +20,10 @@ namespace osu.Game.Rulesets.Mania.Objects { HitResult.Miss, (376, 346, 316) }, }; + public override bool IsHitResultAllowed(HitResult result) => true; + public override void SetDifficulty(double difficulty) { - AllowsPerfect = true; - AllowsOk = true; - Perfect = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Perfect]); Great = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Great]); Good = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Good]); diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs index 8c19e64de6..d4f0360b40 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs @@ -42,7 +42,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables } var result = HitObject.HitWindows.ResultFor(timeOffset); - if (result <= HitResult.Miss) + if (result == HitResult.None) return; if (!validActionPressed) @@ -173,12 +173,12 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables if (!userTriggered) { - if (timeOffset > second_hit_window) + if (timeOffset - MainObject.Result.TimeOffset > second_hit_window) ApplyResult(r => r.Type = HitResult.Miss); return; } - if (Math.Abs(MainObject.Result.TimeOffset - timeOffset) < second_hit_window) + if (Math.Abs(timeOffset - MainObject.Result.TimeOffset) <= second_hit_window) ApplyResult(r => r.Type = MainObject.Result.Type); } diff --git a/osu.Game.Rulesets.Taiko/Objects/TaikoHitWindows.cs b/osu.Game.Rulesets.Taiko/Objects/TaikoHitWindows.cs index 289f084a45..722a327f45 100644 --- a/osu.Game.Rulesets.Taiko/Objects/TaikoHitWindows.cs +++ b/osu.Game.Rulesets.Taiko/Objects/TaikoHitWindows.cs @@ -14,15 +14,28 @@ namespace osu.Game.Rulesets.Taiko.Objects { { HitResult.Great, (100, 70, 40) }, { HitResult.Good, (240, 160, 100) }, - { HitResult.Meh, (270, 190, 140) }, - { HitResult.Miss, (400, 400, 400) }, + { HitResult.Miss, (270, 190, 140) }, }; + protected override double SuccessfulHitWindow => Good; + + public override bool IsHitResultAllowed(HitResult result) + { + switch (result) + { + case HitResult.Great: + case HitResult.Good: + case HitResult.Miss: + return true; + default: + return false; + } + } + public override void SetDifficulty(double difficulty) { Great = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Great]); Good = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Good]); - Meh = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Meh]); Miss = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Miss]); } } diff --git a/osu.Game/Rulesets/Objects/HitWindows.cs b/osu.Game/Rulesets/Objects/HitWindows.cs index 3717209860..621fb418eb 100644 --- a/osu.Game/Rulesets/Objects/HitWindows.cs +++ b/osu.Game/Rulesets/Objects/HitWindows.cs @@ -22,7 +22,6 @@ namespace osu.Game.Rulesets.Objects /// /// Hit window for a result. - /// The user can only achieve receive this result if is true. /// public double Perfect { get; protected set; } @@ -38,7 +37,6 @@ namespace osu.Game.Rulesets.Objects /// /// Hit window for an result. - /// The user can only achieve this result if is true. /// public double Ok { get; protected set; } @@ -53,14 +51,25 @@ namespace osu.Game.Rulesets.Objects public double Miss { get; protected set; } /// - /// Whether it's possible to achieve a result. + /// Hit window for a non- result. /// - public bool AllowsPerfect; + protected virtual double SuccessfulHitWindow => Meh; /// - /// Whether it's possible to achieve a result. + /// Whether it's possible to achieve this . /// - public bool AllowsOk; + /// The result. + public virtual bool IsHitResultAllowed(HitResult result) + { + switch(result) + { + case HitResult.Perfect: + case HitResult.Ok: + return false; + default: + return true; + } + } /// /// Sets hit windows with values that correspond to a difficulty parameter. @@ -85,18 +94,11 @@ namespace osu.Game.Rulesets.Objects { timeOffset = Math.Abs(timeOffset); - if (AllowsPerfect && timeOffset <= HalfWindowFor(HitResult.Perfect)) - return HitResult.Perfect; - if (timeOffset <= HalfWindowFor(HitResult.Great)) - return HitResult.Great; - if (timeOffset <= HalfWindowFor(HitResult.Good)) - return HitResult.Good; - if (AllowsOk && timeOffset <= HalfWindowFor(HitResult.Ok)) - return HitResult.Ok; - if (timeOffset <= HalfWindowFor(HitResult.Meh)) - return HitResult.Meh; - if (timeOffset <= HalfWindowFor(HitResult.Miss)) - return HitResult.Miss; + for(var result = HitResult.Perfect; result >= HitResult.Miss; --result) + { + if(IsHitResultAllowed(result) && timeOffset <= HalfWindowFor(result)) + return result; + } return HitResult.None; } @@ -130,10 +132,10 @@ namespace osu.Game.Rulesets.Objects /// /// Given a time offset, whether the can ever be hit in the future with a non- result. - /// This happens if is less than what is required for a result. + /// This happens if is less than what is required for a result. /// /// The time offset. /// Whether the can be hit at any point in the future from this time offset. - public bool CanBeHit(double timeOffset) => timeOffset <= HalfWindowFor(HitResult.Meh); + public bool CanBeHit(double timeOffset) => timeOffset <= SuccessfulHitWindow / 2; } } From aa79758db5250ff63b7b398260649aabefa62fb1 Mon Sep 17 00:00:00 2001 From: Ivan Pavluk Date: Thu, 6 Dec 2018 19:15:41 +0700 Subject: [PATCH 35/88] Remove unnecessary float literal --- osu.Game.Rulesets.Catch/Judgements/CatchJudgement.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Catch/Judgements/CatchJudgement.cs b/osu.Game.Rulesets.Catch/Judgements/CatchJudgement.cs index 30ba868f6e..a266dfa691 100644 --- a/osu.Game.Rulesets.Catch/Judgements/CatchJudgement.cs +++ b/osu.Game.Rulesets.Catch/Judgements/CatchJudgement.cs @@ -34,7 +34,7 @@ namespace osu.Game.Rulesets.Catch.Judgements default: return 0; case HitResult.Perfect: - return 10.2f; + return 10.2; } } From 407f9d2e78dcf29a784e623059c9a417595bd9c7 Mon Sep 17 00:00:00 2001 From: Ivan Pavluk Date: Thu, 6 Dec 2018 19:33:42 +0700 Subject: [PATCH 36/88] Comment cleanup --- osu.Game.Rulesets.Catch/Judgements/CatchJudgement.cs | 5 ----- osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollJudgement.cs | 2 +- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Judgements/CatchJudgement.cs b/osu.Game.Rulesets.Catch/Judgements/CatchJudgement.cs index a266dfa691..b20bc43886 100644 --- a/osu.Game.Rulesets.Catch/Judgements/CatchJudgement.cs +++ b/osu.Game.Rulesets.Catch/Judgements/CatchJudgement.cs @@ -22,11 +22,6 @@ namespace osu.Game.Rulesets.Catch.Judgements } } - /// - /// Retrieves the numeric health increase of a . - /// - /// The to find the numeric health increase for. - /// The numeric health increase of . protected override double HealthIncreaseFor(HitResult result) { switch (result) diff --git a/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollJudgement.cs b/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollJudgement.cs index b3a64cd579..8c88d6d073 100644 --- a/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollJudgement.cs +++ b/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollJudgement.cs @@ -11,7 +11,7 @@ namespace osu.Game.Rulesets.Taiko.Judgements protected override double HealthIncreaseFor(HitResult result) { - //Drum rolls can be ignored with no health penalty + // Drum rolls can be ignored with no health penalty switch (result) { case HitResult.Miss: From 394c038c33b7120adca8d621c6ada2ec66309b1a Mon Sep 17 00:00:00 2001 From: Ivan Pavluk Date: Thu, 6 Dec 2018 19:52:16 +0700 Subject: [PATCH 37/88] Removed unnecessary JudgementResult casts --- .../Scoring/CatchScoreProcessor.cs | 3 +-- .../Scoring/TaikoScoreProcessor.cs | 15 ++++++--------- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Scoring/CatchScoreProcessor.cs b/osu.Game.Rulesets.Catch/Scoring/CatchScoreProcessor.cs index 403cedde8c..d33b2ae8d3 100644 --- a/osu.Game.Rulesets.Catch/Scoring/CatchScoreProcessor.cs +++ b/osu.Game.Rulesets.Catch/Scoring/CatchScoreProcessor.cs @@ -40,8 +40,7 @@ namespace osu.Game.Rulesets.Catch.Scoring return; } - if (result.Judgement is CatchJudgement catchJudgement) - Health.Value += Math.Max(catchJudgement.HealthIncreaseFor(result) - hpDrainRate, 0) * harshness; + Health.Value += Math.Max(result.Judgement.HealthIncreaseFor(result) - hpDrainRate, 0) * harshness; } } } diff --git a/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs b/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs index 721d435780..9233ab8eb7 100644 --- a/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs +++ b/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs @@ -43,17 +43,14 @@ namespace osu.Game.Rulesets.Taiko.Scoring { base.ApplyResult(result); - if (result.Judgement is TaikoJudgement taikoJudgement) - { - double hpIncrease = taikoJudgement.HealthIncreaseFor(result); + double hpIncrease = result.Judgement.HealthIncreaseFor(result); - if (result.Type == HitResult.Miss) - hpIncrease *= hpMissMultiplier; - else - hpIncrease *= hpMultiplier; + if (result.Type == HitResult.Miss) + hpIncrease *= hpMissMultiplier; + else + hpIncrease *= hpMultiplier; - Health.Value += hpIncrease; - } + Health.Value += hpIncrease; } protected override void Reset(bool storeResults) From 94f01b6678096c85630225acbcb60096c878fe05 Mon Sep 17 00:00:00 2001 From: Ivan Pavluk Date: Thu, 6 Dec 2018 20:05:03 +0700 Subject: [PATCH 38/88] Remove unused using directives --- osu.Game.Rulesets.Catch/Scoring/CatchScoreProcessor.cs | 1 - osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs | 1 - 2 files changed, 2 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Scoring/CatchScoreProcessor.cs b/osu.Game.Rulesets.Catch/Scoring/CatchScoreProcessor.cs index d33b2ae8d3..778d972b52 100644 --- a/osu.Game.Rulesets.Catch/Scoring/CatchScoreProcessor.cs +++ b/osu.Game.Rulesets.Catch/Scoring/CatchScoreProcessor.cs @@ -3,7 +3,6 @@ using System; using osu.Game.Beatmaps; -using osu.Game.Rulesets.Catch.Judgements; using osu.Game.Rulesets.Catch.Objects; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Scoring; diff --git a/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs b/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs index 9233ab8eb7..058d2b4beb 100644 --- a/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs +++ b/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs @@ -4,7 +4,6 @@ using osu.Game.Beatmaps; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Scoring; -using osu.Game.Rulesets.Taiko.Judgements; using osu.Game.Rulesets.Taiko.Objects; using osu.Game.Rulesets.UI; From 6eff7d9acc18cd8768de3d0baa85fd185dc28df1 Mon Sep 17 00:00:00 2001 From: WebFreak001 Date: Thu, 6 Dec 2018 14:34:10 +0100 Subject: [PATCH 39/88] Style fixes --- .../Objects/Drawables/DrawableOsuBlinds.cs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuBlinds.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuBlinds.cs index df7006da1d..d06f1250d8 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuBlinds.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuBlinds.cs @@ -27,10 +27,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables private Sprite panelLeft, panelRight; private Sprite bgPanelLeft, bgPanelRight; - private const float npc_movement_start = 1.5f; - private float npcPosition = npc_movement_start; - private bool animatingBlinds; - private readonly Beatmap beatmap; private ISkinSource skin; @@ -43,7 +39,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables private const float black_depth = 10; private const float bg_panel_depth = 8; private const float fg_panel_depth = 4; - private const float npc_depth = 6; private readonly CompositeDrawable restrictTo; private readonly bool modEasy, modHardrock; @@ -210,6 +205,16 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables this.TransformTo(nameof(targetBreakMultiplier), 1f, 2500, Easing.OutBounce); } + /// + /// Value between 0 and 1 setting a maximum "closedness" for the blinds. + /// Useful for animating how far the blinds can be opened while keeping them at the original position if they are wider open than this. + /// + public float TargetClamp + { + get => targetClamp; + set => targetClamp = value; + } + /// /// Health between 0 and 1 for the blinds to base the width on. Will get animated for 200ms using out-quintic easing. /// From d379d0276115d66b422ee9bc249824ccb8d60fd8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 7 Dec 2018 20:12:56 +0900 Subject: [PATCH 40/88] Remove unnecessary base class --- osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs | 31 +++++++++++----------- osu.Game/Rulesets/Mods/ModBlinds.cs | 24 ----------------- 2 files changed, 16 insertions(+), 39 deletions(-) delete mode 100644 osu.Game/Rulesets/Mods/ModBlinds.cs diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs index a9379c9133..f216ae5814 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs @@ -1,6 +1,8 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System.Linq; +using osu.Game.Graphics; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; @@ -9,30 +11,29 @@ using osu.Game.Rulesets.UI; namespace osu.Game.Rulesets.Osu.Mods { - public class OsuModBlinds : ModBlinds + public class OsuModBlinds : Mod, IApplicableToRulesetContainer, IApplicableToScoreProcessor { + public override string Name => "Blinds"; + public override string Acronym => "BL"; + public override FontAwesome Icon => FontAwesome.fa_adjust; + public override ModType Type => ModType.DifficultyIncrease; + public override string Description => "Play with blinds on your screen."; + public override bool Ranked => false; + public override double ScoreMultiplier => 1.12; private DrawableOsuBlinds flashlight; - public override void ApplyToRulesetContainer(RulesetContainer rulesetContainer) + public void ApplyToRulesetContainer(RulesetContainer rulesetContainer) { - bool hasEasy = false; - bool hasHardrock = false; - foreach (var mod in rulesetContainer.ActiveMods) - { - if (mod is ModEasy) - hasEasy = true; - if (mod is ModHardRock) - hasHardrock = true; - } + bool hasEasy = rulesetContainer.ActiveMods.Any(m => m is ModEasy); + bool hasHardrock = rulesetContainer.ActiveMods.Any(m => m is ModHardRock); + rulesetContainer.Overlays.Add(flashlight = new DrawableOsuBlinds(rulesetContainer.Playfield.HitObjectContainer, hasEasy, hasHardrock, rulesetContainer.Beatmap)); } - public override void ApplyToScoreProcessor(ScoreProcessor scoreProcessor) + public void ApplyToScoreProcessor(ScoreProcessor scoreProcessor) { - scoreProcessor.Health.ValueChanged += val => { - flashlight.AnimateTarget((float)val); - }; + scoreProcessor.Health.ValueChanged += val => { flashlight.AnimateTarget((float)val); }; } } } diff --git a/osu.Game/Rulesets/Mods/ModBlinds.cs b/osu.Game/Rulesets/Mods/ModBlinds.cs deleted file mode 100644 index e4a17551ec..0000000000 --- a/osu.Game/Rulesets/Mods/ModBlinds.cs +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) 2007-2018 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using osu.Game.Graphics; -using osu.Game.Rulesets.Objects; -using osu.Game.Rulesets.Scoring; -using osu.Game.Rulesets.UI; - -namespace osu.Game.Rulesets.Mods -{ - public abstract class ModBlinds : Mod, IApplicableToRulesetContainer, IApplicableToScoreProcessor - where T : HitObject - { - public override string Name => "Blinds"; - public override string Acronym => "BL"; - public override FontAwesome Icon => FontAwesome.fa_adjust; - public override ModType Type => ModType.DifficultyIncrease; - public override string Description => "Play with blinds on your screen."; - public override bool Ranked => false; - - public abstract void ApplyToRulesetContainer(RulesetContainer rulesetContainer); - public abstract void ApplyToScoreProcessor(ScoreProcessor scoreProcessor); - } -} From 7d9cdf6f81c41f4fa4b96111bebb2e70a9391fac Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 7 Dec 2018 20:13:03 +0900 Subject: [PATCH 41/88] Remove unnecessary private field --- osu.Game/Rulesets/UI/RulesetContainer.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/osu.Game/Rulesets/UI/RulesetContainer.cs b/osu.Game/Rulesets/UI/RulesetContainer.cs index 72e32290e2..67bcb7581f 100644 --- a/osu.Game/Rulesets/UI/RulesetContainer.cs +++ b/osu.Game/Rulesets/UI/RulesetContainer.cs @@ -68,11 +68,10 @@ namespace osu.Game.Rulesets.UI /// public Playfield Playfield => playfield.Value; - private readonly Container overlays; /// /// Place to put drawables above hit objects but below UI. /// - public Container Overlays => overlays; + public readonly Container Overlays; /// /// The cursor provided by this . May be null if no cursor is provided. @@ -93,7 +92,7 @@ namespace osu.Game.Rulesets.UI { Ruleset = ruleset; playfield = new Lazy(CreatePlayfield); - overlays = new Container + Overlays = new Container { RelativeSizeAxes = Axes.Both, Width = 1, From 4f34d42b3372aea76d29a3a09e771fac1b6f2af7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 7 Dec 2018 21:11:35 +0900 Subject: [PATCH 42/88] Major code refactors --- osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs | 222 +++++++++++++++- .../Objects/Drawables/DrawableOsuBlinds.cs | 243 ------------------ .../Drawables/Pieces/ModBlindsPanelSprite.cs | 26 -- 3 files changed, 217 insertions(+), 274 deletions(-) delete mode 100644 osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuBlinds.cs delete mode 100644 osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ModBlindsPanelSprite.cs diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs index f216ae5814..4078dce643 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs @@ -2,38 +2,250 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System.Linq; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.Textures; +using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Objects; -using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.UI; +using osu.Game.Skinning; +using osuTK; +using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Mods { public class OsuModBlinds : Mod, IApplicableToRulesetContainer, IApplicableToScoreProcessor { public override string Name => "Blinds"; + public override string Description => "Play with blinds on your screen."; public override string Acronym => "BL"; + public override FontAwesome Icon => FontAwesome.fa_adjust; public override ModType Type => ModType.DifficultyIncrease; - public override string Description => "Play with blinds on your screen."; + public override bool Ranked => false; public override double ScoreMultiplier => 1.12; - private DrawableOsuBlinds flashlight; + private DrawableOsuBlinds blinds; public void ApplyToRulesetContainer(RulesetContainer rulesetContainer) { bool hasEasy = rulesetContainer.ActiveMods.Any(m => m is ModEasy); bool hasHardrock = rulesetContainer.ActiveMods.Any(m => m is ModHardRock); - rulesetContainer.Overlays.Add(flashlight = new DrawableOsuBlinds(rulesetContainer.Playfield.HitObjectContainer, hasEasy, hasHardrock, rulesetContainer.Beatmap)); + rulesetContainer.Overlays.Add(blinds = new DrawableOsuBlinds(rulesetContainer.Playfield.HitObjectContainer, hasEasy, hasHardrock, rulesetContainer.Beatmap)); } public void ApplyToScoreProcessor(ScoreProcessor scoreProcessor) { - scoreProcessor.Health.ValueChanged += val => { flashlight.AnimateTarget((float)val); }; + scoreProcessor.Health.ValueChanged += val => { blinds.AnimateClosedness((float)val); }; + } + + /// + /// Element for the Blinds mod drawing 2 black boxes covering the whole screen which resize inside a restricted area with some leniency. + /// + public class DrawableOsuBlinds : Container + { + /// + /// Black background boxes behind blind panel textures. + /// + private Box blackBoxLeft, blackBoxRight; + + private Drawable panelLeft, panelRight, bgPanelLeft, bgPanelRight; + + private readonly Beatmap beatmap; + + /// + /// Value between 0 and 1 setting a maximum "closedness" for the blinds. + /// Useful for animating how far the blinds can be opened while keeping them at the original position if they are wider open than this. + /// + private const float target_clamp = 1; + + private readonly float targetBreakMultiplier = 0; + private readonly float easing = 1; + + private const float black_depth = 10; + private const float bg_panel_depth = 8; + private const float fg_panel_depth = 4; + + private readonly CompositeDrawable restrictTo; + private readonly bool modEasy, modHardrock; + + /// + /// + /// Percentage of playfield to extend blinds over. Basically moves the origin points where the blinds start. + /// + /// + /// -1 would mean the blinds always cover the whole screen no matter health. + /// 0 would mean the blinds will only ever be on the edge of the playfield on 0% health. + /// 1 would mean the blinds are fully outside the playfield on 50% health. + /// Infinity would mean the blinds are always outside the playfield except on 100% health. + /// + /// + private const float leniency = 0.1f; + + public DrawableOsuBlinds(CompositeDrawable restrictTo, bool hasEasy, bool hasHardrock, Beatmap beatmap) + { + this.restrictTo = restrictTo; + this.beatmap = beatmap; + + modEasy = hasEasy; + modHardrock = hasHardrock; + } + + [BackgroundDependencyLoader] + private void load() + { + RelativeSizeAxes = Axes.Both; + + Children = new[] + { + blackBoxLeft = new Box + { + Anchor = Anchor.TopLeft, + Origin = Anchor.TopLeft, + Colour = Color4.Black, + RelativeSizeAxes = Axes.Y, + Width = 0, + Height = 1, + Depth = black_depth + }, + blackBoxRight = new Box + { + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + Colour = Color4.Black, + RelativeSizeAxes = Axes.Y, + Width = 0, + Height = 1, + Depth = black_depth + }, + bgPanelLeft = new ModBlindsPanel + { + Origin = Anchor.TopRight, + Colour = Color4.Gray, + Depth = bg_panel_depth + 1 + }, + panelLeft = new ModBlindsPanel + { + Origin = Anchor.TopRight, + Depth = bg_panel_depth + }, + bgPanelRight = new ModBlindsPanel + { + Origin = Anchor.TopLeft, + Colour = Color4.Gray, + Depth = fg_panel_depth + 1 + }, + panelRight = new ModBlindsPanel + { + Origin = Anchor.TopLeft, + Depth = fg_panel_depth + }, + }; + } + + private float applyGap(float value) + { + const float easy_multiplier = 0.95f; + const float hardrock_multiplier = 1.1f; + + float multiplier = 1; + if (modEasy) + { + multiplier = easy_multiplier; + // TODO: include OD/CS + } + else if (modHardrock) + { + multiplier = hardrock_multiplier; + // TODO: include OD/CS + } + + return MathHelper.Clamp(value * multiplier, 0, target_clamp) * targetBreakMultiplier; + } + + private static float applyAdjustmentCurve(float value) + { + // lagrange polinominal for (0,0) (0.5,0.35) (1,1) should make a good curve + return 0.6f * value * value + 0.4f * value; + } + + protected override void Update() + { + float start = Parent.ToLocalSpace(restrictTo.ScreenSpaceDrawQuad.TopLeft).X; + float end = Parent.ToLocalSpace(restrictTo.ScreenSpaceDrawQuad.TopRight).X; + + float rawWidth = end - start; + + start -= rawWidth * leniency * 0.5f; + end += rawWidth * leniency * 0.5f; + + float width = (end - start) * 0.5f * applyAdjustmentCurve(applyGap(easing)); + + // different values in case the playfield ever moves from center to somewhere else. + blackBoxLeft.Width = start + width; + blackBoxRight.Width = DrawWidth - end + width; + + panelLeft.X = start + width; + panelRight.X = end - width; + bgPanelLeft.X = start; + bgPanelRight.X = end; + } + + protected override void LoadComplete() + { + const float break_open_early = 500; + const float break_close_late = 250; + + base.LoadComplete(); + + var firstObj = beatmap.HitObjects[0]; + var startDelay = firstObj.StartTime - firstObj.TimePreempt; + + using (BeginAbsoluteSequence(startDelay + break_close_late, true)) + leaveBreak(); + + foreach (var breakInfo in beatmap.Breaks) + { + if (breakInfo.HasEffect) + { + using (BeginAbsoluteSequence(breakInfo.StartTime - break_open_early, true)) + { + enterBreak(); + using (BeginDelayedSequence(breakInfo.Duration + break_open_early + break_close_late, true)) + leaveBreak(); + } + } + } + } + + private void enterBreak() => this.TransformTo(nameof(targetBreakMultiplier), 0f, 1000, Easing.OutSine); + + private void leaveBreak() => this.TransformTo(nameof(targetBreakMultiplier), 1f, 2500, Easing.OutBounce); + + /// + /// 0 is open, 1 is closed. + /// + public void AnimateClosedness(float value) => this.TransformTo(nameof(easing), value, 200, Easing.OutQuint); + + public class ModBlindsPanel : CompositeDrawable + { + [BackgroundDependencyLoader] + private void load(TextureStore textures) + { + InternalChild = new SkinnableDrawable("Play/osu/blinds-panel", s => new Sprite { Texture = textures.Get("Play/osu/blinds-panel") }) + { + RelativeSizeAxes = Axes.Both, + }; + } + } } } } diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuBlinds.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuBlinds.cs deleted file mode 100644 index d06f1250d8..0000000000 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuBlinds.cs +++ /dev/null @@ -1,243 +0,0 @@ -// Copyright (c) 2007-2018 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using osu.Framework.Allocation; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.Sprites; -using osu.Framework.Graphics.Textures; -using osu.Game.Beatmaps; -using osu.Game.Skinning; -using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; -using osuTK; -using osuTK.Graphics; - -namespace osu.Game.Rulesets.Osu.Objects.Drawables -{ - /// - /// Element for the Blinds mod drawing 2 black boxes covering the whole screen which resize inside a restricted area with some leniency. - /// - public class DrawableOsuBlinds : Container - { - /// - /// Black background boxes behind blind panel textures. - /// - private Box blackBoxLeft, blackBoxRight; - private Sprite panelLeft, panelRight; - private Sprite bgPanelLeft, bgPanelRight; - - private readonly Beatmap beatmap; - - private ISkinSource skin; - - private float targetClamp = 1; - private readonly float targetBreakMultiplier = 0; - private float target = 1; - private readonly float easing = 1; - - private const float black_depth = 10; - private const float bg_panel_depth = 8; - private const float fg_panel_depth = 4; - - private readonly CompositeDrawable restrictTo; - private readonly bool modEasy, modHardrock; - - /// - /// - /// Percentage of playfield to extend blinds over. Basically moves the origin points where the blinds start. - /// - /// - /// -1 would mean the blinds always cover the whole screen no matter health. - /// 0 would mean the blinds will only ever be on the edge of the playfield on 0% health. - /// 1 would mean the blinds are fully outside the playfield on 50% health. - /// Infinity would mean the blinds are always outside the playfield except on 100% health. - /// - /// - private const float leniency = 0.1f; - - public DrawableOsuBlinds(CompositeDrawable restrictTo, bool hasEasy, bool hasHardrock, Beatmap beatmap) - { - this.restrictTo = restrictTo; - this.beatmap = beatmap; - - modEasy = hasEasy; - modHardrock = hasHardrock; - } - - [BackgroundDependencyLoader] - private void load(ISkinSource skin, TextureStore textures) - { - RelativeSizeAxes = Axes.Both; - Width = 1; - Height = 1; - - Add(blackBoxLeft = new Box - { - Anchor = Anchor.TopLeft, - Origin = Anchor.TopLeft, - Colour = Color4.Black, - RelativeSizeAxes = Axes.Y, - Width = 0, - Height = 1, - Depth = black_depth - }); - Add(blackBoxRight = new Box - { - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - Colour = Color4.Black, - RelativeSizeAxes = Axes.Y, - Width = 0, - Height = 1, - Depth = black_depth - }); - - Add(bgPanelLeft = new ModBlindsPanelSprite { - Origin = Anchor.TopRight, - Colour = Color4.Gray, - Depth = bg_panel_depth + 1 - }); - Add(panelLeft = new ModBlindsPanelSprite { - Origin = Anchor.TopRight, - Depth = bg_panel_depth - }); - - Add(bgPanelRight = new ModBlindsPanelSprite { - Origin = Anchor.TopLeft, - Colour = Color4.Gray, - Depth = fg_panel_depth + 1 - }); - Add(panelRight = new ModBlindsPanelSprite { - Origin = Anchor.TopLeft, - Depth = fg_panel_depth - }); - - this.skin = skin; - skin.SourceChanged += skinChanged; - PanelTexture = textures.Get("Play/osu/blinds-panel"); - } - - private void skinChanged() - { - PanelTexture = skin.GetTexture("Play/osu/blinds-panel"); - } - - private float applyGap(float value) - { - const float easy_multiplier = 0.95f; - const float hardrock_multiplier = 1.1f; - - float multiplier = 1; - if (modEasy) - { - multiplier = easy_multiplier; - // TODO: include OD/CS - } - else if (modHardrock) - { - multiplier = hardrock_multiplier; - // TODO: include OD/CS - } - - return MathHelper.Clamp(value * multiplier, 0, targetClamp) * targetBreakMultiplier; - } - - private static float applyAdjustmentCurve(float value) - { - // lagrange polinominal for (0,0) (0.5,0.35) (1,1) should make a good curve - return 0.6f * value * value + 0.4f * value; - } - - protected override void Update() - { - float start = Parent.ToLocalSpace(restrictTo.ScreenSpaceDrawQuad.TopLeft).X; - float end = Parent.ToLocalSpace(restrictTo.ScreenSpaceDrawQuad.TopRight).X; - float rawWidth = end - start; - start -= rawWidth * leniency * 0.5f; - end += rawWidth * leniency * 0.5f; - - float width = (end - start) * 0.5f * applyAdjustmentCurve(applyGap(easing)); - // different values in case the playfield ever moves from center to somewhere else. - blackBoxLeft.Width = start + width; - blackBoxRight.Width = DrawWidth - end + width; - - panelLeft.X = start + width; - panelRight.X = end - width; - bgPanelLeft.X = start; - bgPanelRight.X = end; - } - - protected override void LoadComplete() - { - const float break_open_early = 500; - const float break_close_late = 250; - - base.LoadComplete(); - - var firstObj = beatmap.HitObjects[0]; - var startDelay = firstObj.StartTime - firstObj.TimePreempt; - - using (BeginAbsoluteSequence(startDelay + break_close_late, true)) - LeaveBreak(); - - foreach (var breakInfo in beatmap.Breaks) - { - if (breakInfo.HasEffect) - { - using (BeginAbsoluteSequence(breakInfo.StartTime - break_open_early, true)) - { - EnterBreak(); - using (BeginDelayedSequence(breakInfo.Duration + break_open_early + break_close_late, true)) - LeaveBreak(); - } - } - } - } - - public void EnterBreak() - { - this.TransformTo(nameof(targetBreakMultiplier), 0f, 1000, Easing.OutSine); - } - - public void LeaveBreak() - { - this.TransformTo(nameof(targetBreakMultiplier), 1f, 2500, Easing.OutBounce); - } - - /// - /// Value between 0 and 1 setting a maximum "closedness" for the blinds. - /// Useful for animating how far the blinds can be opened while keeping them at the original position if they are wider open than this. - /// - public float TargetClamp - { - get => targetClamp; - set => targetClamp = value; - } - - /// - /// Health between 0 and 1 for the blinds to base the width on. Will get animated for 200ms using out-quintic easing. - /// - public void AnimateTarget(float value) - { - target = value; - this.TransformTo(nameof(easing), target, 200, Easing.OutQuint); - } - - public float Target - { - get => target; - } - - public Texture PanelTexture - { - set - { - panelLeft.Texture = value; - panelRight.Texture = value; - bgPanelLeft.Texture = value; - bgPanelRight.Texture = value; - } - } - } -} diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ModBlindsPanelSprite.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ModBlindsPanelSprite.cs deleted file mode 100644 index c6e2db1842..0000000000 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ModBlindsPanelSprite.cs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) 2007-2018 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using osu.Framework.Graphics; -using osu.Framework.Graphics.Sprites; - -namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces -{ - public class ModBlindsPanelSprite : Sprite - { - public ModBlindsPanelSprite() - { - RelativeSizeAxes = Axes.None; - Anchor = Anchor.TopLeft; - } - - protected override void Update() - { - Height = Parent?.DrawHeight ?? 0; - if (Height == 0 || Texture == null) - Width = 0; - else - Width = Texture.Width / (float)Texture.Height * Height; - } - } -} From 7a703f923799f403e2bb98ade1868d1a8fb3bc6b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 9 Dec 2018 15:08:25 +0900 Subject: [PATCH 43/88] Fix API getting stuck in connecting state on some exceptions --- osu.Game/Online/API/APIAccess.cs | 48 ++++++++++++++++++++++---------- 1 file changed, 34 insertions(+), 14 deletions(-) diff --git a/osu.Game/Online/API/APIAccess.cs b/osu.Game/Online/API/APIAccess.cs index 1dda257c95..cf709e2162 100644 --- a/osu.Game/Online/API/APIAccess.cs +++ b/osu.Game/Online/API/APIAccess.cs @@ -196,19 +196,7 @@ namespace osu.Game.Online.API /// true if we should remove this request from the queue. private bool handleRequest(APIRequest req) { - try - { - Logger.Log($@"Performing request {req}", LoggingTarget.Network); - req.Perform(this); - - //we could still be in initialisation, at which point we don't want to say we're Online yet. - if (IsLoggedIn) - State = APIState.Online; - - failureCount = 0; - return true; - } - catch (WebException we) + bool handleWebException(WebException we) { HttpStatusCode statusCode = (we.Response as HttpWebResponse)?.StatusCode ?? (we.Status == WebExceptionStatus.UnknownError ? HttpStatusCode.NotAcceptable : HttpStatusCode.RequestTimeout); @@ -217,6 +205,7 @@ namespace osu.Game.Online.API switch (we.Message) { case "Unauthorized": + case "Forbidden": statusCode = HttpStatusCode.Unauthorized; break; } @@ -239,9 +228,40 @@ namespace osu.Game.Online.API return true; } - req.Fail(we); return true; } + + try + { + Logger.Log($@"Performing request {req}", LoggingTarget.Network); + req.Failure += ex => + { + switch (ex) + { + case WebException we: + handleWebException(we); + break; + } + }; + + req.Perform(this); + + //we could still be in initialisation, at which point we don't want to say we're Online yet. + if (IsLoggedIn) + State = APIState.Online; + + failureCount = 0; + return true; + } + catch (WebException we) + { + var removeFromQueue = handleWebException(we); + + if (removeFromQueue) + req.Fail(we); + + return removeFromQueue; + } catch (Exception e) { if (e is TimeoutException) From 784a114eae0b117c2daacf2081ba4ebdf34c6379 Mon Sep 17 00:00:00 2001 From: Dan Balasescu <1329837+smoogipoo@users.noreply.github.com> Date: Sun, 9 Dec 2018 23:38:19 +0700 Subject: [PATCH 44/88] formatting fix Co-Authored-By: pavlukivan --- osu.Game/Rulesets/Objects/HitWindows.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Objects/HitWindows.cs b/osu.Game/Rulesets/Objects/HitWindows.cs index 621fb418eb..76d6579fc6 100644 --- a/osu.Game/Rulesets/Objects/HitWindows.cs +++ b/osu.Game/Rulesets/Objects/HitWindows.cs @@ -94,7 +94,7 @@ namespace osu.Game.Rulesets.Objects { timeOffset = Math.Abs(timeOffset); - for(var result = HitResult.Perfect; result >= HitResult.Miss; --result) + for (var result = HitResult.Perfect; result >= HitResult.Miss; --result) { if(IsHitResultAllowed(result) && timeOffset <= HalfWindowFor(result)) return result; From 77a544e475360e72446d97c9f7b5a74678eb3906 Mon Sep 17 00:00:00 2001 From: Dan Balasescu <1329837+smoogipoo@users.noreply.github.com> Date: Sun, 9 Dec 2018 23:38:29 +0700 Subject: [PATCH 45/88] formatting fix Co-Authored-By: pavlukivan --- osu.Game/Rulesets/Objects/HitWindows.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Objects/HitWindows.cs b/osu.Game/Rulesets/Objects/HitWindows.cs index 76d6579fc6..319bfdec65 100644 --- a/osu.Game/Rulesets/Objects/HitWindows.cs +++ b/osu.Game/Rulesets/Objects/HitWindows.cs @@ -96,7 +96,7 @@ namespace osu.Game.Rulesets.Objects for (var result = HitResult.Perfect; result >= HitResult.Miss; --result) { - if(IsHitResultAllowed(result) && timeOffset <= HalfWindowFor(result)) + if (IsHitResultAllowed(result) && timeOffset <= HalfWindowFor(result)) return result; } From 8457324044641bde7650f125f8fd018f508ec2a9 Mon Sep 17 00:00:00 2001 From: Ivan Pavluk Date: Mon, 10 Dec 2018 09:04:12 +0700 Subject: [PATCH 46/88] SuccessfulHitWindow->SuccessfulHitResult --- osu.Game.Rulesets.Taiko/Objects/TaikoHitWindows.cs | 2 +- .../Scoring/TaikoScoreProcessor.cs | 13 ++++++++++--- osu.Game/Rulesets/Objects/HitWindows.cs | 6 +++--- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Objects/TaikoHitWindows.cs b/osu.Game.Rulesets.Taiko/Objects/TaikoHitWindows.cs index 722a327f45..2317d4cc90 100644 --- a/osu.Game.Rulesets.Taiko/Objects/TaikoHitWindows.cs +++ b/osu.Game.Rulesets.Taiko/Objects/TaikoHitWindows.cs @@ -17,7 +17,7 @@ namespace osu.Game.Rulesets.Taiko.Objects { HitResult.Miss, (270, 190, 140) }, }; - protected override double SuccessfulHitWindow => Good; + protected override HitResult SuccessfulHitResult => HitResult.Good; public override bool IsHitResultAllowed(HitResult result) { diff --git a/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs b/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs index 058d2b4beb..bd92905648 100644 --- a/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs +++ b/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs @@ -12,16 +12,23 @@ namespace osu.Game.Rulesets.Taiko.Scoring internal class TaikoScoreProcessor : ScoreProcessor { /// - /// The HP awarded by a hit. + /// A value used in calculating . /// - private const double hp_hit_great = 0.03; + private const double object_count_factor = 3; /// /// Taiko fails at the end of the map if the player has not half-filled their HP bar. /// protected override bool DefaultFailCondition => JudgedHits == MaxHits && Health.Value <= 0.5; + /// + /// HP multiplier for a successful . + /// private double hpMultiplier; + + /// + /// HP multiplier for a . + /// private double hpMissMultiplier; public TaikoScoreProcessor(RulesetContainer rulesetContainer) @@ -33,7 +40,7 @@ namespace osu.Game.Rulesets.Taiko.Scoring { base.ApplyBeatmap(beatmap); - hpMultiplier = 0.01 / (hp_hit_great * beatmap.HitObjects.FindAll(o => o is Hit).Count * BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.DrainRate, 0.5, 0.75, 0.98)); + hpMultiplier = 1 / (object_count_factor * beatmap.HitObjects.FindAll(o => o is Hit).Count * BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.DrainRate, 0.5, 0.75, 0.98)); hpMissMultiplier = BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.DrainRate, 0.0018, 0.0075, 0.0120); } diff --git a/osu.Game/Rulesets/Objects/HitWindows.cs b/osu.Game/Rulesets/Objects/HitWindows.cs index 319bfdec65..dd114afb7b 100644 --- a/osu.Game/Rulesets/Objects/HitWindows.cs +++ b/osu.Game/Rulesets/Objects/HitWindows.cs @@ -51,9 +51,9 @@ namespace osu.Game.Rulesets.Objects public double Miss { get; protected set; } /// - /// Hit window for a non- result. + /// The with the largest hit window that produces a successful hit. /// - protected virtual double SuccessfulHitWindow => Meh; + protected virtual HitResult SuccessfulHitResult => HitResult.Meh; /// /// Whether it's possible to achieve this . @@ -136,6 +136,6 @@ namespace osu.Game.Rulesets.Objects /// /// The time offset. /// Whether the can be hit at any point in the future from this time offset. - public bool CanBeHit(double timeOffset) => timeOffset <= SuccessfulHitWindow / 2; + public bool CanBeHit(double timeOffset) => timeOffset <= HalfWindowFor(SuccessfulHitResult); } } From 839e177d2a6a6ab84446cdce32051595892c4115 Mon Sep 17 00:00:00 2001 From: Ivan Pavluk Date: Mon, 10 Dec 2018 04:59:35 +0000 Subject: [PATCH 47/88] Docstring change --- osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs b/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs index bd92905648..318efdbf3e 100644 --- a/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs +++ b/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs @@ -12,7 +12,7 @@ namespace osu.Game.Rulesets.Taiko.Scoring internal class TaikoScoreProcessor : ScoreProcessor { /// - /// A value used in calculating . + /// A value used for calculating . /// private const double object_count_factor = 3; From a2d1c2c096ccfbc56ceff2319164393dd4e2c149 Mon Sep 17 00:00:00 2001 From: Ivan Pavluk Date: Mon, 10 Dec 2018 05:05:03 +0000 Subject: [PATCH 48/88] Fix formatting --- osu.Game.Rulesets.Taiko/Judgements/TaikoSwellJudgement.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/Judgements/TaikoSwellJudgement.cs b/osu.Game.Rulesets.Taiko/Judgements/TaikoSwellJudgement.cs index 7c525bba6c..024e0e618f 100644 --- a/osu.Game.Rulesets.Taiko/Judgements/TaikoSwellJudgement.cs +++ b/osu.Game.Rulesets.Taiko/Judgements/TaikoSwellJudgement.cs @@ -11,7 +11,7 @@ namespace osu.Game.Rulesets.Taiko.Judgements protected override double HealthIncreaseFor(HitResult result) { - switch(result) + switch (result) { case HitResult.Miss: return -0.65; From a62b105fb539c9a52e4e09f3f937652cab4dbe8f Mon Sep 17 00:00:00 2001 From: Ivan Pavluk Date: Mon, 10 Dec 2018 05:06:18 +0000 Subject: [PATCH 49/88] Fix formatting --- osu.Game/Rulesets/Objects/HitWindows.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Objects/HitWindows.cs b/osu.Game/Rulesets/Objects/HitWindows.cs index dd114afb7b..e4d987e2dc 100644 --- a/osu.Game/Rulesets/Objects/HitWindows.cs +++ b/osu.Game/Rulesets/Objects/HitWindows.cs @@ -61,7 +61,7 @@ namespace osu.Game.Rulesets.Objects /// The result. public virtual bool IsHitResultAllowed(HitResult result) { - switch(result) + switch (result) { case HitResult.Perfect: case HitResult.Ok: From ea4dce845491503da0fd86a3c1b59a4a9c3d966e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 10 Dec 2018 21:08:14 +0900 Subject: [PATCH 50/88] Add a polling component model --- .../Visual/TestCasePollingComponent.cs | 98 ++++++++++++++++ osu.Game/Online/Chat/ChannelManager.cs | 93 +++++++-------- osu.Game/Online/PollingComponent.cs | 108 ++++++++++++++++++ osu.Game/OsuGame.cs | 2 + 4 files changed, 249 insertions(+), 52 deletions(-) create mode 100644 osu.Game.Tests/Visual/TestCasePollingComponent.cs create mode 100644 osu.Game/Online/PollingComponent.cs diff --git a/osu.Game.Tests/Visual/TestCasePollingComponent.cs b/osu.Game.Tests/Visual/TestCasePollingComponent.cs new file mode 100644 index 0000000000..928c92cb2b --- /dev/null +++ b/osu.Game.Tests/Visual/TestCasePollingComponent.cs @@ -0,0 +1,98 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using System.Threading.Tasks; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Game.Graphics.Sprites; +using osu.Game.Online; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Tests.Visual +{ + public class TestCasePollingComponent : OsuTestCase + { + private Container pollBox; + private TestPoller poller; + + [BackgroundDependencyLoader] + private void load() + { + Children = new Drawable[] + { + poller = new TestPoller(), + pollBox = new Container + { + Alpha = 0, + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] + { + new Box + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Scale = new Vector2(0.4f), + Colour = Color4.LimeGreen, + RelativeSizeAxes = Axes.Both, + }, + new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Text = "Poll!", + } + } + } + }; + + int count = 0; + + poller.OnPoll += () => + { + pollBox.FadeOutFromOne(500); + count++; + }; + + AddStep("set poll to 1 second", () => poller.TimeBetweenPolls = TimePerAction); + + void checkCount(int checkValue) => AddAssert($"count is {checkValue}", () => count == checkValue); + + checkCount(1); + checkCount(2); + checkCount(3); + + AddStep("set poll to 5 second", () => poller.TimeBetweenPolls = TimePerAction * 5); + + checkCount(4); + checkCount(4); + checkCount(4); + checkCount(4); + + checkCount(5); + checkCount(5); + checkCount(5); + + AddStep("set poll to 5 second", () => poller.TimeBetweenPolls = TimePerAction); + + AddAssert("count is 6", () => count == 6); + + } + + protected override double TimePerAction => 500; + + public class TestPoller : PollingComponent + { + public event Action OnPoll; + + protected override Task Poll() + { + OnPoll?.Invoke(); + return base.Poll(); + } + } + } +} diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index 863ad3042f..a63af0f7a3 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -4,11 +4,10 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Configuration; -using osu.Framework.Graphics; using osu.Framework.Logging; -using osu.Framework.Threading; using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Game.Users; @@ -18,7 +17,7 @@ namespace osu.Game.Online.Chat /// /// Manages everything channel related /// - public class ChannelManager : Component, IOnlineComponent + public class ChannelManager : PollingComponent { /// /// The channels the player joins on startup @@ -49,11 +48,14 @@ namespace osu.Game.Online.Chat public IBindableCollection AvailableChannels => availableChannels; private IAPIProvider api; - private ScheduledDelegate fetchMessagesScheduleder; + + public readonly BindableBool HighPollRate = new BindableBool(); public ChannelManager() { CurrentChannel.ValueChanged += currentChannelChanged; + + HighPollRate.BindValueChanged(high => TimeBetweenPolls = high ? 1000 : 6000, true); } /// @@ -360,73 +362,60 @@ namespace osu.Game.Online.Chat } } - public void APIStateChanged(APIAccess api, APIState state) - { - switch (state) - { - case APIState.Online: - fetchUpdates(); - break; - default: - fetchMessagesScheduleder?.Cancel(); - fetchMessagesScheduleder = null; - break; - } - } - private long lastMessageId; - private const int update_poll_interval = 1000; private bool channelsInitialised; - private void fetchUpdates() + protected override Task Poll() { - fetchMessagesScheduleder?.Cancel(); - fetchMessagesScheduleder = Scheduler.AddDelayed(() => + if (!api.IsLoggedIn) + return base.Poll(); + + var fetchReq = new GetUpdatesRequest(lastMessageId); + + var tcs = new TaskCompletionSource(); + + fetchReq.Success += updates => { - var fetchReq = new GetUpdatesRequest(lastMessageId); - - fetchReq.Success += updates => + if (updates?.Presence != null) { - if (updates?.Presence != null) + foreach (var channel in updates.Presence) { - foreach (var channel in updates.Presence) - { - // we received this from the server so should mark the channel already joined. - JoinChannel(channel, true); - } - - //todo: handle left channels - - handleChannelMessages(updates.Messages); - - foreach (var group in updates.Messages.GroupBy(m => m.ChannelId)) - JoinedChannels.FirstOrDefault(c => c.Id == group.Key)?.AddNewMessages(group.ToArray()); - - lastMessageId = updates.Messages.LastOrDefault()?.Id ?? lastMessageId; + // we received this from the server so should mark the channel already joined. + JoinChannel(channel, true); } - if (!channelsInitialised) - { - channelsInitialised = true; - // we want this to run after the first presence so we can see if the user is in any channels already. - initializeChannels(); - } + //todo: handle left channels - fetchUpdates(); - }; + handleChannelMessages(updates.Messages); - fetchReq.Failure += delegate { fetchUpdates(); }; + foreach (var group in updates.Messages.GroupBy(m => m.ChannelId)) + JoinedChannels.FirstOrDefault(c => c.Id == group.Key)?.AddNewMessages(group.ToArray()); - api.Queue(fetchReq); - }, update_poll_interval); + lastMessageId = updates.Messages.LastOrDefault()?.Id ?? lastMessageId; + } + + if (!channelsInitialised) + { + channelsInitialised = true; + // we want this to run after the first presence so we can see if the user is in any channels already. + initializeChannels(); + } + + tcs.SetResult(true); + }; + + fetchReq.Failure += _ => tcs.SetResult(false); + + api.Queue(fetchReq); + + return tcs.Task; } [BackgroundDependencyLoader] private void load(IAPIProvider api) { this.api = api; - api.Register(this); } } diff --git a/osu.Game/Online/PollingComponent.cs b/osu.Game/Online/PollingComponent.cs new file mode 100644 index 0000000000..d9dcfc40c2 --- /dev/null +++ b/osu.Game/Online/PollingComponent.cs @@ -0,0 +1,108 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using System.Threading.Tasks; +using osu.Framework.Graphics; +using osu.Framework.Threading; + +namespace osu.Game.Online +{ + /// + /// A component which requires a constant polling process. + /// + public abstract class PollingComponent : Component + { + private double? lastTimePolled; + + private ScheduledDelegate scheduledPoll; + + private bool pollingActive; + + private double timeBetweenPolls; + + /// + /// The time that should be waited between polls. + /// + public double TimeBetweenPolls + { + get => timeBetweenPolls; + set + { + timeBetweenPolls = value; + scheduledPoll?.Cancel(); + pollIfNecessary(); + } + } + + protected override void LoadComplete() + { + base.LoadComplete(); + pollIfNecessary(); + } + + private bool pollIfNecessary() + { + // we must be loaded so we have access to clock. + if (!IsLoaded) return false; + + // there's already a poll process running. + if (pollingActive) return false; + + // don't try polling if the time between polls hasn't been set. + if (timeBetweenPolls == 0) return false; + + if (!lastTimePolled.HasValue) + { + doPoll(); + return true; + } + + if (Time.Current - lastTimePolled.Value > timeBetweenPolls) + { + doPoll(); + return true; + } + + // not ennough time has passed since the last poll. we do want to schedule a poll to happen, though. + scheduleNextPoll(); + return false; + } + + private void doPoll() + { + scheduledPoll = null; + pollingActive = true; + Poll().ContinueWith(_ => pollComplete()); + } + + /// + /// Perform the polling in this method. Call when done. + /// + protected virtual Task Poll() + { + return Task.CompletedTask; + } + + /// + /// Call when a poll operation has completed. + /// + private void pollComplete() + { + lastTimePolled = Time.Current; + pollingActive = false; + + if (scheduledPoll == null) + scheduleNextPoll(); + } + + private void scheduleNextPoll() + { + scheduledPoll?.Cancel(); + + double lastPollDuration = lastTimePolled.HasValue ? Time.Current - lastTimePolled.Value : 0; + + scheduledPoll = Scheduler.AddDelayed(doPoll, Math.Max(0, timeBetweenPolls - lastPollDuration)); + } + } +} diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 73ecbafb9e..31a00e68ac 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -418,6 +418,8 @@ namespace osu.Game dependencies.Cache(notifications); dependencies.Cache(dialogOverlay); + chatOverlay.StateChanged += state => channelManager.HighPollRate.Value = state == Visibility.Visible; + Add(externalLinkOpener = new ExternalLinkOpener()); var singleDisplaySideOverlays = new OverlayContainer[] { settings, notifications }; From 49dd6ae9b0b8993977b66e7c3f4eb992e331f20d Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 12 Dec 2018 13:21:44 +0900 Subject: [PATCH 51/88] Move a lot more of PlaySongSelect into SongSelect --- osu.Game/Screens/Select/PlaySongSelect.cs | 103 ++-------------------- osu.Game/Screens/Select/SongSelect.cs | 95 ++++++++++++++++---- 2 files changed, 85 insertions(+), 113 deletions(-) diff --git a/osu.Game/Screens/Select/PlaySongSelect.cs b/osu.Game/Screens/Select/PlaySongSelect.cs index 8d37da0377..cbe22d968a 100644 --- a/osu.Game/Screens/Select/PlaySongSelect.cs +++ b/osu.Game/Screens/Select/PlaySongSelect.cs @@ -1,99 +1,28 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using System.Collections.Generic; using System.Linq; -using osuTK.Input; using osu.Framework.Allocation; -using osu.Framework.Audio; -using osu.Framework.Audio.Sample; -using osu.Framework.Configuration; -using osu.Framework.Graphics; using osu.Framework.Screens; -using osu.Game.Beatmaps; using osu.Game.Graphics; -using osu.Game.Overlays; -using osu.Game.Rulesets.Mods; using osu.Game.Screens.Play; -using osu.Game.Screens.Ranking; -using osu.Game.Skinning; +using osuTK.Input; namespace osu.Game.Screens.Select { public class PlaySongSelect : SongSelect { - private OsuScreen player; - protected readonly BeatmapDetailArea BeatmapDetails; private bool removeAutoModOnResume; + private OsuScreen player; - public PlaySongSelect() + [BackgroundDependencyLoader] + private void load(OsuColour colours) { - LeftContent.Add(BeatmapDetails = new BeatmapDetailArea - { - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Top = 10, Right = 5 }, - }); - - BeatmapDetails.Leaderboard.ScoreSelected += s => Push(new Results(s)); - } - - private SampleChannel sampleConfirm; - - [Cached] - [Cached(Type = typeof(IBindable>))] - private readonly Bindable> selectedMods = new Bindable>(new Mod[] { }); - - [BackgroundDependencyLoader(true)] - private void load(OsuColour colours, AudioManager audio, BeatmapManager beatmaps, SkinManager skins, DialogOverlay dialogOverlay, Bindable> selectedMods) - { - if (selectedMods != null) this.selectedMods.BindTo(selectedMods); - - sampleConfirm = audio.Sample.Get(@"SongSelect/confirm-selection"); - - BeatmapOptions.AddButton(@"Remove", @"from unplayed", FontAwesome.fa_times_circle_o, colours.Purple, null, Key.Number1); - BeatmapOptions.AddButton(@"Clear", @"local scores", FontAwesome.fa_eraser, colours.Purple, null, Key.Number2); BeatmapOptions.AddButton(@"Edit", @"beatmap", FontAwesome.fa_pencil, colours.Yellow, () => { ValidForResume = false; Edit(); }, Key.Number3); - - if (dialogOverlay != null) - { - Schedule(() => - { - // if we have no beatmaps but osu-stable is found, let's prompt the user to import. - if (!beatmaps.GetAllUsableBeatmapSets().Any() && beatmaps.StableInstallationAvailable) - dialogOverlay.Push(new ImportFromStablePopup(() => - { - beatmaps.ImportFromStableAsync(); - skins.ImportFromStableAsync(); - })); - }); - } - } - - protected override void ExitFromBack() - { - if (modSelect.State == Visibility.Visible) - { - modSelect.Hide(); - return; - } - - base.ExitFromBack(); - } - - protected override void UpdateBeatmap(WorkingBeatmap beatmap) - { - beatmap.Mods.BindTo(selectedMods); - - base.UpdateBeatmap(beatmap); - - BeatmapDetails.Beatmap = beatmap; - - if (beatmap.Track != null) - beatmap.Track.Looping = true; } protected override void OnResuming(Screen last) @@ -107,27 +36,9 @@ namespace osu.Game.Screens.Select removeAutoModOnResume = false; } - BeatmapDetails.Leaderboard.RefreshScores(); - - Beatmap.Value.Track.Looping = true; - base.OnResuming(last); } - protected override bool OnExiting(Screen next) - { - if (base.OnExiting(next)) - return true; - - if (Beatmap.Value.Track != null) - Beatmap.Value.Track.Looping = false; - - selectedMods.UnbindAll(); - Beatmap.Value.Mods.Value = new Mod[] { }; - - return false; - } - protected override bool OnStart() { if (player != null) return false; @@ -138,10 +49,10 @@ namespace osu.Game.Screens.Select var auto = Ruleset.Value.CreateInstance().GetAutoplayMod(); var autoType = auto.GetType(); - var mods = selectedMods.Value; + var mods = SelectedMods.Value; if (mods.All(m => m.GetType() != autoType)) { - selectedMods.Value = mods.Append(auto); + SelectedMods.Value = mods.Append(auto); removeAutoModOnResume = true; } } @@ -149,7 +60,7 @@ namespace osu.Game.Screens.Select Beatmap.Value.Track.Looping = false; Beatmap.Disabled = true; - sampleConfirm?.Play(); + SampleConfirm?.Play(); LoadComponentAsync(player = new PlayerLoader(new Player()), l => { diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index c7e999f7c7..71b63c8e5b 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -2,6 +2,7 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; +using System.Collections.Generic; using System.Linq; using osuTK; using osuTK.Input; @@ -27,7 +28,9 @@ using osu.Game.Rulesets.Mods; using osu.Game.Screens.Backgrounds; using osu.Game.Screens.Edit; using osu.Game.Screens.Menu; +using osu.Game.Screens.Ranking; using osu.Game.Screens.Select.Options; +using osu.Game.Skinning; namespace osu.Game.Screens.Select { @@ -61,8 +64,6 @@ namespace osu.Game.Screens.Select protected override BackgroundScreen CreateBackground() => new BackgroundScreenBeatmap(); - protected Container LeftContent; - protected readonly BeatmapCarousel Carousel; private readonly BeatmapInfoWedge beatmapInfoWedge; private DialogOverlay dialogOverlay; @@ -70,22 +71,17 @@ namespace osu.Game.Screens.Select protected readonly ModSelectOverlay ModSelect; + protected SampleChannel SampleConfirm; private SampleChannel sampleChangeDifficulty; private SampleChannel sampleChangeBeatmap; + protected readonly BeatmapDetailArea BeatmapDetails; + protected new readonly Bindable Ruleset = new Bindable(); - private DependencyContainer dependencies; - - protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) - { - dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); - dependencies.CacheAs(this); - dependencies.CacheAs(Ruleset); - dependencies.CacheAs>(Ruleset); - - return dependencies; - } + [Cached] + [Cached(Type = typeof(IBindable>))] + protected readonly Bindable> SelectedMods = new Bindable>(new Mod[] { }); protected SongSelect() { @@ -108,7 +104,7 @@ namespace osu.Game.Screens.Select } } }, - LeftContent = new Container + new Container { Origin = Anchor.BottomLeft, Anchor = Anchor.BottomLeft, @@ -120,6 +116,11 @@ namespace osu.Game.Screens.Select Top = wedged_container_size.Y + left_area_padding, Left = left_area_padding, Right = left_area_padding * 2, + }, + Child = BeatmapDetails = new BeatmapDetailArea + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Top = 10, Right = 5 }, } }, new Container @@ -208,13 +209,16 @@ namespace osu.Game.Screens.Select } }); } + + BeatmapDetails.Leaderboard.ScoreSelected += s => Push(new Results(s)); } - protected virtual void ExitFromBack() => Exit(); - [BackgroundDependencyLoader(true)] - private void load(BeatmapManager beatmaps, AudioManager audio, DialogOverlay dialog, OsuColour colours) + private void load(BeatmapManager beatmaps, AudioManager audio, DialogOverlay dialog, OsuColour colours, SkinManager skins, Bindable> selectedMods) { + if (selectedMods != null) + SelectedMods.BindTo(selectedMods); + if (Footer != null) { Footer.AddButton(@"mods", colours.Yellow, ModSelect, Key.F1); @@ -222,6 +226,8 @@ namespace osu.Game.Screens.Select Footer.AddButton(@"options", colours.Blue, BeatmapOptions, Key.F3); BeatmapOptions.AddButton(@"Delete", @"all difficulties", FontAwesome.fa_trash, colours.Pink, () => delete(Beatmap.Value.BeatmapSetInfo), Key.Number4, float.MaxValue); + BeatmapOptions.AddButton(@"Remove", @"from unplayed", FontAwesome.fa_times_circle_o, colours.Purple, null, Key.Number1); + BeatmapOptions.AddButton(@"Clear", @"local scores", FontAwesome.fa_eraser, colours.Purple, null, Key.Number2); } if (this.beatmaps == null) @@ -236,8 +242,46 @@ namespace osu.Game.Screens.Select sampleChangeDifficulty = audio.Sample.Get(@"SongSelect/select-difficulty"); sampleChangeBeatmap = audio.Sample.Get(@"SongSelect/select-expand"); + SampleConfirm = audio.Sample.Get(@"SongSelect/confirm-selection"); Carousel.LoadBeatmapSetsFromManager(this.beatmaps); + + if (dialogOverlay != null) + { + Schedule(() => + { + // if we have no beatmaps but osu-stable is found, let's prompt the user to import. + if (!beatmaps.GetAllUsableBeatmapSets().Any() && beatmaps.StableInstallationAvailable) + dialogOverlay.Push(new ImportFromStablePopup(() => + { + beatmaps.ImportFromStableAsync(); + skins.ImportFromStableAsync(); + })); + }); + } + } + + private DependencyContainer dependencies; + + protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) + { + dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); + dependencies.CacheAs(this); + dependencies.CacheAs(Ruleset); + dependencies.CacheAs>(Ruleset); + + return dependencies; + } + + protected virtual void ExitFromBack() + { + if (ModSelect.State == Visibility.Visible) + { + ModSelect.Hide(); + return; + } + + Exit(); } public void Edit(BeatmapInfo beatmap = null) @@ -434,6 +478,10 @@ namespace osu.Game.Screens.Select protected override void OnResuming(Screen last) { + BeatmapDetails.Leaderboard.RefreshScores(); + + Beatmap.Value.Track.Looping = true; + if (Beatmap != null && !Beatmap.Value.BeatmapSetInfo.DeletePending) { UpdateBeatmap(Beatmap.Value); @@ -477,6 +525,12 @@ namespace osu.Game.Screens.Select FilterControl.Deactivate(); + if (Beatmap.Value.Track != null) + Beatmap.Value.Track.Looping = false; + + SelectedMods.UnbindAll(); + Beatmap.Value.Mods.Value = new Mod[] { }; + return base.OnExiting(next); } @@ -502,6 +556,8 @@ namespace osu.Game.Screens.Select /// The working beatmap. protected virtual void UpdateBeatmap(WorkingBeatmap beatmap) { + beatmap.Mods.BindTo(SelectedMods); + Logger.Log($"working beatmap updated to {beatmap}"); if (Background is BackgroundScreenBeatmap backgroundModeBeatmap) @@ -512,6 +568,11 @@ namespace osu.Game.Screens.Select } beatmapInfoWedge.Beatmap = beatmap; + + BeatmapDetails.Beatmap = beatmap; + + if (beatmap.Track != null) + beatmap.Track.Looping = true; } private void ensurePlayingSelected(bool preview = false) From d86cbf66a9ad7c00824ad6cb5dd6b97b7e246dbc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 12 Dec 2018 13:10:47 +0700 Subject: [PATCH 52/88] Update docstring Co-Authored-By: pavlukivan --- osu.Game/Rulesets/Objects/HitWindows.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Objects/HitWindows.cs b/osu.Game/Rulesets/Objects/HitWindows.cs index e4d987e2dc..841452df55 100644 --- a/osu.Game/Rulesets/Objects/HitWindows.cs +++ b/osu.Game/Rulesets/Objects/HitWindows.cs @@ -58,7 +58,8 @@ namespace osu.Game.Rulesets.Objects /// /// Whether it's possible to achieve this . /// - /// The result. + /// The result type to check. + /// Whether the can be achieved. public virtual bool IsHitResultAllowed(HitResult result) { switch (result) From ffb91b4afcef7d668ffeb0e3d6d0d88d12274dfd Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 12 Dec 2018 13:11:03 +0700 Subject: [PATCH 53/88] Update docstring Co-Authored-By: pavlukivan --- osu.Game/Rulesets/Objects/HitWindows.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Objects/HitWindows.cs b/osu.Game/Rulesets/Objects/HitWindows.cs index 841452df55..c75e914d2d 100644 --- a/osu.Game/Rulesets/Objects/HitWindows.cs +++ b/osu.Game/Rulesets/Objects/HitWindows.cs @@ -56,7 +56,7 @@ namespace osu.Game.Rulesets.Objects protected virtual HitResult SuccessfulHitResult => HitResult.Meh; /// - /// Whether it's possible to achieve this . + /// Check whether it is possible to achieve the provided . /// /// The result type to check. /// Whether the can be achieved. From e49e2fda9e3fdd8488a70010e3bd36e3a2d045c2 Mon Sep 17 00:00:00 2001 From: Ivan Pavluk Date: Wed, 12 Dec 2018 13:24:58 +0700 Subject: [PATCH 54/88] Rename SuccessfulHitResult->LowestSuccessfulHitResult --- osu.Game.Rulesets.Taiko/Objects/TaikoHitWindows.cs | 2 +- osu.Game/Rulesets/Objects/HitWindows.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Objects/TaikoHitWindows.cs b/osu.Game.Rulesets.Taiko/Objects/TaikoHitWindows.cs index 2317d4cc90..2c207114da 100644 --- a/osu.Game.Rulesets.Taiko/Objects/TaikoHitWindows.cs +++ b/osu.Game.Rulesets.Taiko/Objects/TaikoHitWindows.cs @@ -17,7 +17,7 @@ namespace osu.Game.Rulesets.Taiko.Objects { HitResult.Miss, (270, 190, 140) }, }; - protected override HitResult SuccessfulHitResult => HitResult.Good; + protected override HitResult LowestSuccessfulHitResult => HitResult.Good; public override bool IsHitResultAllowed(HitResult result) { diff --git a/osu.Game/Rulesets/Objects/HitWindows.cs b/osu.Game/Rulesets/Objects/HitWindows.cs index c75e914d2d..cf8769a105 100644 --- a/osu.Game/Rulesets/Objects/HitWindows.cs +++ b/osu.Game/Rulesets/Objects/HitWindows.cs @@ -53,7 +53,7 @@ namespace osu.Game.Rulesets.Objects /// /// The with the largest hit window that produces a successful hit. /// - protected virtual HitResult SuccessfulHitResult => HitResult.Meh; + protected virtual HitResult LowestSuccessfulHitResult => HitResult.Meh; /// /// Check whether it is possible to achieve the provided . @@ -137,6 +137,6 @@ namespace osu.Game.Rulesets.Objects /// /// The time offset. /// Whether the can be hit at any point in the future from this time offset. - public bool CanBeHit(double timeOffset) => timeOffset <= HalfWindowFor(SuccessfulHitResult); + public bool CanBeHit(double timeOffset) => timeOffset <= HalfWindowFor(LowestSuccessfulHitResult); } } From 77e0d7ed8e3ecc799387c5d2096183ca5269ff88 Mon Sep 17 00:00:00 2001 From: Ivan Pavluk Date: Wed, 12 Dec 2018 07:57:37 +0000 Subject: [PATCH 55/88] Fix formatting --- .../Judgements/TaikoDrumRollTickJudgement.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollTickJudgement.cs b/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollTickJudgement.cs index 86b495ca08..e11bdf225f 100644 --- a/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollTickJudgement.cs +++ b/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollTickJudgement.cs @@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Taiko.Judgements protected override double HealthIncreaseFor(HitResult result) { - switch(result) + switch (result) { case HitResult.Great: return 0.15; From 28b033bd993d19ff50462d0ce8dea2c06b71febd Mon Sep 17 00:00:00 2001 From: Ivan Pavluk Date: Wed, 12 Dec 2018 17:15:59 +0700 Subject: [PATCH 56/88] Autodetect LowestSuccessfulHitResult --- .../Objects/TaikoHitWindows.cs | 2 -- osu.Game/Rulesets/Objects/HitWindows.cs | 16 +++++++++++++--- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Objects/TaikoHitWindows.cs b/osu.Game.Rulesets.Taiko/Objects/TaikoHitWindows.cs index 2c207114da..9199e6f141 100644 --- a/osu.Game.Rulesets.Taiko/Objects/TaikoHitWindows.cs +++ b/osu.Game.Rulesets.Taiko/Objects/TaikoHitWindows.cs @@ -17,8 +17,6 @@ namespace osu.Game.Rulesets.Taiko.Objects { HitResult.Miss, (270, 190, 140) }, }; - protected override HitResult LowestSuccessfulHitResult => HitResult.Good; - public override bool IsHitResultAllowed(HitResult result) { switch (result) diff --git a/osu.Game/Rulesets/Objects/HitWindows.cs b/osu.Game/Rulesets/Objects/HitWindows.cs index cf8769a105..40fb98a997 100644 --- a/osu.Game/Rulesets/Objects/HitWindows.cs +++ b/osu.Game/Rulesets/Objects/HitWindows.cs @@ -51,9 +51,19 @@ namespace osu.Game.Rulesets.Objects public double Miss { get; protected set; } /// - /// The with the largest hit window that produces a successful hit. + /// Retrieves the with the largest hit window that produces a successful hit. /// - protected virtual HitResult LowestSuccessfulHitResult => HitResult.Meh; + /// The lowest allowed successful . + protected HitResult LowestSuccessfulHitResult() + { + for (var result = HitResult.Meh; result <= HitResult.Perfect; ++result) + { + if (IsHitResultAllowed(result)) + return result; + } + + return HitResult.None; + } /// /// Check whether it is possible to achieve the provided . @@ -137,6 +147,6 @@ namespace osu.Game.Rulesets.Objects /// /// The time offset. /// Whether the can be hit at any point in the future from this time offset. - public bool CanBeHit(double timeOffset) => timeOffset <= HalfWindowFor(LowestSuccessfulHitResult); + public bool CanBeHit(double timeOffset) => timeOffset <= HalfWindowFor(LowestSuccessfulHitResult()); } } From ebd93757806d66e2a6cf7c6dc80d44a9c2073667 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 11 Dec 2018 20:12:30 +0900 Subject: [PATCH 57/88] Add more tests --- .../Visual/TestCasePollingComponent.cs | 108 ++++++++++++------ 1 file changed, 76 insertions(+), 32 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCasePollingComponent.cs b/osu.Game.Tests/Visual/TestCasePollingComponent.cs index 928c92cb2b..a77a4a7d57 100644 --- a/osu.Game.Tests/Visual/TestCasePollingComponent.cs +++ b/osu.Game.Tests/Visual/TestCasePollingComponent.cs @@ -3,10 +3,11 @@ using System; using System.Threading.Tasks; -using osu.Framework.Allocation; +using NUnit.Framework; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; +using osu.Framework.Logging; using osu.Game.Graphics.Sprites; using osu.Game.Online; using osuTK; @@ -19,12 +20,16 @@ namespace osu.Game.Tests.Visual private Container pollBox; private TestPoller poller; - [BackgroundDependencyLoader] - private void load() + private const float safety_adjust = 1f; + private int count; + + [SetUp] + public void SetUp() => Schedule(() => { + count = 0; + Children = new Drawable[] { - poller = new TestPoller(), pollBox = new Container { Alpha = 0, @@ -48,41 +53,75 @@ namespace osu.Game.Tests.Visual } } }; + }); - int count = 0; + //[Test] + public void TestInstantPolling() + { + createPoller(true); + AddStep("set poll interval to 1", () => poller.TimeBetweenPolls = TimePerAction * safety_adjust); + checkCount(1); + checkCount(2); + checkCount(3); + + AddStep("set poll interval to 5", () => poller.TimeBetweenPolls = TimePerAction * safety_adjust * 5); + checkCount(4); + checkCount(4); + checkCount(4); + + skip(); + + checkCount(5); + checkCount(5); + + AddStep("set poll interval to 1", () => poller.TimeBetweenPolls = TimePerAction * safety_adjust); + checkCount(6); + checkCount(7); + } + + [Test] + public void TestSlowPolling() + { + createPoller(false); + + AddStep("set poll interval to 1", () => poller.TimeBetweenPolls = TimePerAction * safety_adjust * 5); + checkCount(0); + skip(); + checkCount(0); + skip(); + skip(); + checkCount(0); + skip(); + skip(); + checkCount(0); + } + + private void skip() => AddStep("skip", () => + { + // could be 4 or 5 at this point due to timing discrepancies (safety_adjust @ 0.2 * 5 ~= 1) + // easiest to just ignore the value at this point and move on. + }); + + private void checkCount(int checkValue) + { + Logger.Log($"value is {count}"); + AddAssert($"count is {checkValue}", () => count == checkValue); + } + + private void createPoller(bool instant) => AddStep("create poller", () => + { + poller?.Expire(); + + Add(poller = instant ? new TestPoller() : new TestSlowPoller()); poller.OnPoll += () => { pollBox.FadeOutFromOne(500); count++; }; + }); - AddStep("set poll to 1 second", () => poller.TimeBetweenPolls = TimePerAction); - - void checkCount(int checkValue) => AddAssert($"count is {checkValue}", () => count == checkValue); - - checkCount(1); - checkCount(2); - checkCount(3); - - AddStep("set poll to 5 second", () => poller.TimeBetweenPolls = TimePerAction * 5); - - checkCount(4); - checkCount(4); - checkCount(4); - checkCount(4); - - checkCount(5); - checkCount(5); - checkCount(5); - - AddStep("set poll to 5 second", () => poller.TimeBetweenPolls = TimePerAction); - - AddAssert("count is 6", () => count == 6); - - } - - protected override double TimePerAction => 500; + protected override double TimePerAction => 500000; public class TestPoller : PollingComponent { @@ -90,9 +129,14 @@ namespace osu.Game.Tests.Visual protected override Task Poll() { - OnPoll?.Invoke(); + Schedule(() => OnPoll?.Invoke()); return base.Poll(); } } + + public class TestSlowPoller : TestPoller + { + protected override Task Poll() => Task.Delay((int)(TimeBetweenPolls / 2f / Clock.Rate)).ContinueWith(_ => base.Poll()); + } } } From 4fc9902cd2d7827122f90fcb1f4e4380124b4177 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 12 Dec 2018 21:30:21 +0900 Subject: [PATCH 58/88] Fix reverting to default skin via settings button causing a hard crash --- osu.Game/Overlays/Settings/Sections/SkinSection.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Settings/Sections/SkinSection.cs b/osu.Game/Overlays/Settings/Sections/SkinSection.cs index 23f35d5d3a..e259996b7f 100644 --- a/osu.Game/Overlays/Settings/Sections/SkinSection.cs +++ b/osu.Game/Overlays/Settings/Sections/SkinSection.cs @@ -21,7 +21,7 @@ namespace osu.Game.Overlays.Settings.Sections public override FontAwesome Icon => FontAwesome.fa_paint_brush; - private readonly Bindable dropdownBindable = new Bindable(); + private readonly Bindable dropdownBindable = new Bindable { Default = SkinInfo.Default }; private readonly Bindable configBindable = new Bindable(); private SkinManager skins; From ac0fc6236c0cb2d552f21c0629995f87ed65ccb2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 13 Dec 2018 14:51:18 +0900 Subject: [PATCH 59/88] Fix crash when changing beatmap toggles at loading screen --- osu.Game/Skinning/LocalSkinOverrideContainer.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/osu.Game/Skinning/LocalSkinOverrideContainer.cs b/osu.Game/Skinning/LocalSkinOverrideContainer.cs index 25d9442e6f..d7d2737d35 100644 --- a/osu.Game/Skinning/LocalSkinOverrideContainer.cs +++ b/osu.Game/Skinning/LocalSkinOverrideContainer.cs @@ -16,8 +16,8 @@ namespace osu.Game.Skinning { public event Action SourceChanged; - private Bindable beatmapSkins = new Bindable(); - private Bindable beatmapHitsounds = new Bindable(); + private readonly Bindable beatmapSkins = new Bindable(); + private readonly Bindable beatmapHitsounds = new Bindable(); public Drawable GetDrawableComponent(string componentName) { @@ -84,11 +84,8 @@ namespace osu.Game.Skinning [BackgroundDependencyLoader] private void load(OsuConfigManager config) { - beatmapSkins = config.GetBindable(OsuSetting.BeatmapSkins); - beatmapSkins.BindValueChanged(_ => onSourceChanged()); - - beatmapHitsounds = config.GetBindable(OsuSetting.BeatmapHitsounds); - beatmapHitsounds.BindValueChanged(_ => onSourceChanged(), true); + config.BindWith(OsuSetting.BeatmapSkins, beatmapSkins); + config.BindWith(OsuSetting.BeatmapHitsounds, beatmapHitsounds); } protected override void LoadComplete() @@ -97,6 +94,9 @@ namespace osu.Game.Skinning if (fallbackSource != null) fallbackSource.SourceChanged += onSourceChanged; + + beatmapSkins.BindValueChanged(_ => onSourceChanged()); + beatmapHitsounds.BindValueChanged(_ => onSourceChanged(), true); } protected override void Dispose(bool isDisposing) From 71e5ce59da01307d444712e0176193d91b5def0b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 13 Dec 2018 16:17:24 +0900 Subject: [PATCH 60/88] Fix crash on exiting player during results transition --- osu.Game/Screens/Play/Player.cs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index bf44e9e636..19b49b099c 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -170,7 +170,7 @@ namespace osu.Game.Screens.Play { Retries = RestartCount, OnRetry = Restart, - OnQuit = Exit, + OnQuit = performUserRequestedExit, CheckCanPause = () => AllowPause && ValidForResume && !HasFailed && !RulesetContainer.HasReplayLoaded, Children = new[] { @@ -211,7 +211,7 @@ namespace osu.Game.Screens.Play failOverlay = new FailOverlay { OnRetry = Restart, - OnQuit = Exit, + OnQuit = performUserRequestedExit, }, new HotkeyRetryOverlay { @@ -225,7 +225,7 @@ namespace osu.Game.Screens.Play } }; - hudOverlay.HoldToQuit.Action = Exit; + hudOverlay.HoldToQuit.Action = performUserRequestedExit; hudOverlay.KeyCounter.Visible.BindTo(RulesetContainer.HasReplayLoaded); RulesetContainer.IsPaused.BindTo(pauseContainer.IsPaused); @@ -250,8 +250,16 @@ namespace osu.Game.Screens.Play mod.ApplyToClock(sourceClock); } + private void performUserRequestedExit() + { + if (!IsCurrentScreen) return; + Exit(); + } + public void Restart() { + if (!IsCurrentScreen) return; + sampleRestart?.Play(); ValidForResume = false; RestartRequested?.Invoke(); From a6fc1280943dea4a38f1942b7234b65d31726238 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 14 Dec 2018 15:41:05 +0900 Subject: [PATCH 61/88] Fix WaveOverlayContainer always being present --- osu.Game/Overlays/WaveOverlayContainer.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/osu.Game/Overlays/WaveOverlayContainer.cs b/osu.Game/Overlays/WaveOverlayContainer.cs index c5a4953c5e..5f7cf17a9d 100644 --- a/osu.Game/Overlays/WaveOverlayContainer.cs +++ b/osu.Game/Overlays/WaveOverlayContainer.cs @@ -25,13 +25,20 @@ namespace osu.Game.Overlays protected override void PopIn() { base.PopIn(); + Waves.Show(); + + this.FadeIn(); } protected override void PopOut() { base.PopOut(); + Waves.Hide(); + + // this is required or we will remain present even though our waves are hidden. + this.Delay(WaveContainer.DISAPPEAR_DURATION).FadeOut(); } } } From 9072af9792a0133e72cdd2272cd2c92aefb91599 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 14 Dec 2018 15:48:34 +0900 Subject: [PATCH 62/88] Move bulk of method into separate private method with minor clean-ups --- osu.Game/Online/API/APIAccess.cs | 78 +++++++++++++++----------------- 1 file changed, 37 insertions(+), 41 deletions(-) diff --git a/osu.Game/Online/API/APIAccess.cs b/osu.Game/Online/API/APIAccess.cs index cf709e2162..a1376b8b94 100644 --- a/osu.Game/Online/API/APIAccess.cs +++ b/osu.Game/Online/API/APIAccess.cs @@ -196,52 +196,13 @@ namespace osu.Game.Online.API /// true if we should remove this request from the queue. private bool handleRequest(APIRequest req) { - bool handleWebException(WebException we) - { - HttpStatusCode statusCode = (we.Response as HttpWebResponse)?.StatusCode - ?? (we.Status == WebExceptionStatus.UnknownError ? HttpStatusCode.NotAcceptable : HttpStatusCode.RequestTimeout); - - // special cases for un-typed but useful message responses. - switch (we.Message) - { - case "Unauthorized": - case "Forbidden": - statusCode = HttpStatusCode.Unauthorized; - break; - } - - switch (statusCode) - { - case HttpStatusCode.Unauthorized: - Logout(false); - return true; - case HttpStatusCode.RequestTimeout: - failureCount++; - log.Add($@"API failure count is now {failureCount}"); - - if (failureCount < 3) - //we might try again at an api level. - return false; - - State = APIState.Failing; - flushQueue(); - return true; - } - - return true; - } - try { Logger.Log($@"Performing request {req}", LoggingTarget.Network); req.Failure += ex => { - switch (ex) - { - case WebException we: - handleWebException(we); - break; - } + if (ex is WebException we) + handleWebException(we); }; req.Perform(this); @@ -296,6 +257,41 @@ namespace osu.Game.Online.API } } + private bool handleWebException(WebException we) + { + HttpStatusCode statusCode = (we.Response as HttpWebResponse)?.StatusCode + ?? (we.Status == WebExceptionStatus.UnknownError ? HttpStatusCode.NotAcceptable : HttpStatusCode.RequestTimeout); + + // special cases for un-typed but useful message responses. + switch (we.Message) + { + case "Unauthorized": + case "Forbidden": + statusCode = HttpStatusCode.Unauthorized; + break; + } + + switch (statusCode) + { + case HttpStatusCode.Unauthorized: + Logout(false); + return true; + case HttpStatusCode.RequestTimeout: + failureCount++; + log.Add($@"API failure count is now {failureCount}"); + + if (failureCount < 3) + //we might try again at an api level. + return false; + + State = APIState.Failing; + flushQueue(); + return true; + } + + return true; + } + public bool IsLoggedIn => LocalUser.Value.Id > 1; public void Queue(APIRequest request) From 3fda40c4acae0ce25d8a96e18f9bc196c8f2d6d1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 14 Dec 2018 17:42:11 +0900 Subject: [PATCH 63/88] Ignore annoying tests for now --- osu.Game.Tests/Visual/TestCasePollingComponent.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCasePollingComponent.cs b/osu.Game.Tests/Visual/TestCasePollingComponent.cs index a77a4a7d57..b4b9d465e5 100644 --- a/osu.Game.Tests/Visual/TestCasePollingComponent.cs +++ b/osu.Game.Tests/Visual/TestCasePollingComponent.cs @@ -55,7 +55,7 @@ namespace osu.Game.Tests.Visual }; }); - //[Test] + [Test] public void TestInstantPolling() { createPoller(true); @@ -81,6 +81,7 @@ namespace osu.Game.Tests.Visual } [Test] + [Ignore("i have no idea how to fix the timing of this one")] public void TestSlowPolling() { createPoller(false); @@ -121,7 +122,7 @@ namespace osu.Game.Tests.Visual }; }); - protected override double TimePerAction => 500000; + protected override double TimePerAction => 500; public class TestPoller : PollingComponent { From 64626f62dbe9db8c265076404c1460eabc31165a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 14 Dec 2018 19:02:25 +0900 Subject: [PATCH 64/88] Update framework --- osu.Game/osu.Game.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index ed0e6c8417..305c9035b5 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -18,7 +18,7 @@ - + From 38fd35a0cf450e30fa1845e938728c2424676613 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 14 Dec 2018 19:17:21 +0900 Subject: [PATCH 65/88] Add polling time to ctor --- .idea/.idea.osu/.idea/runConfigurations/osu_.xml | 9 ++++++--- osu.Game/Online/PollingComponent.cs | 12 +++++++++++- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/.idea/.idea.osu/.idea/runConfigurations/osu_.xml b/.idea/.idea.osu/.idea/runConfigurations/osu_.xml index 344301d4a7..2735f4ceb3 100644 --- a/.idea/.idea.osu/.idea/runConfigurations/osu_.xml +++ b/.idea/.idea.osu/.idea/runConfigurations/osu_.xml @@ -1,17 +1,20 @@ - \ No newline at end of file diff --git a/osu.Game/Online/PollingComponent.cs b/osu.Game/Online/PollingComponent.cs index d9dcfc40c2..9d0bed7595 100644 --- a/osu.Game/Online/PollingComponent.cs +++ b/osu.Game/Online/PollingComponent.cs @@ -22,7 +22,8 @@ namespace osu.Game.Online private double timeBetweenPolls; /// - /// The time that should be waited between polls. + /// The time in milliseconds to wait between polls. + /// Setting to zero stops all polling. /// public double TimeBetweenPolls { @@ -35,6 +36,15 @@ namespace osu.Game.Online } } + /// + /// + /// + /// The initial time in milliseconds to wait between polls. Setting to zero stops al polling. + protected PollingComponent(double timeBetweenPolls = 0) + { + TimeBetweenPolls = timeBetweenPolls; + } + protected override void LoadComplete() { base.LoadComplete(); From 0b5f3c00bf2fdac0c6e833155a917dc56251a38e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 14 Dec 2018 20:50:27 +0900 Subject: [PATCH 66/88] Revert "Fix WaveOverlayContainer always being present" This reverts commit a6fc1280943dea4a38f1942b7234b65d31726238. --- osu.Game/Overlays/WaveOverlayContainer.cs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/osu.Game/Overlays/WaveOverlayContainer.cs b/osu.Game/Overlays/WaveOverlayContainer.cs index 5f7cf17a9d..c5a4953c5e 100644 --- a/osu.Game/Overlays/WaveOverlayContainer.cs +++ b/osu.Game/Overlays/WaveOverlayContainer.cs @@ -25,20 +25,13 @@ namespace osu.Game.Overlays protected override void PopIn() { base.PopIn(); - Waves.Show(); - - this.FadeIn(); } protected override void PopOut() { base.PopOut(); - Waves.Hide(); - - // this is required or we will remain present even though our waves are hidden. - this.Delay(WaveContainer.DISAPPEAR_DURATION).FadeOut(); } } } From 00998d54432abb578b711a441cb1badb4ede0ba0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 17 Dec 2018 14:29:11 +0900 Subject: [PATCH 67/88] Fix web requests not getting correctly handled on first connection --- osu.Game/Online/API/APIAccess.cs | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/osu.Game/Online/API/APIAccess.cs b/osu.Game/Online/API/APIAccess.cs index a1376b8b94..57dd4f1568 100644 --- a/osu.Game/Online/API/APIAccess.cs +++ b/osu.Game/Online/API/APIAccess.cs @@ -141,7 +141,7 @@ namespace osu.Game.Online.API State = APIState.Online; }; - if (!handleRequest(userReq)) + if (!handleRequest(userReq, out _)) { Thread.Sleep(500); continue; @@ -170,11 +170,15 @@ namespace osu.Game.Online.API lock (queue) { if (queue.Count == 0) break; - req = queue.Dequeue(); + req = queue.Peek(); } // TODO: handle failures better - handleRequest(req); + handleRequest(req, out var removeFromQueue); + + if (removeFromQueue) + lock (queue) + queue.Dequeue(); } Thread.Sleep(50); @@ -193,9 +197,11 @@ namespace osu.Game.Online.API /// Handle a single API request. /// /// The request. - /// true if we should remove this request from the queue. - private bool handleRequest(APIRequest req) + /// true if the request succeeded. + private bool handleRequest(APIRequest req, out bool removeFromQueue) { + removeFromQueue = true; + try { Logger.Log($@"Performing request {req}", LoggingTarget.Network); @@ -216,12 +222,12 @@ namespace osu.Game.Online.API } catch (WebException we) { - var removeFromQueue = handleWebException(we); + removeFromQueue = handleWebException(we); if (removeFromQueue) req.Fail(we); - return removeFromQueue; + return false; } catch (Exception e) { @@ -229,7 +235,7 @@ namespace osu.Game.Online.API log.Add(@"API level timeout exception was hit"); req.Fail(e); - return true; + return false; } } From 6088612a266b0fd407d015849262236d0ff548ed Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 18 Dec 2018 20:19:40 +0900 Subject: [PATCH 68/88] Remove all retry logic and simplify overall handling of API requests --- osu.Game/Online/API/APIAccess.cs | 38 +++++++------------------------ osu.Game/Online/API/APIRequest.cs | 35 ++++++++++------------------ 2 files changed, 20 insertions(+), 53 deletions(-) diff --git a/osu.Game/Online/API/APIAccess.cs b/osu.Game/Online/API/APIAccess.cs index 57dd4f1568..7786bb55ac 100644 --- a/osu.Game/Online/API/APIAccess.cs +++ b/osu.Game/Online/API/APIAccess.cs @@ -102,7 +102,7 @@ namespace osu.Game.Online.API if (queue.Count == 0) { log.Add(@"Queueing a ping request"); - Queue(new ListChannelsRequest { Timeout = 5000 }); + Queue(new GetUserRequest()); } break; @@ -141,7 +141,7 @@ namespace osu.Game.Online.API State = APIState.Online; }; - if (!handleRequest(userReq, out _)) + if (!handleRequest(userReq)) { Thread.Sleep(500); continue; @@ -170,15 +170,10 @@ namespace osu.Game.Online.API lock (queue) { if (queue.Count == 0) break; - req = queue.Peek(); + req = queue.Dequeue(); } - // TODO: handle failures better - handleRequest(req, out var removeFromQueue); - - if (removeFromQueue) - lock (queue) - queue.Dequeue(); + handleRequest(req); } Thread.Sleep(50); @@ -195,46 +190,29 @@ namespace osu.Game.Online.API /// /// Handle a single API request. + /// Ensures all exceptions are caught and dealt with correctly. /// /// The request. /// true if the request succeeded. - private bool handleRequest(APIRequest req, out bool removeFromQueue) + private bool handleRequest(APIRequest req) { - removeFromQueue = true; - try { - Logger.Log($@"Performing request {req}", LoggingTarget.Network); - req.Failure += ex => - { - if (ex is WebException we) - handleWebException(we); - }; - req.Perform(this); //we could still be in initialisation, at which point we don't want to say we're Online yet. - if (IsLoggedIn) - State = APIState.Online; + if (IsLoggedIn) State = APIState.Online; failureCount = 0; return true; } catch (WebException we) { - removeFromQueue = handleWebException(we); - - if (removeFromQueue) - req.Fail(we); - + handleWebException(we); return false; } catch (Exception e) { - if (e is TimeoutException) - log.Add(@"API level timeout exception was hit"); - - req.Fail(e); return false; } } diff --git a/osu.Game/Online/API/APIRequest.cs b/osu.Game/Online/API/APIRequest.cs index adbedb2aac..41f774e83c 100644 --- a/osu.Game/Online/API/APIRequest.cs +++ b/osu.Game/Online/API/APIRequest.cs @@ -3,6 +3,7 @@ using System; using osu.Framework.IO.Network; +using osu.Framework.Logging; namespace osu.Game.Online.API { @@ -35,23 +36,12 @@ namespace osu.Game.Online.API /// public abstract class APIRequest { - /// - /// The maximum amount of time before this request will fail. - /// - public int Timeout = WebRequest.DEFAULT_TIMEOUT; - protected virtual string Target => string.Empty; protected virtual WebRequest CreateWebRequest() => new WebRequest(Uri); protected virtual string Uri => $@"{API.Endpoint}/api/v2/{Target}"; - private double remainingTime => Math.Max(0, Timeout - (DateTimeOffset.UtcNow - (startTime ?? DateTimeOffset.MinValue)).TotalMilliseconds); - - public bool ExceededTimeout => remainingTime == 0; - - private DateTimeOffset? startTime; - protected APIAccess API; protected WebRequest WebRequest; @@ -75,27 +65,24 @@ namespace osu.Game.Online.API { API = api; - if (checkAndProcessFailure()) + if (checkAndScheduleFailure()) return; - if (startTime == null) - startTime = DateTimeOffset.UtcNow; - - if (remainingTime <= 0) - throw new TimeoutException(@"API request timeout hit"); - WebRequest = CreateWebRequest(); WebRequest.Failed += Fail; WebRequest.AllowRetryOnTimeout = false; WebRequest.AddHeader("Authorization", $"Bearer {api.AccessToken}"); - if (checkAndProcessFailure()) + if (checkAndScheduleFailure()) return; if (!WebRequest.Aborted) //could have been aborted by a Cancel() call + { + Logger.Log($@"Performing request {this}", LoggingTarget.Network); WebRequest.Perform(); + } - if (checkAndProcessFailure()) + if (checkAndScheduleFailure()) return; api.Schedule(delegate { Success?.Invoke(); }); @@ -105,19 +92,21 @@ namespace osu.Game.Online.API public void Fail(Exception e) { - cancelled = true; + if (cancelled) return; + cancelled = true; WebRequest?.Abort(); + Logger.Log($@"Failing request {this} ({e})", LoggingTarget.Network); pendingFailure = () => Failure?.Invoke(e); - checkAndProcessFailure(); + checkAndScheduleFailure(); } /// /// Checked for cancellation or error. Also queues up the Failed event if we can. /// /// Whether we are in a failed or cancelled state. - private bool checkAndProcessFailure() + private bool checkAndScheduleFailure() { if (API == null || pendingFailure == null) return cancelled; From 4a1af67893d7959ebe77353ec5cf63afa8d0407f Mon Sep 17 00:00:00 2001 From: Roman Kapustin Date: Tue, 18 Dec 2018 22:49:53 +0300 Subject: [PATCH 69/88] Do not delete file on import failure --- osu.Game/Database/ArchiveModelManager.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/osu.Game/Database/ArchiveModelManager.cs b/osu.Game/Database/ArchiveModelManager.cs index 50767608af..77e92421e9 100644 --- a/osu.Game/Database/ArchiveModelManager.cs +++ b/osu.Game/Database/ArchiveModelManager.cs @@ -149,8 +149,10 @@ namespace osu.Game.Database try { notification.Text = $"Importing ({++current} of {paths.Length})\n{Path.GetFileName(path)}"; + + TModel import; using (ArchiveReader reader = getReaderFrom(path)) - imported.Add(Import(reader)); + imported.Add(import = Import(reader)); notification.Progress = (float)current / paths.Length; @@ -160,7 +162,7 @@ namespace osu.Game.Database // TODO: Add a check to prevent files from storage to be deleted. try { - if (File.Exists(path)) + if (import != null && File.Exists(path)) File.Delete(path); } catch (Exception e) From bacc07f5ec3ed6e873a6872bd1f2b406d6e4d80f Mon Sep 17 00:00:00 2001 From: Styphix Date: Tue, 18 Dec 2018 19:44:31 -0500 Subject: [PATCH 70/88] Changed `OsuFocusedOverlayContainer` to `WaveOverlayContainer` from `ChannelSelectionOverlay` Not sure what colour i shouldve gone for but im certain that this should be fine --- .../Overlays/Chat/Selection/ChannelSelectionOverlay.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Chat/Selection/ChannelSelectionOverlay.cs b/osu.Game/Overlays/Chat/Selection/ChannelSelectionOverlay.cs index 3afac211f1..0cc0076903 100644 --- a/osu.Game/Overlays/Chat/Selection/ChannelSelectionOverlay.cs +++ b/osu.Game/Overlays/Chat/Selection/ChannelSelectionOverlay.cs @@ -20,7 +20,7 @@ using osu.Game.Graphics.Containers; namespace osu.Game.Overlays.Chat.Selection { - public class ChannelSelectionOverlay : OsuFocusedOverlayContainer + public class ChannelSelectionOverlay : WaveOverlayContainer { public static readonly float WIDTH_PADDING = 170; @@ -39,6 +39,11 @@ namespace osu.Game.Overlays.Chat.Selection { RelativeSizeAxes = Axes.X; + Waves.FirstWaveColour = OsuColour.FromHex("353535"); + Waves.SecondWaveColour = OsuColour.FromHex("434343"); + Waves.ThirdWaveColour = OsuColour.FromHex("515151"); + Waves.FourthWaveColour = OsuColour.FromHex("595959"); + Children = new Drawable[] { new Container From 9d8170efa0b69bcbbbccd172130013d248a43428 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 19 Dec 2018 14:32:43 +0900 Subject: [PATCH 71/88] Only go into failing state if previously online --- osu.Game/Online/API/APIAccess.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/osu.Game/Online/API/APIAccess.cs b/osu.Game/Online/API/APIAccess.cs index 7786bb55ac..cfbcf0326a 100644 --- a/osu.Game/Online/API/APIAccess.cs +++ b/osu.Game/Online/API/APIAccess.cs @@ -268,8 +268,12 @@ namespace osu.Game.Online.API //we might try again at an api level. return false; - State = APIState.Failing; - flushQueue(); + if (State == APIState.Online) + { + State = APIState.Failing; + flushQueue(); + } + return true; } From 8d458b0b6e6d5d57047834bfcb06c5576efe7566 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 19 Dec 2018 19:45:50 +0900 Subject: [PATCH 72/88] Update framework version --- osu.Game/osu.Game.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 305c9035b5..8ae644c06a 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -18,7 +18,7 @@ - + From 07f8b8e334d398de787475881cf34b698c7ba879 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 20 Dec 2018 15:47:26 +0900 Subject: [PATCH 73/88] Update resources --- osu-resources | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu-resources b/osu-resources index 694cb03f19..9880089b4e 160000 --- a/osu-resources +++ b/osu-resources @@ -1 +1 @@ -Subproject commit 694cb03f19c93106ed0f2593f3e506e835fb652a +Subproject commit 9880089b4e8fcd78d68f30c8a40d43bf8dccca86 From bb850da2002a9322437fbd209bd139f0e0435bd2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 20 Dec 2018 15:48:45 +0900 Subject: [PATCH 74/88] Remove skinnability for now Not sure if we want this going forward. --- osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs index 4078dce643..ec2839b4ad 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs @@ -14,7 +14,6 @@ using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.UI; -using osu.Game.Skinning; using osuTK; using osuTK.Graphics; @@ -235,15 +234,12 @@ namespace osu.Game.Rulesets.Osu.Mods /// public void AnimateClosedness(float value) => this.TransformTo(nameof(easing), value, 200, Easing.OutQuint); - public class ModBlindsPanel : CompositeDrawable + public class ModBlindsPanel : Sprite { [BackgroundDependencyLoader] private void load(TextureStore textures) { - InternalChild = new SkinnableDrawable("Play/osu/blinds-panel", s => new Sprite { Texture = textures.Get("Play/osu/blinds-panel") }) - { - RelativeSizeAxes = Axes.Both, - }; + Texture = textures.Get("Play/osu/blinds-panel"); } } } From 3a13899ce1d48881cc60035d31a8a9fba20e0b1e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 20 Dec 2018 16:50:38 +0900 Subject: [PATCH 75/88] Add stand-alone chat component --- .../Visual/TestCaseMatchChatDisplay.cs | 83 +++++++++ osu.Game/Online/Chat/StandAloneChatDisplay.cs | 175 ++++++++++++++++++ 2 files changed, 258 insertions(+) create mode 100644 osu.Game.Tests/Visual/TestCaseMatchChatDisplay.cs create mode 100644 osu.Game/Online/Chat/StandAloneChatDisplay.cs diff --git a/osu.Game.Tests/Visual/TestCaseMatchChatDisplay.cs b/osu.Game.Tests/Visual/TestCaseMatchChatDisplay.cs new file mode 100644 index 0000000000..c959eeb3d4 --- /dev/null +++ b/osu.Game.Tests/Visual/TestCaseMatchChatDisplay.cs @@ -0,0 +1,83 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Graphics; +using osu.Game.Online.Chat; +using osu.Game.Users; +using osuTK; + +namespace osu.Game.Tests.Visual +{ + public class TestCaseStandAloneChatDisplay : OsuTestCase + { + private readonly Channel testChannel = new Channel(); + + private readonly User admin = new User + { + Username = "HappyStick", + Id = 2, + Colour = "f2ca34" + }; + + private readonly User redUser = new User + { + Username = "BanchoBot", + Id = 3, + }; + + private readonly User blueUser = new User + { + Username = "Zallius", + Id = 4, + }; + + public TestCaseStandAloneChatDisplay() + { + StandAloneChatDisplay chatDisplay; + + Add(chatDisplay = new StandAloneChatDisplay + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(400, 80) + }); + + chatDisplay.Channel.Value = testChannel; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + AddStep("message from admin", () => testChannel.AddLocalEcho(new LocalEchoMessage + { + Sender = admin, + Content = "I am a wang!" + })); + + AddStep("message from team red", () => testChannel.AddLocalEcho(new LocalEchoMessage + { + Sender = redUser, + Content = "I am team red." + })); + + AddStep("message from team red", () => testChannel.AddLocalEcho(new LocalEchoMessage + { + Sender = redUser, + Content = "I plan to win!" + })); + + AddStep("message from team blue", () => testChannel.AddLocalEcho(new LocalEchoMessage + { + Sender = blueUser, + Content = "Not on my watch. Prepare to eat saaaaaaaaaand. Lots and lots of saaaaaaand." + })); + + AddStep("message from admin", () => testChannel.AddLocalEcho(new LocalEchoMessage + { + Sender = admin, + Content = "Okay okay, calm down guys. Let's do this!" + })); + } + } +} diff --git a/osu.Game/Online/Chat/StandAloneChatDisplay.cs b/osu.Game/Online/Chat/StandAloneChatDisplay.cs new file mode 100644 index 0000000000..30a730c5a1 --- /dev/null +++ b/osu.Game/Online/Chat/StandAloneChatDisplay.cs @@ -0,0 +1,175 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System.Collections.Generic; +using System.Linq; +using osu.Framework.Allocation; +using osu.Framework.Configuration; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Game.Graphics; +using osu.Game.Graphics.Containers; +using osu.Game.Graphics.Sprites; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Online.Chat +{ + /// + /// Display a chat channel in an insolated region. + /// + public class StandAloneChatDisplay : CompositeDrawable + { + public readonly Bindable Channel = new Bindable(); + private readonly FillFlowContainer messagesFlow; + private Channel lastChannel; + + public StandAloneChatDisplay() + { + CornerRadius = 10; + Masking = true; + + InternalChildren = new Drawable[] + { + new Box + { + Colour = Color4.Black, + Alpha = 0.8f, + RelativeSizeAxes = Axes.Both + }, + messagesFlow = new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + LayoutEasing = Easing.Out, + LayoutDuration = 500, + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + Direction = FillDirection.Vertical + } + }; + + Channel.BindValueChanged(channelChanged); + } + + public void Contract() + { + this.FadeIn(300); + this.MoveToY(0, 500, Easing.OutQuint); + } + + public void Expand() + { + this.FadeOut(200); + this.MoveToY(100, 500, Easing.In); + } + + protected virtual Drawable CreateMessage(Message message) + { + return new StandAloneMessage(message); + } + + private void channelChanged(Channel channel) + { + if (lastChannel != null) + lastChannel.NewMessagesArrived -= newMessages; + + lastChannel = channel; + messagesFlow.Clear(); + + if (channel == null) return; + + channel.NewMessagesArrived += newMessages; + } + + private void newMessages(IEnumerable messages) + { + var excessChildren = messagesFlow.Children.Count - 10; + if (excessChildren > 0) + foreach (var c in messagesFlow.Children.Take(excessChildren)) + c.Expire(); + + foreach (var message in messages) + { + var formatted = MessageFormatter.FormatMessage(message); + var drawable = CreateMessage(formatted); + drawable.Y = messagesFlow.Height; + messagesFlow.Add(drawable); + } + } + + protected class StandAloneMessage : CompositeDrawable + { + protected readonly Message Message; + protected OsuSpriteText SenderText; + protected Circle ColourBox; + + public StandAloneMessage(Message message) + { + Message = message; + } + + [BackgroundDependencyLoader] + private void load() + { + Margin = new MarginPadding(3); + + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + + InternalChildren = new Drawable[] + { + new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Horizontal, + Children = new Drawable[] + { + new Container + { + RelativeSizeAxes = Axes.X, + Width = 0.2f, + Children = new Drawable[] + { + SenderText = new OsuSpriteText + { + Font = @"Exo2.0-Bold", + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + Text = Message.Sender.ToString() + } + } + }, + new Container + { + Size = new Vector2(8, OsuSpriteText.FONT_SIZE), + Margin = new MarginPadding { Horizontal = 3 }, + Children = new Drawable[] + { + ColourBox = new Circle + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(8) + } + } + }, + new OsuTextFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Width = 0.5f, + Text = Message.DisplayContent + } + } + } + }; + + if (!string.IsNullOrEmpty(Message.Sender.Colour)) + SenderText.Colour = ColourBox.Colour = OsuColour.FromHex(Message.Sender.Colour); + } + } + } +} From 65447d6f4afcab996dabc0acf74856acbfa0c6f3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 20 Dec 2018 17:01:08 +0900 Subject: [PATCH 76/88] Add optional parameters to target messages at a specific channel --- osu.Game/Online/Chat/ChannelManager.cs | 44 +++++++++++++++----------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index a63af0f7a3..4241b47cd3 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -96,12 +96,14 @@ namespace osu.Game.Online.Chat /// /// The message text that is going to be posted /// Is true if the message is an action, e.g.: user is currently eating - public void PostMessage(string text, bool isAction = false) + /// An optional target channel. If null, will be used. + public void PostMessage(string text, bool isAction = false, Channel target = null) { - if (CurrentChannel.Value == null) - return; + if (target == null) + target = CurrentChannel.Value; - var currentChannel = CurrentChannel.Value; + if (target == null) + return; void dequeueAndRun() { @@ -113,7 +115,7 @@ namespace osu.Game.Online.Chat { if (!api.IsLoggedIn) { - currentChannel.AddNewMessages(new ErrorMessage("Please sign in to participate in chat!")); + target.AddNewMessages(new ErrorMessage("Please sign in to participate in chat!")); return; } @@ -121,29 +123,29 @@ namespace osu.Game.Online.Chat { Sender = api.LocalUser.Value, Timestamp = DateTimeOffset.Now, - ChannelId = CurrentChannel.Value.Id, + ChannelId = target.Id, IsAction = isAction, Content = text }; - currentChannel.AddLocalEcho(message); + target.AddLocalEcho(message); // if this is a PM and the first message, we need to do a special request to create the PM channel - if (currentChannel.Type == ChannelType.PM && !currentChannel.Joined) + if (target.Type == ChannelType.PM && !target.Joined) { - var createNewPrivateMessageRequest = new CreateNewPrivateMessageRequest(currentChannel.Users.First(), message); + var createNewPrivateMessageRequest = new CreateNewPrivateMessageRequest(target.Users.First(), message); createNewPrivateMessageRequest.Success += createRes => { - currentChannel.Id = createRes.ChannelID; - currentChannel.ReplaceMessage(message, createRes.Message); + target.Id = createRes.ChannelID; + target.ReplaceMessage(message, createRes.Message); dequeueAndRun(); }; createNewPrivateMessageRequest.Failure += exception => { Logger.Error(exception, "Posting message failed."); - currentChannel.ReplaceMessage(message, null); + target.ReplaceMessage(message, null); dequeueAndRun(); }; @@ -155,14 +157,14 @@ namespace osu.Game.Online.Chat req.Success += m => { - currentChannel.ReplaceMessage(message, m); + target.ReplaceMessage(message, m); dequeueAndRun(); }; req.Failure += exception => { Logger.Error(exception, "Posting message failed."); - currentChannel.ReplaceMessage(message, null); + target.ReplaceMessage(message, null); dequeueAndRun(); }; @@ -178,9 +180,13 @@ namespace osu.Game.Online.Chat /// Posts a command locally. Commands like /help will result in a help message written in the current channel. /// /// the text containing the command identifier and command parameters. - public void PostCommand(string text) + /// An optional target channel. If null, will be used. + public void PostCommand(string text, Channel target = null) { - if (CurrentChannel.Value == null) + if (target == null) + target = CurrentChannel.Value; + + if (target == null) return; var parameters = text.Split(new[] { ' ' }, 2); @@ -192,7 +198,7 @@ namespace osu.Game.Online.Chat case "me": if (string.IsNullOrWhiteSpace(content)) { - CurrentChannel.Value.AddNewMessages(new ErrorMessage("Usage: /me [action]")); + target.AddNewMessages(new ErrorMessage("Usage: /me [action]")); break; } @@ -200,11 +206,11 @@ namespace osu.Game.Online.Chat break; case "help": - CurrentChannel.Value.AddNewMessages(new InfoMessage("Supported commands: /help, /me [action]")); + target.AddNewMessages(new InfoMessage("Supported commands: /help, /me [action]")); break; default: - CurrentChannel.Value.AddNewMessages(new ErrorMessage($@"""/{command}"" is not supported! For a list of supported commands see /help")); + target.AddNewMessages(new ErrorMessage($@"""/{command}"" is not supported! For a list of supported commands see /help")); break; } } From bc8b0485d8cf58772d76aae94060baaded4a9430 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 20 Dec 2018 18:21:37 +0900 Subject: [PATCH 77/88] Add textbox/posting support --- ...ay.cs => TestCaseStandAloneChatDisplay.cs} | 27 ++++++++-- osu.Game/Online/Chat/StandAloneChatDisplay.cs | 54 ++++++++++++++++++- 2 files changed, 76 insertions(+), 5 deletions(-) rename osu.Game.Tests/Visual/{TestCaseMatchChatDisplay.cs => TestCaseStandAloneChatDisplay.cs} (73%) diff --git a/osu.Game.Tests/Visual/TestCaseMatchChatDisplay.cs b/osu.Game.Tests/Visual/TestCaseStandAloneChatDisplay.cs similarity index 73% rename from osu.Game.Tests/Visual/TestCaseMatchChatDisplay.cs rename to osu.Game.Tests/Visual/TestCaseStandAloneChatDisplay.cs index c959eeb3d4..16ce720ab1 100644 --- a/osu.Game.Tests/Visual/TestCaseMatchChatDisplay.cs +++ b/osu.Game.Tests/Visual/TestCaseStandAloneChatDisplay.cs @@ -1,6 +1,7 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Game.Online.Chat; using osu.Game.Users; @@ -31,24 +32,42 @@ namespace osu.Game.Tests.Visual Id = 4, }; + [Cached] + private ChannelManager channelManager = new ChannelManager(); + + private readonly StandAloneChatDisplay chatDisplay; + private readonly StandAloneChatDisplay chatDisplay2; + public TestCaseStandAloneChatDisplay() { - StandAloneChatDisplay chatDisplay; + Add(channelManager); Add(chatDisplay = new StandAloneChatDisplay { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Margin = new MarginPadding(20), Size = new Vector2(400, 80) }); - chatDisplay.Channel.Value = testChannel; + Add(chatDisplay2 = new StandAloneChatDisplay(true) + { + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + Margin = new MarginPadding(20), + Size = new Vector2(400, 150) + }); } protected override void LoadComplete() { base.LoadComplete(); + channelManager.CurrentChannel.Value = testChannel; + + chatDisplay.Channel.Value = testChannel; + chatDisplay2.Channel.Value = testChannel; + AddStep("message from admin", () => testChannel.AddLocalEcho(new LocalEchoMessage { Sender = admin, diff --git a/osu.Game/Online/Chat/StandAloneChatDisplay.cs b/osu.Game/Online/Chat/StandAloneChatDisplay.cs index 30a730c5a1..cb4bf9fdf8 100644 --- a/osu.Game/Online/Chat/StandAloneChatDisplay.cs +++ b/osu.Game/Online/Chat/StandAloneChatDisplay.cs @@ -8,9 +8,11 @@ using osu.Framework.Configuration; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.UserInterface; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; using osuTK; using osuTK.Graphics; @@ -22,10 +24,20 @@ namespace osu.Game.Online.Chat public class StandAloneChatDisplay : CompositeDrawable { public readonly Bindable Channel = new Bindable(); + private readonly FillFlowContainer messagesFlow; + private Channel lastChannel; - public StandAloneChatDisplay() + private readonly FocusedTextBox textbox; + + protected ChannelManager ChannelManager; + + /// + /// Construct a new instance. + /// + /// Whether a textbox for posting new messages should be displayed. + public StandAloneChatDisplay(bool postingTextbox = false) { CornerRadius = 10; Masking = true; @@ -50,9 +62,49 @@ namespace osu.Game.Online.Chat } }; + const float textbox_height = 30; + + if (postingTextbox) + { + messagesFlow.Y -= textbox_height; + AddInternal(textbox = new FocusedTextBox + { + RelativeSizeAxes = Axes.X, + Height = textbox_height, + PlaceholderText = "type your message", + OnCommit = postMessage, + ReleaseFocusOnCommit = false, + HoldFocus = true, + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + }); + } + Channel.BindValueChanged(channelChanged); } + [BackgroundDependencyLoader(true)] + private void load(ChannelManager manager) + { + if (ChannelManager == null) + ChannelManager = manager; + } + + private void postMessage(TextBox sender, bool newtext) + { + var text = textbox.Text.Trim(); + + if (string.IsNullOrWhiteSpace(text)) + return; + + if (text[0] == '/') + ChannelManager?.PostCommand(text.Substring(1)); + else + ChannelManager?.PostMessage(text); + + textbox.Text = string.Empty; + } + public void Contract() { this.FadeIn(300); From d3368df94dd3338cbe611304185a773b89bf7df6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 20 Dec 2018 19:35:32 +0900 Subject: [PATCH 78/88] Simplify changes to RulesetContainer --- osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs | 4 +-- osu.Game/Rulesets/UI/RulesetContainer.cs | 35 ++++++++++------------ osu.Game/Screens/Play/Player.cs | 1 - 3 files changed, 17 insertions(+), 23 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs index ec2839b4ad..f6c2c1215d 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs @@ -35,8 +35,8 @@ namespace osu.Game.Rulesets.Osu.Mods public void ApplyToRulesetContainer(RulesetContainer rulesetContainer) { - bool hasEasy = rulesetContainer.ActiveMods.Any(m => m is ModEasy); - bool hasHardrock = rulesetContainer.ActiveMods.Any(m => m is ModHardRock); + bool hasEasy = rulesetContainer.Mods.Any(m => m is ModEasy); + bool hasHardrock = rulesetContainer.Mods.Any(m => m is ModHardRock); rulesetContainer.Overlays.Add(blinds = new DrawableOsuBlinds(rulesetContainer.Playfield.HitObjectContainer, hasEasy, hasHardrock, rulesetContainer.Beatmap)); } diff --git a/osu.Game/Rulesets/UI/RulesetContainer.cs b/osu.Game/Rulesets/UI/RulesetContainer.cs index 67bcb7581f..22d4eee5e4 100644 --- a/osu.Game/Rulesets/UI/RulesetContainer.cs +++ b/osu.Game/Rulesets/UI/RulesetContainer.cs @@ -71,7 +71,7 @@ namespace osu.Game.Rulesets.UI /// /// Place to put drawables above hit objects but below UI. /// - public readonly Container Overlays; + public Container Overlays { get; protected set; } /// /// The cursor provided by this . May be null if no cursor is provided. @@ -92,12 +92,6 @@ namespace osu.Game.Rulesets.UI { Ruleset = ruleset; playfield = new Lazy(CreatePlayfield); - Overlays = new Container - { - RelativeSizeAxes = Axes.Both, - Width = 1, - Height = 1 - }; IsPaused.ValueChanged += paused => { @@ -215,7 +209,7 @@ namespace osu.Game.Rulesets.UI /// /// The mods which are to be applied. /// - protected IEnumerable Mods; + public IEnumerable Mods { get; protected set; } /// /// The this was created with. @@ -226,7 +220,6 @@ namespace osu.Game.Rulesets.UI protected override Container Content => content; private Container content; - private IEnumerable mods; /// /// Whether to assume the beatmap passed into this is for the current ruleset. @@ -256,17 +249,24 @@ namespace osu.Game.Rulesets.UI [BackgroundDependencyLoader] private void load(OsuConfigManager config) { - KeyBindingInputManager.Add(content = new Container + KeyBindingInputManager.Children = new Drawable[] { - RelativeSizeAxes = Axes.Both, - }); - - AddInternal(KeyBindingInputManager); - KeyBindingInputManager.Add(Playfield); + content = new Container + { + RelativeSizeAxes = Axes.Both, + }, + Playfield + }; if (Cursor != null) KeyBindingInputManager.Add(Cursor); + InternalChildren = new Drawable[] + { + KeyBindingInputManager, + Overlays = new Container { RelativeSizeAxes = Axes.Both } + }; + // Apply mods applyRulesetMods(Mods, config); @@ -324,11 +324,6 @@ namespace osu.Game.Rulesets.UI mod.ApplyToDrawableHitObjects(Playfield.HitObjectContainer.Objects); } - /// - /// Returns the currently selected mods for this ruleset container. - /// - public IEnumerable ActiveMods { get => Mods; } - /// /// Creates and adds the visual representation of a to this . /// diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index fd2c94e814..19b49b099c 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -184,7 +184,6 @@ namespace osu.Game.Screens.Play RelativeSizeAxes = Axes.Both, Child = RulesetContainer }, - RulesetContainer.Overlays, new BreakOverlay(beatmap.BeatmapInfo.LetterboxInBreaks, ScoreProcessor) { Anchor = Anchor.Centre, From ef9d93ff6b93ec3eacd500e509728f2f9ca04eea Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 20 Dec 2018 19:46:39 +0900 Subject: [PATCH 79/88] Remove mod multipliers We decided that mods shouldn't be interacting with other mods. This can be added once we have the ability to have per-mod settings, as a difficulty setting local to blinds. --- osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs | 71 +++------------------- osu.Game/Rulesets/UI/RulesetContainer.cs | 2 +- 2 files changed, 10 insertions(+), 63 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs index f6c2c1215d..cc2102f0e9 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs @@ -1,7 +1,6 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using System.Linq; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -35,10 +34,7 @@ namespace osu.Game.Rulesets.Osu.Mods public void ApplyToRulesetContainer(RulesetContainer rulesetContainer) { - bool hasEasy = rulesetContainer.Mods.Any(m => m is ModEasy); - bool hasHardrock = rulesetContainer.Mods.Any(m => m is ModHardRock); - - rulesetContainer.Overlays.Add(blinds = new DrawableOsuBlinds(rulesetContainer.Playfield.HitObjectContainer, hasEasy, hasHardrock, rulesetContainer.Beatmap)); + rulesetContainer.Overlays.Add(blinds = new DrawableOsuBlinds(rulesetContainer.Playfield.HitObjectContainer, rulesetContainer.Beatmap)); } public void ApplyToScoreProcessor(ScoreProcessor scoreProcessor) @@ -69,12 +65,7 @@ namespace osu.Game.Rulesets.Osu.Mods private readonly float targetBreakMultiplier = 0; private readonly float easing = 1; - private const float black_depth = 10; - private const float bg_panel_depth = 8; - private const float fg_panel_depth = 4; - private readonly CompositeDrawable restrictTo; - private readonly bool modEasy, modHardrock; /// /// @@ -89,13 +80,10 @@ namespace osu.Game.Rulesets.Osu.Mods /// private const float leniency = 0.1f; - public DrawableOsuBlinds(CompositeDrawable restrictTo, bool hasEasy, bool hasHardrock, Beatmap beatmap) + public DrawableOsuBlinds(CompositeDrawable restrictTo, Beatmap beatmap) { this.restrictTo = restrictTo; this.beatmap = beatmap; - - modEasy = hasEasy; - modHardrock = hasHardrock; } [BackgroundDependencyLoader] @@ -111,9 +99,6 @@ namespace osu.Game.Rulesets.Osu.Mods Origin = Anchor.TopLeft, Colour = Color4.Black, RelativeSizeAxes = Axes.Y, - Width = 0, - Height = 1, - Depth = black_depth }, blackBoxRight = new Box { @@ -121,60 +106,22 @@ namespace osu.Game.Rulesets.Osu.Mods Origin = Anchor.TopRight, Colour = Color4.Black, RelativeSizeAxes = Axes.Y, - Width = 0, - Height = 1, - Depth = black_depth }, bgPanelLeft = new ModBlindsPanel { Origin = Anchor.TopRight, Colour = Color4.Gray, - Depth = bg_panel_depth + 1 - }, - panelLeft = new ModBlindsPanel - { - Origin = Anchor.TopRight, - Depth = bg_panel_depth - }, - bgPanelRight = new ModBlindsPanel - { - Origin = Anchor.TopLeft, - Colour = Color4.Gray, - Depth = fg_panel_depth + 1 - }, - panelRight = new ModBlindsPanel - { - Origin = Anchor.TopLeft, - Depth = fg_panel_depth }, + panelLeft = new ModBlindsPanel { Origin = Anchor.TopRight, }, + bgPanelRight = new ModBlindsPanel { Colour = Color4.Gray }, + panelRight = new ModBlindsPanel() }; } - private float applyGap(float value) - { - const float easy_multiplier = 0.95f; - const float hardrock_multiplier = 1.1f; + private float calculateGap(float value) => MathHelper.Clamp(value, 0, target_clamp) * targetBreakMultiplier; - float multiplier = 1; - if (modEasy) - { - multiplier = easy_multiplier; - // TODO: include OD/CS - } - else if (modHardrock) - { - multiplier = hardrock_multiplier; - // TODO: include OD/CS - } - - return MathHelper.Clamp(value * multiplier, 0, target_clamp) * targetBreakMultiplier; - } - - private static float applyAdjustmentCurve(float value) - { - // lagrange polinominal for (0,0) (0.5,0.35) (1,1) should make a good curve - return 0.6f * value * value + 0.4f * value; - } + // lagrange polinominal for (0,0) (0.6,0.4) (1,1) should make a good curve + private static float applyAdjustmentCurve(float value) => 0.6f * value * value + 0.4f * value; protected override void Update() { @@ -186,7 +133,7 @@ namespace osu.Game.Rulesets.Osu.Mods start -= rawWidth * leniency * 0.5f; end += rawWidth * leniency * 0.5f; - float width = (end - start) * 0.5f * applyAdjustmentCurve(applyGap(easing)); + float width = (end - start) * 0.5f * applyAdjustmentCurve(calculateGap(easing)); // different values in case the playfield ever moves from center to somewhere else. blackBoxLeft.Width = start + width; diff --git a/osu.Game/Rulesets/UI/RulesetContainer.cs b/osu.Game/Rulesets/UI/RulesetContainer.cs index 22d4eee5e4..56222ff282 100644 --- a/osu.Game/Rulesets/UI/RulesetContainer.cs +++ b/osu.Game/Rulesets/UI/RulesetContainer.cs @@ -209,7 +209,7 @@ namespace osu.Game.Rulesets.UI /// /// The mods which are to be applied. /// - public IEnumerable Mods { get; protected set; } + protected IEnumerable Mods; /// /// The this was created with. From 36f57a7abbd4155a31c3db8f4d2b4d03b5cea7ce Mon Sep 17 00:00:00 2001 From: Paul Teng Date: Thu, 20 Dec 2018 05:49:05 -0500 Subject: [PATCH 80/88] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index baaba22726..a2f6472371 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ We are accepting bug reports (please report with as much detail as possible). Fe # Requirements -- A desktop platform with the [.NET Core SDK 2.1](https://www.microsoft.com/net/learn/get-started) or higher installed. +- A desktop platform with the [.NET Core SDK 2.2](https://www.microsoft.com/net/learn/get-started) or higher installed. - When working with the codebase, we recommend using an IDE with intellisense and syntax highlighting, such as [Visual Studio Community Edition](https://www.visualstudio.com/) (Windows), [Visual Studio Code](https://code.visualstudio.com/) (with the C# plugin installed) or [Jetbrains Rider](https://www.jetbrains.com/rider/) (commercial). # Building and running From aaac45ab8cb384402c068dcc2226121fdf0affbf Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 20 Dec 2018 21:06:40 +0900 Subject: [PATCH 81/88] Add ability to select chat tabs with alt-1-9 --- osu.Game/Graphics/UserInterface/Nub.cs | 16 ++++++++++- osu.Game/Overlays/ChatOverlay.cs | 37 ++++++++++++++++++++++++- osu.Game/Overlays/Volume/MuteButton.cs | 16 ++++++++++- osu.Game/Screens/Play/HUD/ModDisplay.cs | 24 ++++++++++++---- 4 files changed, 84 insertions(+), 9 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/Nub.cs b/osu.Game/Graphics/UserInterface/Nub.cs index 974708af97..b715c80fb6 100644 --- a/osu.Game/Graphics/UserInterface/Nub.cs +++ b/osu.Game/Graphics/UserInterface/Nub.cs @@ -1,6 +1,7 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System; using osuTK; using osuTK.Graphics; using osu.Framework.Allocation; @@ -99,7 +100,20 @@ namespace osu.Game.Graphics.UserInterface } } - public Bindable Current { get; } = new Bindable(); + private readonly Bindable current = new Bindable(); + + public Bindable Current + { + get => current; + set + { + if (value == null) + throw new ArgumentNullException(nameof(value)); + + current.UnbindBindings(); + current.BindTo(value); + } + } private Color4 accentColour; public Color4 AccentColour diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs index 75e22f85d1..680e7ac416 100644 --- a/osu.Game/Overlays/ChatOverlay.cs +++ b/osu.Game/Overlays/ChatOverlay.cs @@ -2,6 +2,7 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System.Collections.Generic; +using System.Linq; using osuTK; using osuTK.Graphics; using osu.Framework.Allocation; @@ -19,6 +20,7 @@ using osu.Game.Online.Chat; using osu.Game.Overlays.Chat; using osu.Game.Overlays.Chat.Selection; using osu.Game.Overlays.Chat.Tabs; +using osuTK.Input; namespace osu.Game.Overlays { @@ -222,7 +224,7 @@ namespace osu.Game.Overlays else { currentChannelContainer.Clear(false); - Scheduler.Add(() => currentChannelContainer.Add(loaded)); + currentChannelContainer.Add(loaded); } } @@ -262,6 +264,39 @@ namespace osu.Game.Overlays return base.OnDragEnd(e); } + private void selectTab(int index) + { + var channel = channelTabControl.Items.Skip(index).FirstOrDefault(); + if (channel != null && channel.Name != "+") + channelTabControl.Current.Value = channel; + } + + protected override bool OnKeyDown(KeyDownEvent e) + { + if (e.AltPressed) + { + switch (e.Key) + { + case Key.Number1: + case Key.Number2: + case Key.Number3: + case Key.Number4: + case Key.Number5: + case Key.Number6: + case Key.Number7: + case Key.Number8: + case Key.Number9: + selectTab((int)e.Key - (int)Key.Number1); + return true; + case Key.Number0: + selectTab(9); + return true; + } + } + + return base.OnKeyDown(e); + } + public override bool AcceptsFocus => true; protected override void OnFocus(FocusEvent e) diff --git a/osu.Game/Overlays/Volume/MuteButton.cs b/osu.Game/Overlays/Volume/MuteButton.cs index e31b349827..dddfddedef 100644 --- a/osu.Game/Overlays/Volume/MuteButton.cs +++ b/osu.Game/Overlays/Volume/MuteButton.cs @@ -1,6 +1,7 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System; using osu.Framework.Allocation; using osu.Framework.Configuration; using osu.Framework.Extensions.Color4Extensions; @@ -18,7 +19,20 @@ namespace osu.Game.Overlays.Volume { public class MuteButton : Container, IHasCurrentValue { - public Bindable Current { get; } = new Bindable(); + private readonly Bindable current = new Bindable(); + + public Bindable Current + { + get => current; + set + { + if (value == null) + throw new ArgumentNullException(nameof(value)); + + current.UnbindBindings(); + current.BindTo(value); + } + } private Color4 hoveredColour, unhoveredColour; private const float width = 100; diff --git a/osu.Game/Screens/Play/HUD/ModDisplay.cs b/osu.Game/Screens/Play/HUD/ModDisplay.cs index 9509c7acae..c6f39b4705 100644 --- a/osu.Game/Screens/Play/HUD/ModDisplay.cs +++ b/osu.Game/Screens/Play/HUD/ModDisplay.cs @@ -1,7 +1,9 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System; using System.Collections.Generic; +using System.Linq; using osu.Framework.Configuration; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -11,7 +13,6 @@ using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.UI; using osuTK; using osu.Game.Graphics.Containers; -using System.Linq; using osu.Framework.Input.Events; namespace osu.Game.Screens.Play.HUD @@ -20,9 +21,20 @@ namespace osu.Game.Screens.Play.HUD { private const int fade_duration = 1000; - private readonly Bindable> mods = new Bindable>(); + private readonly Bindable> current = new Bindable>(); - public Bindable> Current => mods; + public Bindable> Current + { + get => current; + set + { + if (value == null) + throw new ArgumentNullException(nameof(value)); + + current.UnbindBindings(); + current.BindTo(value); + } + } private readonly FillFlowContainer iconsContainer; private readonly OsuSpriteText unrankedText; @@ -50,7 +62,7 @@ namespace osu.Game.Screens.Play.HUD } }; - mods.ValueChanged += mods => + Current.ValueChanged += mods => { iconsContainer.Clear(); foreach (Mod mod in mods) @@ -66,7 +78,7 @@ namespace osu.Game.Screens.Play.HUD protected override void Dispose(bool isDisposing) { base.Dispose(isDisposing); - mods.UnbindAll(); + Current.UnbindAll(); } protected override void LoadComplete() @@ -77,7 +89,7 @@ namespace osu.Game.Screens.Play.HUD private void appearTransform() { - if (mods.Value.Any(m => !m.Ranked)) + if (Current.Value.Any(m => !m.Ranked)) unrankedText.FadeInFromZero(fade_duration, Easing.OutQuint); else unrankedText.Hide(); From e26958f90164e3979d97a72458061b4850731561 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 21 Dec 2018 10:23:44 +0900 Subject: [PATCH 82/88] Fix targeting netcoreapp2.1 in many places --- .../runConfigurations/RulesetTests__catch_.xml | 2 +- .../runConfigurations/RulesetTests__mania_.xml | 2 +- .../runConfigurations/RulesetTests__osu__.xml | 2 +- .../runConfigurations/RulesetTests__taiko_.xml | 2 +- .../.idea/runConfigurations/VisualTests.xml | 2 +- .vscode/launch.json | 16 ++++++++-------- .vscode/tasks.json | 6 +----- .../.vscode/launch.json | 4 ++-- .../.vscode/launch.json | 4 ++-- osu.Game.Rulesets.Osu.Tests/.vscode/launch.json | 4 ++-- .../.vscode/launch.json | 4 ++-- 11 files changed, 22 insertions(+), 26 deletions(-) diff --git a/.idea/.idea.osu/.idea/runConfigurations/RulesetTests__catch_.xml b/.idea/.idea.osu/.idea/runConfigurations/RulesetTests__catch_.xml index 1c988fe6fd..2eff16cc91 100644 --- a/.idea/.idea.osu/.idea/runConfigurations/RulesetTests__catch_.xml +++ b/.idea/.idea.osu/.idea/runConfigurations/RulesetTests__catch_.xml @@ -1,6 +1,6 @@ -