From e71a9668a537b2616b71b8f192c37671e2447553 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sun, 5 Apr 2020 21:32:55 +0300 Subject: [PATCH 01/14] Disallow draining in non-draining sections --- .../Scoring/DrainingHealthProcessor.cs | 57 ++++++++++++++++--- 1 file changed, 50 insertions(+), 7 deletions(-) diff --git a/osu.Game/Rulesets/Scoring/DrainingHealthProcessor.cs b/osu.Game/Rulesets/Scoring/DrainingHealthProcessor.cs index fffcbb3c9f..b36e42326c 100644 --- a/osu.Game/Rulesets/Scoring/DrainingHealthProcessor.cs +++ b/osu.Game/Rulesets/Scoring/DrainingHealthProcessor.cs @@ -3,7 +3,9 @@ using System; using System.Collections.Generic; +using System.Linq; using osu.Game.Beatmaps; +using osu.Game.Beatmaps.Timing; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Objects; @@ -47,6 +49,34 @@ namespace osu.Game.Rulesets.Scoring private double targetMinimumHealth; private double drainRate = 1; + private readonly List<(double startTime, double endTime)> nonDrainSections = new List<(double, double)>(); + private int currentNonDrainSection; + + private bool isInNonDrainSection + { + get + { + if (nonDrainSections.Count == 0) + return false; + + var time = Time.Current; + + if (time > nonDrainSections[currentNonDrainSection].endTime) + { + while (time > nonDrainSections[currentNonDrainSection].endTime && currentNonDrainSection < nonDrainSections.Count - 1) + currentNonDrainSection++; + } + else + { + while (time < nonDrainSections[currentNonDrainSection].startTime && currentNonDrainSection > 0) + currentNonDrainSection--; + } + + var closestSection = nonDrainSections[currentNonDrainSection]; + return time >= closestSection.startTime && time <= closestSection.endTime; + } + } + /// /// Creates a new . /// @@ -60,23 +90,36 @@ namespace osu.Game.Rulesets.Scoring { base.Update(); - if (!IsBreakTime.Value) - { - // When jumping in and out of gameplay time within a single frame, health should only be drained for the period within the gameplay time - double lastGameplayTime = Math.Clamp(Time.Current - Time.Elapsed, drainStartTime, gameplayEndTime); - double currentGameplayTime = Math.Clamp(Time.Current, drainStartTime, gameplayEndTime); + if (isInNonDrainSection) + return; - Health.Value -= drainRate * (currentGameplayTime - lastGameplayTime); - } + // When jumping in and out of gameplay time within a single frame, health should only be drained for the period within the gameplay time + double lastGameplayTime = Math.Clamp(Time.Current - Time.Elapsed, drainStartTime, gameplayEndTime); + double currentGameplayTime = Math.Clamp(Time.Current, drainStartTime, gameplayEndTime); + + Health.Value -= drainRate * (currentGameplayTime - lastGameplayTime); } public override void ApplyBeatmap(IBeatmap beatmap) { + nonDrainSections.Clear(); + this.beatmap = beatmap; if (beatmap.HitObjects.Count > 0) gameplayEndTime = beatmap.HitObjects[^1].GetEndTime(); + // Ranges between the end of last hit object before a break + // and the start of first hit object after a break should + // not allow HP draining. (with break periods in) + foreach (BreakPeriod b in beatmap.Breaks) + { + var startTime = beatmap.HitObjects.LastOrDefault(h => h.GetEndTime() < b.StartTime)?.GetEndTime() ?? double.MinValue; + var endTime = beatmap.HitObjects.FirstOrDefault(h => h.StartTime > b.EndTime)?.StartTime ?? double.MaxValue; + + nonDrainSections.Add((startTime, endTime)); + } + targetMinimumHealth = BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.DrainRate, min_health_target, mid_health_target, max_health_target); base.ApplyBeatmap(beatmap); From 7fab07670ed8ff6725bc4b8c1c543e0101af9664 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sun, 5 Apr 2020 21:35:09 +0300 Subject: [PATCH 02/14] Remove no longer necessary usage of IsBreakTime --- osu.Game/Rulesets/Scoring/HealthProcessor.cs | 5 ----- osu.Game/Screens/Play/Player.cs | 2 -- 2 files changed, 7 deletions(-) diff --git a/osu.Game/Rulesets/Scoring/HealthProcessor.cs b/osu.Game/Rulesets/Scoring/HealthProcessor.cs index 45edc0f4a3..1535fe4d00 100644 --- a/osu.Game/Rulesets/Scoring/HealthProcessor.cs +++ b/osu.Game/Rulesets/Scoring/HealthProcessor.cs @@ -26,11 +26,6 @@ namespace osu.Game.Rulesets.Scoring /// public readonly BindableDouble Health = new BindableDouble(1) { MinValue = 0, MaxValue = 1 }; - /// - /// Whether gameplay is currently in a break. - /// - public readonly IBindable IsBreakTime = new Bindable(); - /// /// Whether this ScoreProcessor has already triggered the failed state. /// diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 4597ae760c..f2051790db 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -243,8 +243,6 @@ namespace osu.Game.Screens.Play Breaks = working.Beatmap.Breaks } }); - - HealthProcessor.IsBreakTime.BindTo(breakTracker.IsBreakTime); } private void addOverlayComponents(Container target, WorkingBeatmap working) From c902ba40860b2757ea960925322bf9731b4eeefc Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sun, 5 Apr 2020 21:46:07 +0300 Subject: [PATCH 03/14] Add test cases for HP draining not applied before a break and after it --- .../TestSceneDrainingHealthProcessor.cs | 87 ++++++++++++++----- 1 file changed, 66 insertions(+), 21 deletions(-) diff --git a/osu.Game.Tests/Gameplay/TestSceneDrainingHealthProcessor.cs b/osu.Game.Tests/Gameplay/TestSceneDrainingHealthProcessor.cs index 885abb61b5..2f83ea4832 100644 --- a/osu.Game.Tests/Gameplay/TestSceneDrainingHealthProcessor.cs +++ b/osu.Game.Tests/Gameplay/TestSceneDrainingHealthProcessor.cs @@ -1,13 +1,15 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.Collections.Generic; +using System.Linq; using NUnit.Framework; -using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Utils; using osu.Framework.Testing; using osu.Framework.Timing; using osu.Game.Beatmaps; +using osu.Game.Beatmaps.Timing; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Scoring; @@ -18,7 +20,6 @@ namespace osu.Game.Tests.Gameplay [HeadlessTest] public class TestSceneDrainingHealthProcessor : OsuTestScene { - private Bindable breakTime; private HealthProcessor processor; private ManualClock clock; @@ -41,6 +42,55 @@ namespace osu.Game.Tests.Gameplay assertHealthEqualTo(1); } + [Test] + public void TestHealthNotDrainedBeforeBreak() + { + createProcessor(createBeatmap(0, 2000, + new BreakPeriod(400, 600), new BreakPeriod(1200, 1400))); + + setTime(300); + setHealth(1); + + setTime(400); + assertHealthEqualTo(1); + + setTime(1100); + setHealth(1); + + setTime(1200); + assertHealthEqualTo(1); + } + + [Test] + public void TestHealthNotDrainedDuringBreak() + { + createProcessor(createBeatmap(0, 2000, new BreakPeriod(0, 1200))); + + setTime(700); + assertHealthEqualTo(1); + setTime(900); + assertHealthEqualTo(1); + } + + [Test] + public void TestHealthNotDrainedAfterBreak() + { + createProcessor(createBeatmap(0, 2000, + new BreakPeriod(400, 600), new BreakPeriod(1200, 1400))); + + setTime(600); + setHealth(1); + + setTime(700); + assertHealthEqualTo(1); + + setTime(1400); + setHealth(1); + + setTime(1500); + assertHealthEqualTo(1); + } + [Test] public void TestHealthNotDrainedAfterGameplayEnd() { @@ -54,18 +104,6 @@ namespace osu.Game.Tests.Gameplay assertHealthEqualTo(1); } - [Test] - public void TestHealthNotDrainedDuringBreak() - { - createProcessor(createBeatmap(0, 2000)); - setBreak(true); - - setTime(700); - assertHealthEqualTo(1); - setTime(900); - assertHealthEqualTo(1); - } - [Test] public void TestHealthDrainedDuringGameplay() { @@ -112,30 +150,39 @@ namespace osu.Game.Tests.Gameplay assertHealthNotEqualTo(1); } - private Beatmap createBeatmap(double startTime, double endTime) + private Beatmap createBeatmap(double startTime, double endTime, params BreakPeriod[] breaks) { var beatmap = new Beatmap { BeatmapInfo = { BaseDifficulty = { DrainRate = 5 } }, }; - for (double time = startTime; time <= endTime; time += 100) + double time = startTime; + + while (time <= endTime) + { beatmap.HitObjects.Add(new JudgeableHitObject { StartTime = time }); + // leave a 100ms gap between the start and end of a break period. + time += (getCurrentBreak(breaks, time)?.Duration ?? 0) + 100; + } + + beatmap.Breaks.AddRange(breaks); + + static BreakPeriod getCurrentBreak(IEnumerable breaks, double time) => + breaks?.FirstOrDefault(b => time >= b.StartTime && time <= b.EndTime); + return beatmap; } private void createProcessor(Beatmap beatmap) => AddStep("create processor", () => { - breakTime = new Bindable(); - Child = processor = new DrainingHealthProcessor(beatmap.HitObjects[0].StartTime).With(d => { d.RelativeSizeAxes = Axes.Both; d.Clock = new FramedClock(clock = new ManualClock()); }); - processor.IsBreakTime.BindTo(breakTime); processor.ApplyBeatmap(beatmap); }); @@ -143,8 +190,6 @@ namespace osu.Game.Tests.Gameplay private void setHealth(double health) => AddStep($"set health = {health}", () => processor.Health.Value = health); - private void setBreak(bool enabled) => AddStep($"{(enabled ? "enable" : "disable")} break", () => breakTime.Value = enabled); - private void assertHealthEqualTo(double value) => AddAssert($"health = {value}", () => Precision.AlmostEquals(value, processor.Health.Value, 0.0001f)); From 1d999bb634de168c5acb1f3abbc5fd12d5596e31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 10 May 2020 18:32:38 +0200 Subject: [PATCH 04/14] Integrate PeriodTracker changes --- .../Scoring/DrainingHealthProcessor.cs | 56 +++++-------------- 1 file changed, 15 insertions(+), 41 deletions(-) diff --git a/osu.Game/Rulesets/Scoring/DrainingHealthProcessor.cs b/osu.Game/Rulesets/Scoring/DrainingHealthProcessor.cs index b36e42326c..1958efdd6f 100644 --- a/osu.Game/Rulesets/Scoring/DrainingHealthProcessor.cs +++ b/osu.Game/Rulesets/Scoring/DrainingHealthProcessor.cs @@ -5,9 +5,9 @@ using System; using System.Collections.Generic; using System.Linq; using osu.Game.Beatmaps; -using osu.Game.Beatmaps.Timing; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Objects; +using osu.Game.Utils; namespace osu.Game.Rulesets.Scoring { @@ -49,33 +49,7 @@ namespace osu.Game.Rulesets.Scoring private double targetMinimumHealth; private double drainRate = 1; - private readonly List<(double startTime, double endTime)> nonDrainSections = new List<(double, double)>(); - private int currentNonDrainSection; - - private bool isInNonDrainSection - { - get - { - if (nonDrainSections.Count == 0) - return false; - - var time = Time.Current; - - if (time > nonDrainSections[currentNonDrainSection].endTime) - { - while (time > nonDrainSections[currentNonDrainSection].endTime && currentNonDrainSection < nonDrainSections.Count - 1) - currentNonDrainSection++; - } - else - { - while (time < nonDrainSections[currentNonDrainSection].startTime && currentNonDrainSection > 0) - currentNonDrainSection--; - } - - var closestSection = nonDrainSections[currentNonDrainSection]; - return time >= closestSection.startTime && time <= closestSection.endTime; - } - } + private PeriodTracker noDrainPeriodTracker; /// /// Creates a new . @@ -90,7 +64,7 @@ namespace osu.Game.Rulesets.Scoring { base.Update(); - if (isInNonDrainSection) + if (noDrainPeriodTracker?.IsInAny(Time.Current) == true) return; // When jumping in and out of gameplay time within a single frame, health should only be drained for the period within the gameplay time @@ -102,23 +76,23 @@ namespace osu.Game.Rulesets.Scoring public override void ApplyBeatmap(IBeatmap beatmap) { - nonDrainSections.Clear(); - this.beatmap = beatmap; if (beatmap.HitObjects.Count > 0) gameplayEndTime = beatmap.HitObjects[^1].GetEndTime(); - // Ranges between the end of last hit object before a break - // and the start of first hit object after a break should - // not allow HP draining. (with break periods in) - foreach (BreakPeriod b in beatmap.Breaks) - { - var startTime = beatmap.HitObjects.LastOrDefault(h => h.GetEndTime() < b.StartTime)?.GetEndTime() ?? double.MinValue; - var endTime = beatmap.HitObjects.FirstOrDefault(h => h.StartTime > b.EndTime)?.StartTime ?? double.MaxValue; - - nonDrainSections.Add((startTime, endTime)); - } + noDrainPeriodTracker = new PeriodTracker(beatmap.Breaks.Select(breakPeriod => new Period( + beatmap.HitObjects + .Select(hitObject => hitObject.GetEndTime()) + .Where(endTime => endTime < breakPeriod.StartTime) + .DefaultIfEmpty(double.MinValue) + .Last(), + beatmap.HitObjects + .Select(hitObject => hitObject.StartTime) + .Where(startTime => startTime > breakPeriod.EndTime) + .DefaultIfEmpty(double.MaxValue) + .First() + ))); targetMinimumHealth = BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.DrainRate, min_health_target, mid_health_target, max_health_target); From e650b10b5e1adfb00123064e043d5768eb0e409f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 11 May 2020 19:03:13 +0200 Subject: [PATCH 05/14] Add test case for maximal break --- .../TestSceneDrainingHealthProcessor.cs | 75 +++++++++---------- 1 file changed, 37 insertions(+), 38 deletions(-) diff --git a/osu.Game.Tests/Gameplay/TestSceneDrainingHealthProcessor.cs b/osu.Game.Tests/Gameplay/TestSceneDrainingHealthProcessor.cs index 2f83ea4832..e50b2231bf 100644 --- a/osu.Game.Tests/Gameplay/TestSceneDrainingHealthProcessor.cs +++ b/osu.Game.Tests/Gameplay/TestSceneDrainingHealthProcessor.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System.Collections.Generic; -using System.Linq; using NUnit.Framework; using osu.Framework.Graphics; using osu.Framework.Utils; @@ -43,52 +41,61 @@ namespace osu.Game.Tests.Gameplay } [Test] - public void TestHealthNotDrainedBeforeBreak() + public void TestHealthDrainBetweenBreakAndObjects() { - createProcessor(createBeatmap(0, 2000, - new BreakPeriod(400, 600), new BreakPeriod(1200, 1400))); + createProcessor(createBeatmap(0, 2000, new BreakPeriod(325, 375))); - setTime(300); + // 275 300 325 350 375 400 425 + // hitobjects o o + // break [-------------] + // no drain [---------------------------] + + setTime(285); setHealth(1); - setTime(400); - assertHealthEqualTo(1); + setTime(295); + assertHealthNotEqualTo(1); - setTime(1100); + setTime(305); setHealth(1); - setTime(1200); + setTime(315); assertHealthEqualTo(1); + + setTime(365); + assertHealthEqualTo(1); + + setTime(395); + assertHealthEqualTo(1); + + setTime(425); + assertHealthNotEqualTo(1); } [Test] - public void TestHealthNotDrainedDuringBreak() + public void TestHealthDrainDuringMaximalBreak() { - createProcessor(createBeatmap(0, 2000, new BreakPeriod(0, 1200))); + createProcessor(createBeatmap(0, 2000, new BreakPeriod(300, 400))); - setTime(700); - assertHealthEqualTo(1); - setTime(900); - assertHealthEqualTo(1); - } + // 275 300 325 350 375 400 425 + // hitobjects o o + // break [---------------------------] + // no drain [---------------------------] - [Test] - public void TestHealthNotDrainedAfterBreak() - { - createProcessor(createBeatmap(0, 2000, - new BreakPeriod(400, 600), new BreakPeriod(1200, 1400))); - - setTime(600); + setTime(285); setHealth(1); - setTime(700); - assertHealthEqualTo(1); + setTime(295); + assertHealthNotEqualTo(1); - setTime(1400); + setTime(305); setHealth(1); - setTime(1500); + setTime(395); assertHealthEqualTo(1); + + setTime(425); + assertHealthNotEqualTo(1); } [Test] @@ -154,24 +161,16 @@ namespace osu.Game.Tests.Gameplay { var beatmap = new Beatmap { - BeatmapInfo = { BaseDifficulty = { DrainRate = 5 } }, + BeatmapInfo = { BaseDifficulty = { DrainRate = 10 } }, }; - double time = startTime; - - while (time <= endTime) + for (double time = startTime; time <= endTime; time += 100) { beatmap.HitObjects.Add(new JudgeableHitObject { StartTime = time }); - - // leave a 100ms gap between the start and end of a break period. - time += (getCurrentBreak(breaks, time)?.Duration ?? 0) + 100; } beatmap.Breaks.AddRange(breaks); - static BreakPeriod getCurrentBreak(IEnumerable breaks, double time) => - breaks?.FirstOrDefault(b => time >= b.StartTime && time <= b.EndTime); - return beatmap; } From 848a3fb6d74ec3b443029cc048934c1df4ea728f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 11 May 2020 19:06:36 +0200 Subject: [PATCH 06/14] Take hitobject start/end times into account in drain --- osu.Game/Rulesets/Scoring/DrainingHealthProcessor.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Rulesets/Scoring/DrainingHealthProcessor.cs b/osu.Game/Rulesets/Scoring/DrainingHealthProcessor.cs index 1958efdd6f..982f527517 100644 --- a/osu.Game/Rulesets/Scoring/DrainingHealthProcessor.cs +++ b/osu.Game/Rulesets/Scoring/DrainingHealthProcessor.cs @@ -84,12 +84,12 @@ namespace osu.Game.Rulesets.Scoring noDrainPeriodTracker = new PeriodTracker(beatmap.Breaks.Select(breakPeriod => new Period( beatmap.HitObjects .Select(hitObject => hitObject.GetEndTime()) - .Where(endTime => endTime < breakPeriod.StartTime) + .Where(endTime => endTime <= breakPeriod.StartTime) .DefaultIfEmpty(double.MinValue) .Last(), beatmap.HitObjects .Select(hitObject => hitObject.StartTime) - .Where(startTime => startTime > breakPeriod.EndTime) + .Where(startTime => startTime >= breakPeriod.EndTime) .DefaultIfEmpty(double.MaxValue) .First() ))); From 554be1c4222eec67b7926c2a4a802b6130aeae35 Mon Sep 17 00:00:00 2001 From: Olle Kelderman Date: Fri, 22 May 2020 19:25:05 +0200 Subject: [PATCH 07/14] add the ability to set the size of the Tournament Client to an arbitrary value instead of a fixed 1080p option --- osu.Game.Tournament/Screens/SetupScreen.cs | 79 ++++++++++++++++++---- 1 file changed, 67 insertions(+), 12 deletions(-) diff --git a/osu.Game.Tournament/Screens/SetupScreen.cs b/osu.Game.Tournament/Screens/SetupScreen.cs index c91379b2d6..f9ec29d0c6 100644 --- a/osu.Game.Tournament/Screens/SetupScreen.cs +++ b/osu.Game.Tournament/Screens/SetupScreen.cs @@ -25,7 +25,7 @@ namespace osu.Game.Tournament.Screens private FillFlowContainer fillFlow; private LoginOverlay loginOverlay; - private ActionableInfo resolution; + private ActionableInfoWithNumberBox resolution; [Resolved] private MatchIPCInfo ipc { get; set; } @@ -108,18 +108,22 @@ namespace osu.Game.Tournament.Screens Items = rulesets.AvailableRulesets, Current = LadderInfo.Ruleset, }, - resolution = new ActionableInfo + resolution = new ActionableInfoWithNumberBox { Label = "Stream area resolution", - ButtonText = "Set to 1080p", - Action = () => + ButtonText = "Set size", + Action = i => { - windowSize.Value = new Size((int)(1920 / TournamentSceneManager.STREAM_AREA_WIDTH * TournamentSceneManager.REQUIRED_WIDTH), 1080); + i = Math.Clamp(i, 480, 2160); + windowSize.Value = new Size((int)(i * aspect_ratio / TournamentSceneManager.STREAM_AREA_WIDTH * TournamentSceneManager.REQUIRED_WIDTH), i); + resolution.NumberValue = i; } }, }; } + private const float aspect_ratio = 16f / 9f; + protected override void Update() { base.Update(); @@ -149,7 +153,7 @@ namespace osu.Game.Tournament.Screens private class ActionableInfo : LabelledDrawable { - private OsuButton button; + protected OsuButton Button; public ActionableInfo() : base(true) @@ -158,22 +162,22 @@ namespace osu.Game.Tournament.Screens public string ButtonText { - set => button.Text = value; + set => Button.Text = value; } public string Value { - set => valueText.Text = value; + set => ValueText.Text = value; } public bool Failing { - set => valueText.Colour = value ? Color4.Red : Color4.White; + set => ValueText.Colour = value ? Color4.Red : Color4.White; } public Action Action; - private TournamentSpriteText valueText; + protected TournamentSpriteText ValueText; protected override Drawable CreateComponent() => new Container { @@ -181,12 +185,12 @@ namespace osu.Game.Tournament.Screens RelativeSizeAxes = Axes.X, Children = new Drawable[] { - valueText = new TournamentSpriteText + ValueText = new TournamentSpriteText { Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, }, - button = new TriangleButton + Button = new TriangleButton { Anchor = Anchor.CentreRight, Origin = Anchor.CentreRight, @@ -196,5 +200,56 @@ namespace osu.Game.Tournament.Screens } }; } + + private class ActionableInfoWithNumberBox : ActionableInfo + { + public new Action Action; + + private OsuNumberBox numberBox; + + public int NumberValue + { + get + { + int.TryParse(numberBox.Text, out var val); + return val; + } + set => numberBox.Text = value.ToString(); + } + + protected override Drawable CreateComponent() => new Container + { + AutoSizeAxes = Axes.Y, + RelativeSizeAxes = Axes.X, + Children = new Drawable[] + { + ValueText = new TournamentSpriteText + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + }, + numberBox = new OsuNumberBox + { + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + Width = 100, + Margin = new MarginPadding + { + Right = 110 + } + }, + Button = new TriangleButton + { + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + Size = new Vector2(100, 30), + Action = () => + { + if (numberBox.Text.Length > 0) Action?.Invoke(NumberValue); + } + }, + } + }; + } } } From 1062e07ec12f017da02a903f0ad1189468e8fe53 Mon Sep 17 00:00:00 2001 From: Olle Kelderman Date: Sun, 24 May 2020 22:24:46 +0200 Subject: [PATCH 08/14] refactor and implemented feedback: - button text change - renamed ActionableInfoWithNumberBox to ResolutionSelector and moved the clamping logic inside it - also removed the ugly right margin and added the FillFlowContainer --- osu.Game.Tournament/Screens/SetupScreen.cs | 99 +++++++++++----------- 1 file changed, 51 insertions(+), 48 deletions(-) diff --git a/osu.Game.Tournament/Screens/SetupScreen.cs b/osu.Game.Tournament/Screens/SetupScreen.cs index f9ec29d0c6..33eefbe553 100644 --- a/osu.Game.Tournament/Screens/SetupScreen.cs +++ b/osu.Game.Tournament/Screens/SetupScreen.cs @@ -25,7 +25,7 @@ namespace osu.Game.Tournament.Screens private FillFlowContainer fillFlow; private LoginOverlay loginOverlay; - private ActionableInfoWithNumberBox resolution; + private ResolutionSelector resolution; [Resolved] private MatchIPCInfo ipc { get; set; } @@ -108,15 +108,13 @@ namespace osu.Game.Tournament.Screens Items = rulesets.AvailableRulesets, Current = LadderInfo.Ruleset, }, - resolution = new ActionableInfoWithNumberBox + resolution = new ResolutionSelector { Label = "Stream area resolution", - ButtonText = "Set size", + ButtonText = "Set height", Action = i => { - i = Math.Clamp(i, 480, 2160); windowSize.Value = new Size((int)(i * aspect_ratio / TournamentSceneManager.STREAM_AREA_WIDTH * TournamentSceneManager.REQUIRED_WIDTH), i); - resolution.NumberValue = i; } }, }; @@ -167,17 +165,18 @@ namespace osu.Game.Tournament.Screens public string Value { - set => ValueText.Text = value; + set => valueText.Text = value; } public bool Failing { - set => ValueText.Colour = value ? Color4.Red : Color4.White; + set => valueText.Colour = value ? Color4.Red : Color4.White; } public Action Action; - protected TournamentSpriteText ValueText; + private TournamentSpriteText valueText; + protected FillFlowContainer FlowContainer; protected override Drawable CreateComponent() => new Container { @@ -185,71 +184,75 @@ namespace osu.Game.Tournament.Screens RelativeSizeAxes = Axes.X, Children = new Drawable[] { - ValueText = new TournamentSpriteText + valueText = new TournamentSpriteText { Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, }, - Button = new TriangleButton + FlowContainer = new FillFlowContainer { Anchor = Anchor.CentreRight, Origin = Anchor.CentreRight, - Size = new Vector2(100, 30), - Action = () => Action?.Invoke() - }, + AutoSizeAxes = Axes.Both, + Spacing = new Vector2(10, 0), + Children = new Drawable[] + { + Button = new TriangleButton + { + Size = new Vector2(100, 30), + Action = () => Action?.Invoke() + } + } + } } }; } - private class ActionableInfoWithNumberBox : ActionableInfo + private class ResolutionSelector : ActionableInfo { + private const int height_min_allowed_value = 480; + private const int height_max_allowed_value = 2160; // 4k public new Action Action; private OsuNumberBox numberBox; - public int NumberValue + protected override Drawable CreateComponent() { - get + var drawable = base.CreateComponent(); + FlowContainer.Insert(0, numberBox = new OsuNumberBox { - int.TryParse(numberBox.Text, out var val); - return val; - } - set => numberBox.Text = value.ToString(); - } + Width = 100 + }); + FlowContainer.SetLayoutPosition(Button, 1); - protected override Drawable CreateComponent() => new Container - { - AutoSizeAxes = Axes.Y, - RelativeSizeAxes = Axes.X, - Children = new Drawable[] + base.Action = () => { - ValueText = new TournamentSpriteText + if (numberBox.Text.Length > 0) { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - }, - numberBox = new OsuNumberBox - { - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreRight, - Width = 100, - Margin = new MarginPadding + // box contains text + if (!int.TryParse(numberBox.Text, out var number)) { - Right = 110 + // at this point, the only reason we can arrive here is if the input number was too big to parse into an int + // so clamp to max allowed value + number = height_max_allowed_value; } - }, - Button = new TriangleButton - { - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreRight, - Size = new Vector2(100, 30), - Action = () => + else { - if (numberBox.Text.Length > 0) Action?.Invoke(NumberValue); + number = Math.Clamp(number, height_min_allowed_value, height_max_allowed_value); } - }, - } - }; + + // in case number got clamped, reset number in numberBox + numberBox.Text = number.ToString(); + + Action?.Invoke(number); + } + else + { + // TODO: input box was empty, give user feedback? do nothing? + } + }; + return drawable; + } } } } From a174117880874df70d5cd07d210db4117a1d7cee Mon Sep 17 00:00:00 2001 From: Olle Kelderman Date: Mon, 25 May 2020 00:55:10 +0200 Subject: [PATCH 09/14] fix flowcontainer order properly and removed todo as its decided to do nothing there for now --- osu.Game.Tournament/Screens/SetupScreen.cs | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/osu.Game.Tournament/Screens/SetupScreen.cs b/osu.Game.Tournament/Screens/SetupScreen.cs index 33eefbe553..bf328987fe 100644 --- a/osu.Game.Tournament/Screens/SetupScreen.cs +++ b/osu.Game.Tournament/Screens/SetupScreen.cs @@ -151,7 +151,7 @@ namespace osu.Game.Tournament.Screens private class ActionableInfo : LabelledDrawable { - protected OsuButton Button; + private OsuButton button; public ActionableInfo() : base(true) @@ -160,7 +160,7 @@ namespace osu.Game.Tournament.Screens public string ButtonText { - set => Button.Text = value; + set => button.Text = value; } public string Value @@ -197,7 +197,7 @@ namespace osu.Game.Tournament.Screens Spacing = new Vector2(10, 0), Children = new Drawable[] { - Button = new TriangleButton + button = new TriangleButton { Size = new Vector2(100, 30), Action = () => Action?.Invoke() @@ -219,11 +219,10 @@ namespace osu.Game.Tournament.Screens protected override Drawable CreateComponent() { var drawable = base.CreateComponent(); - FlowContainer.Insert(0, numberBox = new OsuNumberBox + FlowContainer.Insert(-1, numberBox = new OsuNumberBox { Width = 100 }); - FlowContainer.SetLayoutPosition(Button, 1); base.Action = () => { @@ -246,10 +245,6 @@ namespace osu.Game.Tournament.Screens Action?.Invoke(number); } - else - { - // TODO: input box was empty, give user feedback? do nothing? - } }; return drawable; } From 719da489221850d009c7a87389e3c25edf9a9bf1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 25 May 2020 20:11:00 +0200 Subject: [PATCH 10/14] Rename delegate argument --- osu.Game.Tournament/Screens/SetupScreen.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tournament/Screens/SetupScreen.cs b/osu.Game.Tournament/Screens/SetupScreen.cs index bf328987fe..0ecab449ec 100644 --- a/osu.Game.Tournament/Screens/SetupScreen.cs +++ b/osu.Game.Tournament/Screens/SetupScreen.cs @@ -112,9 +112,9 @@ namespace osu.Game.Tournament.Screens { Label = "Stream area resolution", ButtonText = "Set height", - Action = i => + Action = height => { - windowSize.Value = new Size((int)(i * aspect_ratio / TournamentSceneManager.STREAM_AREA_WIDTH * TournamentSceneManager.REQUIRED_WIDTH), i); + windowSize.Value = new Size((int)(height * aspect_ratio / TournamentSceneManager.STREAM_AREA_WIDTH * TournamentSceneManager.REQUIRED_WIDTH), height); } }, }; From ca68d94cf7aa7acec4d638f61934836bd3c2b3c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 25 May 2020 20:18:17 +0200 Subject: [PATCH 11/14] Invert if to reduce nesting --- osu.Game.Tournament/Screens/SetupScreen.cs | 34 +++++++++++----------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/osu.Game.Tournament/Screens/SetupScreen.cs b/osu.Game.Tournament/Screens/SetupScreen.cs index 0ecab449ec..f8895f4703 100644 --- a/osu.Game.Tournament/Screens/SetupScreen.cs +++ b/osu.Game.Tournament/Screens/SetupScreen.cs @@ -226,25 +226,25 @@ namespace osu.Game.Tournament.Screens base.Action = () => { - if (numberBox.Text.Length > 0) + if (string.IsNullOrEmpty(numberBox.Text)) + return; + + // box contains text + if (!int.TryParse(numberBox.Text, out var number)) { - // box contains text - if (!int.TryParse(numberBox.Text, out var number)) - { - // at this point, the only reason we can arrive here is if the input number was too big to parse into an int - // so clamp to max allowed value - number = height_max_allowed_value; - } - else - { - number = Math.Clamp(number, height_min_allowed_value, height_max_allowed_value); - } - - // in case number got clamped, reset number in numberBox - numberBox.Text = number.ToString(); - - Action?.Invoke(number); + // at this point, the only reason we can arrive here is if the input number was too big to parse into an int + // so clamp to max allowed value + number = height_max_allowed_value; } + else + { + number = Math.Clamp(number, height_min_allowed_value, height_max_allowed_value); + } + + // in case number got clamped, reset number in numberBox + numberBox.Text = number.ToString(); + + Action?.Invoke(number); }; return drawable; } From 748f7fcd8b914ff7e84d0f29463142b18a6b244d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 25 May 2020 20:20:26 +0200 Subject: [PATCH 12/14] Rename constants --- osu.Game.Tournament/Screens/SetupScreen.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tournament/Screens/SetupScreen.cs b/osu.Game.Tournament/Screens/SetupScreen.cs index f8895f4703..e1594de69e 100644 --- a/osu.Game.Tournament/Screens/SetupScreen.cs +++ b/osu.Game.Tournament/Screens/SetupScreen.cs @@ -210,8 +210,8 @@ namespace osu.Game.Tournament.Screens private class ResolutionSelector : ActionableInfo { - private const int height_min_allowed_value = 480; - private const int height_max_allowed_value = 2160; // 4k + private const int minimum_window_height = 480; + private const int maximum_window_height = 2160; // 4k public new Action Action; private OsuNumberBox numberBox; @@ -234,11 +234,11 @@ namespace osu.Game.Tournament.Screens { // at this point, the only reason we can arrive here is if the input number was too big to parse into an int // so clamp to max allowed value - number = height_max_allowed_value; + number = maximum_window_height; } else { - number = Math.Clamp(number, height_min_allowed_value, height_max_allowed_value); + number = Math.Clamp(number, minimum_window_height, maximum_window_height); } // in case number got clamped, reset number in numberBox From 828180ad9b3e6006e70c811e107d340ae18b603e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 2 Jun 2020 19:29:22 +0900 Subject: [PATCH 13/14] Add default --- osu.Game.Tournament/Screens/SetupScreen.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tournament/Screens/SetupScreen.cs b/osu.Game.Tournament/Screens/SetupScreen.cs index e1594de69e..2bd0bcf2f2 100644 --- a/osu.Game.Tournament/Screens/SetupScreen.cs +++ b/osu.Game.Tournament/Screens/SetupScreen.cs @@ -211,7 +211,8 @@ namespace osu.Game.Tournament.Screens private class ResolutionSelector : ActionableInfo { private const int minimum_window_height = 480; - private const int maximum_window_height = 2160; // 4k + private const int maximum_window_height = 2160; + public new Action Action; private OsuNumberBox numberBox; @@ -221,6 +222,7 @@ namespace osu.Game.Tournament.Screens var drawable = base.CreateComponent(); FlowContainer.Insert(-1, numberBox = new OsuNumberBox { + Text = "1080", Width = 100 }); From 78fddc895738ec770447f025bdc8a487bdd5c988 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 2 Jun 2020 19:29:59 +0900 Subject: [PATCH 14/14] Make button match height --- osu.Game.Tournament/Screens/SetupScreen.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tournament/Screens/SetupScreen.cs b/osu.Game.Tournament/Screens/SetupScreen.cs index 2bd0bcf2f2..cf8eb8bd6c 100644 --- a/osu.Game.Tournament/Screens/SetupScreen.cs +++ b/osu.Game.Tournament/Screens/SetupScreen.cs @@ -199,7 +199,7 @@ namespace osu.Game.Tournament.Screens { button = new TriangleButton { - Size = new Vector2(100, 30), + Size = new Vector2(100, 40), Action = () => Action?.Invoke() } }