diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 9e9af23b27..814fc81f51 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -5,7 +5,7 @@ updates: schedule: interval: monthly time: "17:00" - open-pull-requests-limit: 99 + open-pull-requests-limit: 0 # disabled until https://github.com/dependabot/dependabot-core/issues/369 is resolved. ignore: - dependency-name: Microsoft.EntityFrameworkCore.Design versions: diff --git a/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform/Mods/EmptyFreeformModAutoplay.cs b/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform/Mods/EmptyFreeformModAutoplay.cs index f705009d18..d4496a24fd 100644 --- a/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform/Mods/EmptyFreeformModAutoplay.cs +++ b/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform/Mods/EmptyFreeformModAutoplay.cs @@ -3,10 +3,10 @@ using System.Collections.Generic; using osu.Game.Beatmaps; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Rulesets.EmptyFreeform.Replays; using osu.Game.Rulesets.Mods; using osu.Game.Scoring; -using osu.Game.Users; namespace osu.Game.Rulesets.EmptyFreeform.Mods { @@ -16,7 +16,7 @@ namespace osu.Game.Rulesets.EmptyFreeform.Mods { ScoreInfo = new ScoreInfo { - User = new User { Username = "sample" }, + User = new APIUser { Username = "sample" }, }, Replay = new EmptyFreeformAutoGenerator(beatmap).Generate(), }; diff --git a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/Mods/PippidonModAutoplay.cs b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/Mods/PippidonModAutoplay.cs index 4565c97d1a..6e1fe42ee2 100644 --- a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/Mods/PippidonModAutoplay.cs +++ b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/Mods/PippidonModAutoplay.cs @@ -3,10 +3,10 @@ using System.Collections.Generic; using osu.Game.Beatmaps; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Pippidon.Replays; using osu.Game.Scoring; -using osu.Game.Users; namespace osu.Game.Rulesets.Pippidon.Mods { @@ -16,7 +16,7 @@ namespace osu.Game.Rulesets.Pippidon.Mods { ScoreInfo = new ScoreInfo { - User = new User { Username = "sample" }, + User = new APIUser { Username = "sample" }, }, Replay = new PippidonAutoGenerator(beatmap).Generate(), }; diff --git a/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling/Mods/EmptyScrollingModAutoplay.cs b/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling/Mods/EmptyScrollingModAutoplay.cs index 431994e098..c5bacb522f 100644 --- a/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling/Mods/EmptyScrollingModAutoplay.cs +++ b/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling/Mods/EmptyScrollingModAutoplay.cs @@ -5,8 +5,8 @@ using osu.Game.Beatmaps; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.EmptyScrolling.Replays; using osu.Game.Scoring; -using osu.Game.Users; using System.Collections.Generic; +using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Rulesets.EmptyScrolling.Mods { @@ -16,7 +16,7 @@ namespace osu.Game.Rulesets.EmptyScrolling.Mods { ScoreInfo = new ScoreInfo { - User = new User { Username = "sample" }, + User = new APIUser { Username = "sample" }, }, Replay = new EmptyScrollingAutoGenerator(beatmap).Generate(), }; diff --git a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/Mods/PippidonModAutoplay.cs b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/Mods/PippidonModAutoplay.cs index 4565c97d1a..6e1fe42ee2 100644 --- a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/Mods/PippidonModAutoplay.cs +++ b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/Mods/PippidonModAutoplay.cs @@ -3,10 +3,10 @@ using System.Collections.Generic; using osu.Game.Beatmaps; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Pippidon.Replays; using osu.Game.Scoring; -using osu.Game.Users; namespace osu.Game.Rulesets.Pippidon.Mods { @@ -16,7 +16,7 @@ namespace osu.Game.Rulesets.Pippidon.Mods { ScoreInfo = new ScoreInfo { - User = new User { Username = "sample" }, + User = new APIUser { Username = "sample" }, }, Replay = new PippidonAutoGenerator(beatmap).Generate(), }; diff --git a/osu.Android.props b/osu.Android.props index 4f9f83f199..752eb160ed 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,7 +52,7 @@ - + diff --git a/osu.Desktop/DiscordRichPresence.cs b/osu.Desktop/DiscordRichPresence.cs index e2b40e9dc6..e1e7e6ad18 100644 --- a/osu.Desktop/DiscordRichPresence.cs +++ b/osu.Desktop/DiscordRichPresence.cs @@ -11,10 +11,10 @@ using osu.Framework.Graphics; using osu.Framework.Logging; using osu.Game.Configuration; using osu.Game.Online.API; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Rulesets; using osu.Game.Users; using LogLevel = osu.Framework.Logging.LogLevel; -using User = osu.Game.Users.User; namespace osu.Desktop { @@ -27,7 +27,7 @@ namespace osu.Desktop [Resolved] private IBindable ruleset { get; set; } - private IBindable user; + private IBindable user; private readonly IBindable status = new Bindable(); private readonly IBindable activity = new Bindable(); diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModAutoplay.cs b/osu.Game.Rulesets.Catch/Mods/CatchModAutoplay.cs index 6f3e6763bd..11fffb31de 100644 --- a/osu.Game.Rulesets.Catch/Mods/CatchModAutoplay.cs +++ b/osu.Game.Rulesets.Catch/Mods/CatchModAutoplay.cs @@ -3,10 +3,10 @@ using System.Collections.Generic; using osu.Game.Beatmaps; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Rulesets.Catch.Replays; using osu.Game.Rulesets.Mods; using osu.Game.Scoring; -using osu.Game.Users; namespace osu.Game.Rulesets.Catch.Mods { @@ -14,7 +14,7 @@ namespace osu.Game.Rulesets.Catch.Mods { public override Score CreateReplayScore(IBeatmap beatmap, IReadOnlyList mods) => new Score { - ScoreInfo = new ScoreInfo { User = new User { Username = "osu!salad" } }, + ScoreInfo = new ScoreInfo { User = new APIUser { Username = "osu!salad" } }, Replay = new CatchAutoGenerator(beatmap).Generate(), }; } diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModCinema.cs b/osu.Game.Rulesets.Catch/Mods/CatchModCinema.cs index 1b7d254321..6d2286b957 100644 --- a/osu.Game.Rulesets.Catch/Mods/CatchModCinema.cs +++ b/osu.Game.Rulesets.Catch/Mods/CatchModCinema.cs @@ -3,11 +3,11 @@ using System.Collections.Generic; using osu.Game.Beatmaps; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Rulesets.Catch.Objects; using osu.Game.Rulesets.Catch.Replays; using osu.Game.Rulesets.Mods; using osu.Game.Scoring; -using osu.Game.Users; namespace osu.Game.Rulesets.Catch.Mods { @@ -15,7 +15,7 @@ namespace osu.Game.Rulesets.Catch.Mods { public override Score CreateReplayScore(IBeatmap beatmap, IReadOnlyList mods) => new Score { - ScoreInfo = new ScoreInfo { User = new User { Username = "osu!salad" } }, + ScoreInfo = new ScoreInfo { User = new APIUser { Username = "osu!salad" } }, Replay = new CatchAutoGenerator(beatmap).Generate(), }; } diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModAutoplay.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModAutoplay.cs index 86f667466f..1504c868d0 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModAutoplay.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModAutoplay.cs @@ -3,11 +3,11 @@ using System.Collections.Generic; using osu.Game.Beatmaps; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Mania.Replays; using osu.Game.Rulesets.Mods; using osu.Game.Scoring; -using osu.Game.Users; namespace osu.Game.Rulesets.Mania.Mods { @@ -15,7 +15,7 @@ namespace osu.Game.Rulesets.Mania.Mods { public override Score CreateReplayScore(IBeatmap beatmap, IReadOnlyList mods) => new Score { - ScoreInfo = new ScoreInfo { User = new User { Username = "osu!topus" } }, + ScoreInfo = new ScoreInfo { User = new APIUser { Username = "osu!topus" } }, Replay = new ManiaAutoGenerator((ManiaBeatmap)beatmap).Generate(), }; } diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModCinema.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModCinema.cs index 1c06bb389b..4f1276946b 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModCinema.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModCinema.cs @@ -3,12 +3,12 @@ using System.Collections.Generic; using osu.Game.Beatmaps; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.Replays; using osu.Game.Rulesets.Mods; using osu.Game.Scoring; -using osu.Game.Users; namespace osu.Game.Rulesets.Mania.Mods { @@ -16,7 +16,7 @@ namespace osu.Game.Rulesets.Mania.Mods { public override Score CreateReplayScore(IBeatmap beatmap, IReadOnlyList mods) => new Score { - ScoreInfo = new ScoreInfo { User = new User { Username = "osu!topus" } }, + ScoreInfo = new ScoreInfo { User = new APIUser { Username = "osu!topus" } }, Replay = new ManiaAutoGenerator((ManiaBeatmap)beatmap).Generate(), }; } diff --git a/osu.Game.Rulesets.Osu.Tests/OsuDifficultyCalculatorTest.cs b/osu.Game.Rulesets.Osu.Tests/OsuDifficultyCalculatorTest.cs index 7cd06c5225..b0e173e752 100644 --- a/osu.Game.Rulesets.Osu.Tests/OsuDifficultyCalculatorTest.cs +++ b/osu.Game.Rulesets.Osu.Tests/OsuDifficultyCalculatorTest.cs @@ -15,13 +15,13 @@ namespace osu.Game.Rulesets.Osu.Tests { protected override string ResourceAssembly => "osu.Game.Rulesets.Osu"; - [TestCase(6.5295339534769958d, "diffcalc-test")] - [TestCase(1.1514260533755143d, "zero-length-sliders")] + [TestCase(6.6975550434910005d, "diffcalc-test")] + [TestCase(1.4670676815251105d, "zero-length-sliders")] public void Test(double expected, string name) => base.Test(expected, name); - [TestCase(9.047752485219954d, "diffcalc-test")] - [TestCase(1.3985711787077566d, "zero-length-sliders")] + [TestCase(8.9389769779826267d, "diffcalc-test")] + [TestCase(1.7786917985891204d, "zero-length-sliders")] public void TestClockRateAdjusted(double expected, string name) => Test(expected, name, new OsuModDoubleTime()); diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneMissHitWindowJudgements.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneMissHitWindowJudgements.cs index a5629119b6..840d871b7b 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneMissHitWindowJudgements.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneMissHitWindowJudgements.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using NUnit.Framework; using osu.Game.Beatmaps; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Replays; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Beatmaps; @@ -14,7 +15,6 @@ using osu.Game.Rulesets.Osu.Scoring; using osu.Game.Rulesets.Scoring; using osu.Game.Scoring; using osu.Game.Tests.Visual; -using osu.Game.Users; using osuTK; namespace osu.Game.Rulesets.Osu.Tests @@ -69,7 +69,7 @@ namespace osu.Game.Rulesets.Osu.Tests { public override Score CreateReplayScore(IBeatmap beatmap, IReadOnlyList mods) => new Score { - ScoreInfo = new ScoreInfo { User = new User { Username = "Autoplay" } }, + ScoreInfo = new ScoreInfo { User = new APIUser { Username = "Autoplay" } }, Replay = new MissingAutoGenerator(beatmap, mods).Generate() }; } diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs index 4bca87204a..a9d9ff6985 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -54,7 +54,9 @@ namespace osu.Game.Rulesets.Osu.Difficulty if (mods.Any(h => h is OsuModRelax)) { - effectiveMissCount += countOk + countMeh; + // As we're adding Oks and Mehs to an approximated number of combo breaks the result can be higher than total hits in specific scenarios (which breaks some calculations) so we need to clamp it. + effectiveMissCount = Math.Min(effectiveMissCount + countOk + countMeh, totalHits); + multiplier *= 0.6; } @@ -109,13 +111,11 @@ namespace osu.Game.Rulesets.Osu.Difficulty double approachRateFactor = 0.0; if (Attributes.ApproachRate > 10.33) - approachRateFactor = Attributes.ApproachRate - 10.33; + approachRateFactor = 0.3 * (Attributes.ApproachRate - 10.33); else if (Attributes.ApproachRate < 8.0) - approachRateFactor = 0.025 * (8.0 - Attributes.ApproachRate); + approachRateFactor = 0.1 * (8.0 - Attributes.ApproachRate); - double approachRateTotalHitsFactor = 1.0 / (1.0 + Math.Exp(-(0.007 * (totalHits - 400)))); - - double approachRateBonus = 1.0 + (0.03 + 0.37 * approachRateTotalHitsFactor) * approachRateFactor; + aimValue *= 1.0 + approachRateFactor * lengthBonus; // Buff for longer maps with high AR. if (mods.Any(m => m is OsuModBlinds)) aimValue *= 1.3 + (totalHits * (0.0016 / (1 + 2 * effectiveMissCount)) * Math.Pow(accuracy, 16)) * (1 - 0.003 * Attributes.DrainRate * Attributes.DrainRate); @@ -125,10 +125,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty aimValue *= 1.0 + 0.04 * (12.0 - Attributes.ApproachRate); } - aimValue *= approachRateBonus; - - // Scale the aim value with accuracy _slightly_. - aimValue *= 0.5 + accuracy / 2.0; + aimValue *= accuracy; // It is important to also consider accuracy difficulty when doing that. aimValue *= 0.98 + Math.Pow(Attributes.OverallDifficulty, 2) / 2500; @@ -154,11 +151,9 @@ namespace osu.Game.Rulesets.Osu.Difficulty double approachRateFactor = 0.0; if (Attributes.ApproachRate > 10.33) - approachRateFactor = Attributes.ApproachRate - 10.33; + approachRateFactor = 0.3 * (Attributes.ApproachRate - 10.33); - double approachRateTotalHitsFactor = 1.0 / (1.0 + Math.Exp(-(0.007 * (totalHits - 400)))); - - speedValue *= 1.0 + (0.03 + 0.37 * approachRateTotalHitsFactor) * approachRateFactor; + speedValue *= 1.0 + approachRateFactor * lengthBonus; // Buff for longer maps with high AR. if (mods.Any(m => m is OsuModBlinds)) { @@ -255,7 +250,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty private int calculateEffectiveMissCount() { - // guess the number of misses + slider breaks from combo + // Guess the number of misses + slider breaks from combo double comboBasedMissCount = 0.0; if (Attributes.SliderCount > 0) @@ -265,7 +260,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty comboBasedMissCount = fullComboThreshold / Math.Max(1.0, scoreMaxCombo); } - // we're clamping misscount because since its derived from combo it can be higher than total hits and that breaks some calculations + // Clamp misscount since it's derived from combo and can be higher than total hits and that breaks some calculations comboBasedMissCount = Math.Min(comboBasedMissCount, totalHits); return Math.Max(countMiss, (int)Math.Floor(comboBasedMissCount)); diff --git a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs index 4b90285fd4..cbaad93bed 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using System; -using System.Linq; using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Osu.Objects; @@ -14,6 +13,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing { private const int normalized_radius = 50; // Change radius to 50 to make 100 the diameter. Easier for mental maths. private const int min_delta_time = 25; + private const float maximum_slider_radius = normalized_radius * 2.4f; + private const float assumed_slider_radius = normalized_radius * 1.65f; protected new OsuHitObject BaseObject => (OsuHitObject)base.BaseObject; @@ -89,7 +90,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing if (lastObject is Slider lastSlider) { computeSliderCursorPosition(lastSlider); - TravelDistance = lastSlider.LazyTravelDistance * scalingFactor; + TravelDistance = lastSlider.LazyTravelDistance; TravelTime = Math.Max(lastSlider.LazyTravelTime / clockRate, min_delta_time); MovementTime = Math.Max(StrainTime - TravelTime, min_delta_time); @@ -99,7 +100,9 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing // For hitobjects which continue in the direction of the slider, the player will normally follow through the slider, // such that they're not jumping from the lazy position but rather from very close to (or the end of) the slider. // In such cases, a leniency is applied by also considering the jump distance from the tail of the slider, and taking the minimum jump distance. - MovementDistance = Math.Min(JumpDistance, tailJumpDistance); + // Additional distance is removed based on position of jump relative to slider follow circle radius. + // JumpDistance is the leniency distance beyond the assumed_slider_radius. tailJumpDistance is maximum_slider_radius since the full distance of radial leniency is still possible. + MovementDistance = Math.Max(0, Math.Min(JumpDistance - (maximum_slider_radius - assumed_slider_radius), tailJumpDistance - maximum_slider_radius)); } else { @@ -126,37 +129,60 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing if (slider.LazyEndPosition != null) return; - slider.LazyEndPosition = slider.StackedPosition; + slider.LazyTravelTime = slider.NestedHitObjects[^1].StartTime - slider.StartTime; - float followCircleRadius = (float)(slider.Radius * 2.4); - var computeVertex = new Action(t => + double endTimeMin = slider.LazyTravelTime / slider.SpanDuration; + if (endTimeMin % 2 >= 1) + endTimeMin = 1 - endTimeMin % 1; + else + endTimeMin %= 1; + + slider.LazyEndPosition = slider.StackedPosition + slider.Path.PositionAt(endTimeMin); // temporary lazy end position until a real result can be derived. + var currCursorPosition = slider.StackedPosition; + double scalingFactor = normalized_radius / slider.Radius; // lazySliderDistance is coded to be sensitive to scaling, this makes the maths easier with the thresholds being used. + + for (int i = 1; i < slider.NestedHitObjects.Count; i++) { - double progress = (t - slider.StartTime) / slider.SpanDuration; - if (progress % 2 >= 1) - progress = 1 - progress % 1; - else - progress %= 1; + var currMovementObj = (OsuHitObject)slider.NestedHitObjects[i]; - // ReSharper disable once PossibleInvalidOperationException (bugged in current r# version) - var diff = slider.StackedPosition + slider.Path.PositionAt(progress) - slider.LazyEndPosition.Value; - float dist = diff.Length; + Vector2 currMovement = Vector2.Subtract(currMovementObj.StackedPosition, currCursorPosition); + double currMovementLength = scalingFactor * currMovement.Length; - slider.LazyTravelTime = t - slider.StartTime; + // Amount of movement required so that the cursor position needs to be updated. + double requiredMovement = assumed_slider_radius; - if (dist > followCircleRadius) + if (i == slider.NestedHitObjects.Count - 1) { - // The cursor would be outside the follow circle, we need to move it - diff.Normalize(); // Obtain direction of diff - dist -= followCircleRadius; - slider.LazyEndPosition += diff * dist; - slider.LazyTravelDistance += dist; - } - }); + // The end of a slider has special aim rules due to the relaxed time constraint on position. + // There is both a lazy end position as well as the actual end slider position. We assume the player takes the simpler movement. + // For sliders that are circular, the lazy end position may actually be farther away than the sliders true end. + // This code is designed to prevent buffing situations where lazy end is actually a less efficient movement. + Vector2 lazyMovement = Vector2.Subtract((Vector2)slider.LazyEndPosition, currCursorPosition); - // Skip the head circle - var scoringTimes = slider.NestedHitObjects.Skip(1).Select(t => t.StartTime); - foreach (double time in scoringTimes) - computeVertex(time); + if (lazyMovement.Length < currMovement.Length) + currMovement = lazyMovement; + + currMovementLength = scalingFactor * currMovement.Length; + } + else if (currMovementObj is SliderRepeat) + { + // For a slider repeat, assume a tighter movement threshold to better assess repeat sliders. + requiredMovement = normalized_radius; + } + + if (currMovementLength > requiredMovement) + { + // this finds the positional delta from the required radius and the current position, and updates the currCursorPosition accordingly, as well as rewarding distance. + currCursorPosition = Vector2.Add(currCursorPosition, Vector2.Multiply(currMovement, (float)((currMovementLength - requiredMovement) / currMovementLength))); + currMovementLength *= (currMovementLength - requiredMovement) / currMovementLength; + slider.LazyTravelDistance += (float)currMovementLength; + } + + if (i == slider.NestedHitObjects.Count - 1) + slider.LazyEndPosition = currCursorPosition; + } + + slider.LazyTravelDistance *= (float)Math.Pow(1 + slider.RepeatCount / 2.5, 1.0 / 2.5); // Bonus for repeat sliders until a better per nested object strain system can be achieved. } private Vector2 getEndCursorPosition(OsuHitObject hitObject) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs index a054b46366..4c40a49396 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs @@ -23,8 +23,10 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills private const double wide_angle_multiplier = 1.5; private const double acute_angle_multiplier = 2.0; + private const double slider_multiplier = 1.5; + private const double velocity_change_multiplier = 0.75; - private double currentStrain = 1; + private double currentStrain; private double skillMultiplier => 23.25; private double strainDecayBase => 0.15; @@ -61,7 +63,11 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills prevVelocity = Math.Max(prevVelocity, movementVelocity + travelVelocity); } - double angleBonus = 0; + double wideAngleBonus = 0; + double acuteAngleBonus = 0; + double sliderBonus = 0; + double velocityChangeBonus = 0; + double aimStrain = currVelocity; // Start strain with regular velocity. if (Math.Max(osuCurrObj.StrainTime, osuLastObj.StrainTime) < 1.25 * Math.Min(osuCurrObj.StrainTime, osuLastObj.StrainTime)) // If rhythms are the same. @@ -73,10 +79,10 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills double lastLastAngle = osuLastLastObj.Angle.Value; // Rewarding angles, take the smaller velocity as base. - angleBonus = Math.Min(currVelocity, prevVelocity); + double angleBonus = Math.Min(currVelocity, prevVelocity); - double wideAngleBonus = calcWideAngleBonus(currAngle); - double acuteAngleBonus = calcAcuteAngleBonus(currAngle); + wideAngleBonus = calcWideAngleBonus(currAngle); + acuteAngleBonus = calcAcuteAngleBonus(currAngle); if (osuCurrObj.StrainTime > 100) // Only buff deltaTime exceeding 300 bpm 1/2. acuteAngleBonus = 0; @@ -88,14 +94,48 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills * Math.Pow(Math.Sin(Math.PI / 2 * (Math.Clamp(osuCurrObj.JumpDistance, 50, 100) - 50) / 50), 2); // Buff distance exceeding 50 (radius) up to 100 (diameter). } - wideAngleBonus *= angleBonus * (1 - Math.Min(wideAngleBonus, Math.Pow(calcWideAngleBonus(lastAngle), 3))); // Penalize wide angles if they're repeated, reducing the penalty as the lastAngle gets more acute. - acuteAngleBonus *= 0.5 + 0.5 * (1 - Math.Min(acuteAngleBonus, Math.Pow(calcAcuteAngleBonus(lastLastAngle), 3))); // Penalize acute angles if they're repeated, reducing the penalty as the lastLastAngle gets more obtuse. - - angleBonus = acuteAngleBonus * acute_angle_multiplier + wideAngleBonus * wide_angle_multiplier; // add the angle buffs together. + // Penalize wide angles if they're repeated, reducing the penalty as the lastAngle gets more acute. + wideAngleBonus *= angleBonus * (1 - Math.Min(wideAngleBonus, Math.Pow(calcWideAngleBonus(lastAngle), 3))); + // Penalize acute angles if they're repeated, reducing the penalty as the lastLastAngle gets more obtuse. + acuteAngleBonus *= 0.5 + 0.5 * (1 - Math.Min(acuteAngleBonus, Math.Pow(calcAcuteAngleBonus(lastLastAngle), 3))); } } - aimStrain += angleBonus; // Add in angle bonus. + if (Math.Max(prevVelocity, currVelocity) != 0) + { + // We want to use the average velocity over the whole object when awarding differences, not the individual jump and slider path velocities. + prevVelocity = (osuLastObj.JumpDistance + osuLastObj.TravelDistance) / osuLastObj.StrainTime; + currVelocity = (osuCurrObj.JumpDistance + osuCurrObj.TravelDistance) / osuCurrObj.StrainTime; + + // Scale with ratio of difference compared to 0.5 * max dist. + double distRatio = Math.Pow(Math.Sin(Math.PI / 2 * Math.Abs(prevVelocity - currVelocity) / Math.Max(prevVelocity, currVelocity)), 2); + + // Reward for % distance up to 125 / strainTime for overlaps where velocity is still changing. + double overlapVelocityBuff = Math.Min(125 / Math.Min(osuCurrObj.StrainTime, osuLastObj.StrainTime), Math.Abs(prevVelocity - currVelocity)); + + // Reward for % distance slowed down compared to previous, paying attention to not award overlap + double nonOverlapVelocityBuff = Math.Abs(prevVelocity - currVelocity) + // do not award overlap + * Math.Pow(Math.Sin(Math.PI / 2 * Math.Min(1, Math.Min(osuCurrObj.JumpDistance, osuLastObj.JumpDistance) / 100)), 2); + + // Choose the largest bonus, multiplied by ratio. + velocityChangeBonus = Math.Max(overlapVelocityBuff, nonOverlapVelocityBuff) * distRatio; + + // Penalize for rhythm changes. + velocityChangeBonus *= Math.Pow(Math.Min(osuCurrObj.StrainTime, osuLastObj.StrainTime) / Math.Max(osuCurrObj.StrainTime, osuLastObj.StrainTime), 2); + } + + if (osuCurrObj.TravelTime != 0) + { + // Reward sliders based on velocity. + sliderBonus = osuCurrObj.TravelDistance / osuCurrObj.TravelTime; + } + + // Add in acute angle bonus or wide angle bonus + velocity change bonus, whichever is larger. + aimStrain += Math.Max(acuteAngleBonus * acute_angle_multiplier, wideAngleBonus * wide_angle_multiplier + velocityChangeBonus * velocity_change_multiplier); + + // Add in additional slider velocity bonus. + aimStrain += sliderBonus * slider_multiplier; return aimStrain; } diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs index e3abe7d700..466f0556ab 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs @@ -23,7 +23,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills private double strainDecayBase => 0.15; protected override double DecayWeight => 1.0; protected override int HistoryLength => 10; // Look back for 10 notes is added for the sake of flashlight calculations. - private double currentStrain = 1; + + private double currentStrain; private double strainValueOf(DifficultyHitObject current) { diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs index cae6b8e01c..24881d9c47 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs @@ -24,8 +24,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills private double skillMultiplier => 1375; private double strainDecayBase => 0.3; - private double currentStrain = 1; - private double currentRhythm = 1; + private double currentStrain; + private double currentRhythm; protected override int ReducedSectionCount => 5; protected override double DifficultyMultiplier => 1.04; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModAutoplay.cs b/osu.Game.Rulesets.Osu/Mods/OsuModAutoplay.cs index 652da7123e..106edfb623 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModAutoplay.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModAutoplay.cs @@ -5,10 +5,10 @@ using System; using System.Collections.Generic; using System.Linq; using osu.Game.Beatmaps; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Replays; using osu.Game.Scoring; -using osu.Game.Users; namespace osu.Game.Rulesets.Osu.Mods { @@ -18,7 +18,7 @@ namespace osu.Game.Rulesets.Osu.Mods public override Score CreateReplayScore(IBeatmap beatmap, IReadOnlyList mods) => new Score { - ScoreInfo = new ScoreInfo { User = new User { Username = "Autoplay" } }, + ScoreInfo = new ScoreInfo { User = new APIUser { Username = "Autoplay" } }, Replay = new OsuAutoGenerator(beatmap, mods).Generate() }; } diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModCinema.cs b/osu.Game.Rulesets.Osu/Mods/OsuModCinema.cs index df06988b70..f478790134 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModCinema.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModCinema.cs @@ -5,11 +5,11 @@ using System; using System.Collections.Generic; using System.Linq; using osu.Game.Beatmaps; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Replays; using osu.Game.Scoring; -using osu.Game.Users; namespace osu.Game.Rulesets.Osu.Mods { @@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Osu.Mods public override Score CreateReplayScore(IBeatmap beatmap, IReadOnlyList mods) => new Score { - ScoreInfo = new ScoreInfo { User = new User { Username = "Autoplay" } }, + ScoreInfo = new ScoreInfo { User = new APIUser { Username = "Autoplay" } }, Replay = new OsuAutoGenerator(beatmap, mods).Generate() }; } diff --git a/osu.Game.Rulesets.Taiko.Tests/Editor/TestSceneEditorSaving.cs b/osu.Game.Rulesets.Taiko.Tests/Editor/TestSceneEditorSaving.cs new file mode 100644 index 0000000000..159a64d1ac --- /dev/null +++ b/osu.Game.Rulesets.Taiko.Tests/Editor/TestSceneEditorSaving.cs @@ -0,0 +1,91 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Linq; +using NUnit.Framework; +using osu.Framework.Input; +using osu.Framework.Testing; +using osu.Framework.Utils; +using osu.Game.Beatmaps; +using osu.Game.Rulesets.Edit; +using osu.Game.Rulesets.Taiko.Beatmaps; +using osu.Game.Screens.Edit; +using osu.Game.Screens.Edit.Setup; +using osu.Game.Screens.Menu; +using osu.Game.Screens.Select; +using osu.Game.Tests.Visual; +using osuTK.Input; + +namespace osu.Game.Rulesets.Taiko.Tests.Editor +{ + public class TestSceneEditorSaving : OsuGameTestScene + { + private Screens.Edit.Editor editor => Game.ChildrenOfType().FirstOrDefault(); + + private EditorBeatmap editorBeatmap => (EditorBeatmap)editor.Dependencies.Get(typeof(EditorBeatmap)); + + /// + /// Tests the general expected flow of creating a new beatmap, saving it, then loading it back from song select. + /// Emphasis is placed on , since taiko has special handling for it to keep compatibility with stable. + /// + [Test] + public void TestNewBeatmapSaveThenLoad() + { + AddStep("set default beatmap", () => Game.Beatmap.SetDefault()); + AddStep("set taiko ruleset", () => Ruleset.Value = new TaikoRuleset().RulesetInfo); + + PushAndConfirm(() => new EditorLoader()); + + AddUntilStep("wait for editor load", () => editor?.IsLoaded == true); + + AddUntilStep("wait for metadata screen load", () => editor.ChildrenOfType().FirstOrDefault()?.IsLoaded == true); + + // We intentionally switch away from the metadata screen, else there is a feedback loop with the textbox handling which causes metadata changes below to get overwritten. + + AddStep("Enter compose mode", () => InputManager.Key(Key.F1)); + AddUntilStep("Wait for compose mode load", () => editor.ChildrenOfType().FirstOrDefault()?.IsLoaded == true); + + AddStep("Set slider multiplier", () => editorBeatmap.Difficulty.SliderMultiplier = 2); + AddStep("Set artist and title", () => + { + editorBeatmap.BeatmapInfo.Metadata.Artist = "artist"; + editorBeatmap.BeatmapInfo.Metadata.Title = "title"; + }); + AddStep("Set difficulty name", () => editorBeatmap.BeatmapInfo.Version = "difficulty"); + + checkMutations(); + + AddStep("Save", () => InputManager.Keys(PlatformAction.Save)); + + checkMutations(); + + AddStep("Exit", () => InputManager.Key(Key.Escape)); + + AddUntilStep("Wait for main menu", () => Game.ScreenStack.CurrentScreen is MainMenu); + + PushAndConfirm(() => new PlaySongSelect()); + + AddUntilStep("Wait for beatmap selected", () => !Game.Beatmap.IsDefault); + AddStep("Open options", () => InputManager.Key(Key.F3)); + AddStep("Enter editor", () => InputManager.Key(Key.Number5)); + + AddUntilStep("Wait for editor load", () => editor != null); + + checkMutations(); + } + + private void checkMutations() + { + AddAssert("Beatmap has correct slider multiplier", () => + { + // we can only assert value correctness on TaikoMultiplierAppliedDifficulty, because that is the final difficulty converted taiko beatmaps use. + // therefore, ensure that we have that difficulty type by calling .CopyFrom(), which is a no-op if the type is already correct. + var taikoDifficulty = new TaikoBeatmapConverter.TaikoMultiplierAppliedDifficulty(); + taikoDifficulty.CopyFrom(editorBeatmap.Difficulty); + return Precision.AlmostEquals(taikoDifficulty.SliderMultiplier, 2); + }); + AddAssert("Beatmap has correct metadata", () => editorBeatmap.BeatmapInfo.Metadata.Artist == "artist" && editorBeatmap.BeatmapInfo.Metadata.Title == "title"); + AddAssert("Beatmap has correct difficulty name", () => editorBeatmap.BeatmapInfo.Version == "difficulty"); + } + } +} diff --git a/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs b/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs index 94dfb67d93..9b2e9fedc5 100644 --- a/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs +++ b/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs @@ -191,7 +191,7 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps protected override Beatmap CreateBeatmap() => new TaikoBeatmap(); - private class TaikoMultiplierAppliedDifficulty : BeatmapDifficulty + internal class TaikoMultiplierAppliedDifficulty : BeatmapDifficulty { public TaikoMultiplierAppliedDifficulty(IBeatmapDifficultyInfo difficulty) { @@ -209,7 +209,7 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps { base.CopyTo(other); if (!(other is TaikoMultiplierAppliedDifficulty)) - SliderMultiplier /= LegacyBeatmapEncoder.LEGACY_TAIKO_VELOCITY_MULTIPLIER; + other.SliderMultiplier /= LegacyBeatmapEncoder.LEGACY_TAIKO_VELOCITY_MULTIPLIER; } public override void CopyFrom(IBeatmapDifficultyInfo other) diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModAutoplay.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModAutoplay.cs index 31d9abf8b2..5832ae3dc1 100644 --- a/osu.Game.Rulesets.Taiko/Mods/TaikoModAutoplay.cs +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModAutoplay.cs @@ -3,10 +3,10 @@ using System.Collections.Generic; using osu.Game.Beatmaps; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Taiko.Replays; using osu.Game.Scoring; -using osu.Game.Users; namespace osu.Game.Rulesets.Taiko.Mods { @@ -14,7 +14,7 @@ namespace osu.Game.Rulesets.Taiko.Mods { public override Score CreateReplayScore(IBeatmap beatmap, IReadOnlyList mods) => new Score { - ScoreInfo = new ScoreInfo { User = new User { Username = "mekkadosu!" } }, + ScoreInfo = new ScoreInfo { User = new APIUser { Username = "mekkadosu!" } }, Replay = new TaikoAutoGenerator(beatmap).Generate(), }; } diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModCinema.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModCinema.cs index 00f0c8e321..f76e04a069 100644 --- a/osu.Game.Rulesets.Taiko/Mods/TaikoModCinema.cs +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModCinema.cs @@ -3,11 +3,11 @@ using System.Collections.Generic; using osu.Game.Beatmaps; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Taiko.Objects; using osu.Game.Rulesets.Taiko.Replays; using osu.Game.Scoring; -using osu.Game.Users; namespace osu.Game.Rulesets.Taiko.Mods { @@ -15,7 +15,7 @@ namespace osu.Game.Rulesets.Taiko.Mods { public override Score CreateReplayScore(IBeatmap beatmap, IReadOnlyList mods) => new Score { - ScoreInfo = new ScoreInfo { User = new User { Username = "mekkadosu!" } }, + ScoreInfo = new ScoreInfo { User = new APIUser { Username = "mekkadosu!" } }, Replay = new TaikoAutoGenerator(beatmap).Generate(), }; } diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs index 7a95856c36..0bd7c19200 100644 --- a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs @@ -112,7 +112,7 @@ namespace osu.Game.Tests.Beatmaps.Formats Assert.AreEqual("Renatus", metadata.TitleUnicode); Assert.AreEqual("Soleily", metadata.Artist); Assert.AreEqual("Soleily", metadata.ArtistUnicode); - Assert.AreEqual("Gamu", metadata.AuthorString); + Assert.AreEqual("Gamu", metadata.Author.Username); Assert.AreEqual("Insane", beatmapInfo.Version); Assert.AreEqual(string.Empty, metadata.Source); Assert.AreEqual("MBC7 Unisphere 地球ヤバイEP Chikyu Yabai", metadata.Tags); @@ -547,7 +547,7 @@ namespace osu.Game.Tests.Beatmaps.Formats Assert.DoesNotThrow(() => beatmap = decoder.Decode(stream)); Assert.IsNotNull(beatmap); Assert.AreEqual("Beatmap with corrupted header", beatmap.Metadata.Title); - Assert.AreEqual("Evil Hacker", beatmap.Metadata.AuthorString); + Assert.AreEqual("Evil Hacker", beatmap.Metadata.Author.Username); } } @@ -565,7 +565,7 @@ namespace osu.Game.Tests.Beatmaps.Formats Assert.DoesNotThrow(() => beatmap = decoder.Decode(stream)); Assert.IsNotNull(beatmap); Assert.AreEqual("Beatmap with no header", beatmap.Metadata.Title); - Assert.AreEqual("Incredibly Evil Hacker", beatmap.Metadata.AuthorString); + Assert.AreEqual("Incredibly Evil Hacker", beatmap.Metadata.Author.Username); } } @@ -583,7 +583,7 @@ namespace osu.Game.Tests.Beatmaps.Formats Assert.DoesNotThrow(() => beatmap = decoder.Decode(stream)); Assert.IsNotNull(beatmap); Assert.AreEqual("Empty lines at start", beatmap.Metadata.Title); - Assert.AreEqual("Edge Case Hunter", beatmap.Metadata.AuthorString); + Assert.AreEqual("Edge Case Hunter", beatmap.Metadata.Author.Username); } } @@ -601,7 +601,7 @@ namespace osu.Game.Tests.Beatmaps.Formats Assert.DoesNotThrow(() => beatmap = decoder.Decode(stream)); Assert.IsNotNull(beatmap); Assert.AreEqual("The dog ate the file header", beatmap.Metadata.Title); - Assert.AreEqual("Why does this keep happening", beatmap.Metadata.AuthorString); + Assert.AreEqual("Why does this keep happening", beatmap.Metadata.Author.Username); } } @@ -619,7 +619,7 @@ namespace osu.Game.Tests.Beatmaps.Formats Assert.DoesNotThrow(() => beatmap = decoder.Decode(stream)); Assert.IsNotNull(beatmap); Assert.AreEqual("No empty line delimiting header from contents", beatmap.Metadata.Title); - Assert.AreEqual("Edge Case Hunter", beatmap.Metadata.AuthorString); + Assert.AreEqual("Edge Case Hunter", beatmap.Metadata.Author.Username); } } diff --git a/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs index 9ec2f37569..37c1dfc657 100644 --- a/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs @@ -35,7 +35,7 @@ namespace osu.Game.Tests.Beatmaps.Formats Assert.AreEqual("Soleily", meta.Artist); Assert.AreEqual("Soleily", meta.ArtistUnicode); Assert.AreEqual("03. Renatus - Soleily 192kbps.mp3", meta.AudioFile); - Assert.AreEqual("Gamu", meta.AuthorString); + Assert.AreEqual("Gamu", meta.Author.Username); Assert.AreEqual("machinetop_background.jpg", meta.BackgroundFile); Assert.AreEqual(164471, meta.PreviewTime); Assert.AreEqual(string.Empty, meta.Source); diff --git a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs index d68d43c998..a19e977c1a 100644 --- a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs +++ b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs @@ -17,12 +17,12 @@ using osu.Framework.Logging; using osu.Game.Beatmaps; using osu.Game.Database; using osu.Game.IO; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Scoring; using osu.Game.Tests.Resources; using osu.Game.Tests.Scores.IO; -using osu.Game.Users; using SharpCompress.Archives; using SharpCompress.Archives.Zip; using SharpCompress.Common; @@ -408,8 +408,8 @@ namespace osu.Game.Tests.Beatmaps.IO var manager = osu.Dependencies.Get(); // ReSharper disable once AccessToModifiedClosure - manager.ItemUpdated.BindValueChanged(_ => Interlocked.Increment(ref itemAddRemoveFireCount)); - manager.ItemRemoved.BindValueChanged(_ => Interlocked.Increment(ref itemAddRemoveFireCount)); + manager.ItemUpdated += _ => Interlocked.Increment(ref itemAddRemoveFireCount); + manager.ItemRemoved += _ => Interlocked.Increment(ref itemAddRemoveFireCount); var imported = await LoadOszIntoOsu(osu); @@ -859,7 +859,7 @@ namespace osu.Game.Tests.Beatmaps.IO var manager = osu.Dependencies.Get(); - var working = manager.CreateNew(new OsuRuleset().RulesetInfo, User.SYSTEM_USER); + var working = manager.CreateNew(new OsuRuleset().RulesetInfo, APIUser.SYSTEM_USER); var beatmap = working.Beatmap; @@ -892,7 +892,7 @@ namespace osu.Game.Tests.Beatmaps.IO var osu = LoadOsuIntoHost(host); var manager = osu.Dependencies.Get(); - var working = manager.CreateNew(new OsuRuleset().RulesetInfo, User.SYSTEM_USER); + var working = manager.CreateNew(new OsuRuleset().RulesetInfo, APIUser.SYSTEM_USER); manager.Save(working.BeatmapInfo, working.Beatmap); @@ -919,7 +919,7 @@ namespace osu.Game.Tests.Beatmaps.IO var osu = LoadOsuIntoHost(host); var manager = osu.Dependencies.Get(); - var working = manager.CreateNew(new OsuRuleset().RulesetInfo, User.SYSTEM_USER); + var working = manager.CreateNew(new OsuRuleset().RulesetInfo, APIUser.SYSTEM_USER); ((Beatmap)working.Beatmap).HitObjects.Add(new HitCircle { StartTime = 5000 }); diff --git a/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs b/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs index d11da5e2a3..eaf5d107ca 100644 --- a/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs +++ b/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs @@ -60,7 +60,7 @@ namespace osu.Game.Tests.Beatmaps.IO Assert.AreEqual("Soleily", meta.Artist); Assert.AreEqual("Soleily", meta.ArtistUnicode); Assert.AreEqual("03. Renatus - Soleily 192kbps.mp3", meta.AudioFile); - Assert.AreEqual("Deif", meta.AuthorString); + Assert.AreEqual("Deif", meta.Author.Username); Assert.AreEqual("machinetop_background.jpg", meta.BackgroundFile); Assert.AreEqual(164471, meta.PreviewTime); Assert.AreEqual(string.Empty, meta.Source); diff --git a/osu.Game.Tests/Beatmaps/ToStringFormattingTest.cs b/osu.Game.Tests/Beatmaps/ToStringFormattingTest.cs index c477bbd9cf..da7f32a2d3 100644 --- a/osu.Game.Tests/Beatmaps/ToStringFormattingTest.cs +++ b/osu.Game.Tests/Beatmaps/ToStringFormattingTest.cs @@ -3,7 +3,7 @@ using NUnit.Framework; using osu.Game.Beatmaps; -using osu.Game.Users; +using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Tests.Beatmaps { @@ -34,7 +34,7 @@ namespace osu.Game.Tests.Beatmaps { Artist = "artist", Title = "title", - Author = new User { Username = "creator" } + Author = new APIUser { Username = "creator" } } }; @@ -50,7 +50,7 @@ namespace osu.Game.Tests.Beatmaps { Artist = "artist", Title = "title", - Author = new User { Username = "creator" } + Author = new APIUser { Username = "creator" } }, Version = "difficulty" }; diff --git a/osu.Game.Tests/Chat/TestSceneChannelManager.cs b/osu.Game.Tests/Chat/TestSceneChannelManager.cs index 5e22101e5c..eaacc623c9 100644 --- a/osu.Game.Tests/Chat/TestSceneChannelManager.cs +++ b/osu.Game.Tests/Chat/TestSceneChannelManager.cs @@ -9,9 +9,9 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Testing; using osu.Game.Online.API; using osu.Game.Online.API.Requests; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Chat; using osu.Game.Tests.Visual; -using osu.Game.Users; namespace osu.Game.Tests.Chat { @@ -133,7 +133,7 @@ namespace osu.Game.Tests.Chat } } - private Channel createChannel(int id, ChannelType type) => new Channel(new User()) + private Channel createChannel(int id, ChannelType type) => new Channel(new APIUser()) { Id = id, Name = $"Channel {id}", diff --git a/osu.Game.Tests/Database/BeatmapImporterTests.cs b/osu.Game.Tests/Database/BeatmapImporterTests.cs index a21f935f6b..e1fe1e224e 100644 --- a/osu.Game.Tests/Database/BeatmapImporterTests.cs +++ b/osu.Game.Tests/Database/BeatmapImporterTests.cs @@ -482,7 +482,10 @@ namespace osu.Game.Tests.Database var metadata = new RealmBeatmapMetadata { Artist = "SomeArtist", - Author = "SomeAuthor" + Author = + { + Username = "SomeAuthor" + } }; var ruleset = realmFactory.Context.All().First(); diff --git a/osu.Game.Tests/Database/TestRealmKeyBindingStore.cs b/osu.Game.Tests/Database/TestRealmKeyBindingStore.cs index f10b11733e..860828ae81 100644 --- a/osu.Game.Tests/Database/TestRealmKeyBindingStore.cs +++ b/osu.Game.Tests/Database/TestRealmKeyBindingStore.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; using NUnit.Framework; +using osu.Framework.Input; using osu.Framework.Input.Bindings; using osu.Framework.Platform; using osu.Game.Database; @@ -33,7 +34,7 @@ namespace osu.Game.Tests.Database storage = new NativeStorage(directory.FullName); realmContextFactory = new RealmContextFactory(storage, "test"); - keyBindingStore = new RealmKeyBindingStore(realmContextFactory); + keyBindingStore = new RealmKeyBindingStore(realmContextFactory, new ReadableKeyCombinationProvider()); } [Test] diff --git a/osu.Game.Tests/Editing/Checks/CheckBackgroundQualityTest.cs b/osu.Game.Tests/Editing/Checks/CheckBackgroundQualityTest.cs index 2918dde2db..05bfae7e63 100644 --- a/osu.Game.Tests/Editing/Checks/CheckBackgroundQualityTest.cs +++ b/osu.Game.Tests/Editing/Checks/CheckBackgroundQualityTest.cs @@ -54,7 +54,7 @@ namespace osu.Game.Tests.Editing.Checks { // While this is a problem, it is out of scope for this check and is caught by a different one. beatmap.Metadata.BackgroundFile = string.Empty; - var context = getContext(null, System.Array.Empty()); + var context = getContext(null, new MemoryStream(System.Array.Empty())); Assert.That(check.Run(context), Is.Empty); } @@ -103,7 +103,7 @@ namespace osu.Game.Tests.Editing.Checks [Test] public void TestTooUncompressed() { - var context = getContext(new Texture(1920, 1080), new byte[1024 * 1024 * 3]); + var context = getContext(new Texture(1920, 1080), new MemoryStream(new byte[1024 * 1024 * 3])); var issues = check.Run(context).ToList(); @@ -111,19 +111,32 @@ namespace osu.Game.Tests.Editing.Checks Assert.That(issues.Single().Template is CheckBackgroundQuality.IssueTemplateTooUncompressed); } - private BeatmapVerifierContext getContext(Texture background, [CanBeNull] byte[] fileBytes = null) + [Test] + public void TestStreamClosed() { - return new BeatmapVerifierContext(beatmap, getMockWorkingBeatmap(background, fileBytes).Object); + var background = new Texture(1920, 1080); + var stream = new Mock(new byte[1024 * 1024]); + + var context = getContext(background, stream.Object); + + Assert.That(check.Run(context), Is.Empty); + + stream.Verify(x => x.Close(), Times.Once()); + } + + private BeatmapVerifierContext getContext(Texture background, [CanBeNull] Stream stream = null) + { + return new BeatmapVerifierContext(beatmap, getMockWorkingBeatmap(background, stream).Object); } /// - /// Returns the mock of the working beatmap with the given background and filesize. + /// Returns the mock of the working beatmap with the given background and its file stream. /// /// The texture of the background. - /// The bytes that represent the background file. - private Mock getMockWorkingBeatmap(Texture background, [CanBeNull] byte[] fileBytes = null) + /// The stream representing the background file. + private Mock getMockWorkingBeatmap(Texture background, [CanBeNull] Stream stream = null) { - var stream = new MemoryStream(fileBytes ?? new byte[1024 * 1024]); + stream ??= new MemoryStream(new byte[1024 * 1024]); var mock = new Mock(); mock.SetupGet(w => w.Beatmap).Returns(beatmap); diff --git a/osu.Game.Tests/NonVisual/Multiplayer/StatefulMultiplayerClientTest.cs b/osu.Game.Tests/NonVisual/Multiplayer/StatefulMultiplayerClientTest.cs index 8e2259bce8..abe5664737 100644 --- a/osu.Game.Tests/NonVisual/Multiplayer/StatefulMultiplayerClientTest.cs +++ b/osu.Game.Tests/NonVisual/Multiplayer/StatefulMultiplayerClientTest.cs @@ -6,10 +6,10 @@ using Humanizer; using NUnit.Framework; using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Testing; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Multiplayer; using osu.Game.Online.Rooms; using osu.Game.Tests.Visual.Multiplayer; -using osu.Game.Users; namespace osu.Game.Tests.NonVisual.Multiplayer { @@ -21,7 +21,7 @@ namespace osu.Game.Tests.NonVisual.Multiplayer { int id = 2000; - AddRepeatStep("add some users", () => Client.AddUser(new User { Id = id++ }), 5); + AddRepeatStep("add some users", () => Client.AddUser(new APIUser { Id = id++ }), 5); checkPlayingUserCount(0); AddAssert("playlist item is available", () => Client.CurrentMatchPlayingItem.Value != null); @@ -64,7 +64,7 @@ namespace osu.Game.Tests.NonVisual.Multiplayer room.State = MultiplayerRoomState.Playing; room.Users.Add(new MultiplayerRoomUser(PLAYER_1_ID) { - User = new User { Id = PLAYER_1_ID }, + User = new APIUser { Id = PLAYER_1_ID }, State = MultiplayerUserState.Playing }); }; diff --git a/osu.Game.Tests/OnlinePlay/StatefulMultiplayerClientTest.cs b/osu.Game.Tests/OnlinePlay/StatefulMultiplayerClientTest.cs index 82ce588c6f..5a621ecf84 100644 --- a/osu.Game.Tests/OnlinePlay/StatefulMultiplayerClientTest.cs +++ b/osu.Game.Tests/OnlinePlay/StatefulMultiplayerClientTest.cs @@ -3,8 +3,8 @@ using NUnit.Framework; using osu.Framework.Testing; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Tests.Visual.Multiplayer; -using osu.Game.Users; namespace osu.Game.Tests.OnlinePlay { @@ -14,7 +14,7 @@ namespace osu.Game.Tests.OnlinePlay [Test] public void TestUserAddedOnJoin() { - var user = new User { Id = 33 }; + var user = new APIUser { Id = 33 }; AddRepeatStep("add user multiple times", () => Client.AddUser(user), 3); AddAssert("room has 2 users", () => Client.Room?.Users.Count == 2); @@ -23,7 +23,7 @@ namespace osu.Game.Tests.OnlinePlay [Test] public void TestUserRemovedOnLeave() { - var user = new User { Id = 44 }; + var user = new APIUser { Id = 44 }; AddStep("add user", () => Client.AddUser(user)); AddAssert("room has 2 users", () => Client.Room?.Users.Count == 2); diff --git a/osu.Game.Tests/Scores/IO/ImportScoreTest.cs b/osu.Game.Tests/Scores/IO/ImportScoreTest.cs index 2cd02329b7..be7803734e 100644 --- a/osu.Game.Tests/Scores/IO/ImportScoreTest.cs +++ b/osu.Game.Tests/Scores/IO/ImportScoreTest.cs @@ -11,12 +11,12 @@ using osu.Framework.Allocation; using osu.Framework.Platform; using osu.Game.Beatmaps; using osu.Game.IO.Archives; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu.Mods; using osu.Game.Rulesets.Scoring; using osu.Game.Scoring; -using osu.Game.Users; namespace osu.Game.Tests.Scores.IO { @@ -38,7 +38,7 @@ namespace osu.Game.Tests.Scores.IO Accuracy = 0.8, MaxCombo = 500, Combo = 250, - User = new User { Username = "Test user" }, + User = new APIUser { Username = "Test user" }, Date = DateTimeOffset.Now, OnlineScoreID = 12345, }; diff --git a/osu.Game.Tests/Visual/Background/TestSceneBackgroundScreenDefault.cs b/osu.Game.Tests/Visual/Background/TestSceneBackgroundScreenDefault.cs index f7d42a2ee6..ec16578b71 100644 --- a/osu.Game.Tests/Visual/Background/TestSceneBackgroundScreenDefault.cs +++ b/osu.Game.Tests/Visual/Background/TestSceneBackgroundScreenDefault.cs @@ -10,10 +10,10 @@ using osu.Framework.Testing; using osu.Game.Configuration; using osu.Game.Graphics.Backgrounds; using osu.Game.Online.API; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Screens; using osu.Game.Screens.Backgrounds; using osu.Game.Skinning; -using osu.Game.Users; namespace osu.Game.Tests.Visual.Background { @@ -113,7 +113,7 @@ namespace osu.Game.Tests.Visual.Background AddStep($"set background mode to {source}", () => config.SetValue(OsuSetting.MenuBackgroundSource, source)); private void setSupporter(bool isSupporter) => - AddStep($"set supporter {isSupporter}", () => ((DummyAPIAccess)API).LocalUser.Value = new User + AddStep($"set supporter {isSupporter}", () => ((DummyAPIAccess)API).LocalUser.Value = new APIUser { IsSupporter = isSupporter, Id = API.LocalUser.Value.Id + 1, diff --git a/osu.Game.Tests/Visual/Background/TestSceneUserDimBackgrounds.cs b/osu.Game.Tests/Visual/Background/TestSceneUserDimBackgrounds.cs index 693c66ccb0..69ea1dc520 100644 --- a/osu.Game.Tests/Visual/Background/TestSceneUserDimBackgrounds.cs +++ b/osu.Game.Tests/Visual/Background/TestSceneUserDimBackgrounds.cs @@ -18,6 +18,7 @@ using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Rulesets; using osu.Game.Rulesets.Osu.Mods; using osu.Game.Scoring; @@ -29,7 +30,6 @@ using osu.Game.Screens.Ranking; using osu.Game.Screens.Select; using osu.Game.Tests.Beatmaps; using osu.Game.Tests.Resources; -using osu.Game.Users; using osuTK; using osuTK.Graphics; @@ -231,7 +231,7 @@ namespace osu.Game.Tests.Visual.Background AddStep("Transition to Results", () => player.Push(results = new FadeAccessibleResults(new ScoreInfo { - User = new User { Username = "osu!" }, + User = new APIUser { Username = "osu!" }, BeatmapInfo = new TestBeatmap(Ruleset.Value).BeatmapInfo, Ruleset = Ruleset.Value, }))); diff --git a/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCard.cs b/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCard.cs index 2aeb4ab4e2..0feaa8f480 100644 --- a/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCard.cs +++ b/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCard.cs @@ -9,17 +9,22 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; +using osu.Framework.Testing; using osu.Game.Beatmaps; using osu.Game.Beatmaps.Drawables.Cards; +using osu.Game.Online.API; +using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays; -using osu.Game.Users; using osuTK; +using APIUser = osu.Game.Online.API.Requests.Responses.APIUser; namespace osu.Game.Tests.Visual.Beatmaps { public class TestSceneBeatmapCard : OsuTestScene { + private DummyAPIAccess dummyAPI => (DummyAPIAccess)API; + private APIBeatmapSet[] testCases; #region Test case generation @@ -31,22 +36,51 @@ namespace osu.Game.Tests.Visual.Beatmaps normal.HasVideo = true; normal.HasStoryboard = true; + var withStatistics = CreateAPIBeatmapSet(Ruleset.Value); + withStatistics.Title = withStatistics.TitleUnicode = "play favourite stats"; + withStatistics.Status = BeatmapSetOnlineStatus.Approved; + withStatistics.FavouriteCount = 284_239; + withStatistics.PlayCount = 999_001; + withStatistics.Ranked = DateTimeOffset.Now.AddDays(-45); + withStatistics.HypeStatus = new BeatmapSetHypeStatus + { + Current = 34, + Required = 5 + }; + withStatistics.NominationStatus = new BeatmapSetNominationStatus + { + Current = 1, + Required = 2 + }; + var undownloadable = getUndownloadableBeatmapSet(); + undownloadable.LastUpdated = DateTimeOffset.Now.AddYears(-1); var someDifficulties = getManyDifficultiesBeatmapSet(11); + someDifficulties.Title = someDifficulties.TitleUnicode = "favourited"; someDifficulties.Title = someDifficulties.TitleUnicode = "some difficulties"; someDifficulties.Status = BeatmapSetOnlineStatus.Qualified; + someDifficulties.HasFavourited = true; + someDifficulties.FavouriteCount = 1; + someDifficulties.NominationStatus = new BeatmapSetNominationStatus + { + Current = 2, + Required = 2 + }; var manyDifficulties = getManyDifficultiesBeatmapSet(100); manyDifficulties.Status = BeatmapSetOnlineStatus.Pending; var explicitMap = CreateAPIBeatmapSet(Ruleset.Value); + explicitMap.Title = someDifficulties.TitleUnicode = "explicit beatmap"; explicitMap.HasExplicitContent = true; var featuredMap = CreateAPIBeatmapSet(Ruleset.Value); + featuredMap.Title = someDifficulties.TitleUnicode = "featured artist beatmap"; featuredMap.TrackId = 1; var explicitFeaturedMap = CreateAPIBeatmapSet(Ruleset.Value); + explicitFeaturedMap.Title = someDifficulties.TitleUnicode = "explicit featured artist"; explicitFeaturedMap.HasExplicitContent = true; explicitFeaturedMap.TrackId = 2; @@ -59,6 +93,7 @@ namespace osu.Game.Tests.Visual.Beatmaps testCases = new[] { normal, + withStatistics, undownloadable, someDifficulties, manyDifficulties, @@ -75,7 +110,7 @@ namespace osu.Game.Tests.Visual.Beatmaps Title = "undownloadable beatmap", Artist = "test", Source = "more tests", - Author = new User + Author = new APIUser { Username = "BanchoBot", Id = 3, @@ -120,7 +155,7 @@ namespace osu.Game.Tests.Visual.Beatmaps OnlineID = 1, Title = "many difficulties beatmap", Artist = "test", - Author = new User + Author = new APIUser { Username = "BanchoBot", Id = 3, @@ -134,6 +169,19 @@ namespace osu.Game.Tests.Visual.Beatmaps #endregion + [SetUpSteps] + public void SetUpSteps() + { + AddStep("register request handling", () => dummyAPI.HandleRequest = request => + { + if (!(request is PostBeatmapFavouriteRequest)) + return false; + + request.TriggerSuccess(); + return true; + }); + } + private Drawable createContent(OverlayColourScheme colourScheme, Func creationFunc) { var colourProvider = new OverlayColourProvider(colourScheme); diff --git a/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCardFavouriteButton.cs b/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCardFavouriteButton.cs new file mode 100644 index 0000000000..77c9debef6 --- /dev/null +++ b/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCardFavouriteButton.cs @@ -0,0 +1,86 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Linq; +using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Testing; +using osu.Game.Beatmaps.Drawables.Cards.Buttons; +using osu.Game.Online.API; +using osu.Game.Online.API.Requests; +using osu.Game.Online.API.Requests.Responses; +using osu.Game.Overlays; +using osu.Game.Resources.Localisation.Web; +using osuTK; +using osuTK.Input; + +namespace osu.Game.Tests.Visual.Beatmaps +{ + public class TestSceneBeatmapCardFavouriteButton : OsuManualInputManagerTestScene + { + private DummyAPIAccess dummyAPI => (DummyAPIAccess)API; + + [Cached] + private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue); + + [Test] + public void TestInitialState([Values] bool favourited) + { + APIBeatmapSet beatmapSetInfo = null; + FavouriteButton button = null; + + AddStep("create beatmap set", () => + { + beatmapSetInfo = CreateAPIBeatmapSet(Ruleset.Value); + beatmapSetInfo.HasFavourited = favourited; + }); + AddStep("create button", () => Child = button = new FavouriteButton(beatmapSetInfo) { Scale = new Vector2(2) }); + + assertCorrectIcon(favourited); + AddAssert("correct tooltip text", () => button.TooltipText == (favourited ? BeatmapsetsStrings.ShowDetailsUnfavourite : BeatmapsetsStrings.ShowDetailsFavourite)); + } + + [Test] + public void TestRequestHandling() + { + APIBeatmapSet beatmapSetInfo = null; + FavouriteButton button = null; + BeatmapFavouriteAction? lastRequestAction = null; + + AddStep("create beatmap set", () => beatmapSetInfo = CreateAPIBeatmapSet(Ruleset.Value)); + AddStep("create button", () => Child = button = new FavouriteButton(beatmapSetInfo) { Scale = new Vector2(2) }); + + assertCorrectIcon(false); + + AddStep("register request handling", () => dummyAPI.HandleRequest = request => + { + if (!(request is PostBeatmapFavouriteRequest favouriteRequest)) + return false; + + lastRequestAction = favouriteRequest.Action; + request.TriggerSuccess(); + return true; + }); + + AddStep("click icon", () => + { + InputManager.MoveMouseTo(button); + InputManager.Click(MouseButton.Left); + }); + AddUntilStep("favourite request sent", () => lastRequestAction == BeatmapFavouriteAction.Favourite); + assertCorrectIcon(true); + + AddStep("click icon", () => + { + InputManager.MoveMouseTo(button); + InputManager.Click(MouseButton.Left); + }); + AddUntilStep("unfavourite request sent", () => lastRequestAction == BeatmapFavouriteAction.UnFavourite); + assertCorrectIcon(false); + } + + private void assertCorrectIcon(bool favourited) => AddAssert("icon correct", + () => this.ChildrenOfType().Single().Icon.Equals(favourited ? FontAwesome.Solid.Heart : FontAwesome.Regular.Heart)); + } +} diff --git a/osu.Game.Tests/Visual/Components/TestScenePreviewTrackManager.cs b/osu.Game.Tests/Visual/Components/TestScenePreviewTrackManager.cs index 89e20043fb..82b6710a17 100644 --- a/osu.Game.Tests/Visual/Components/TestScenePreviewTrackManager.cs +++ b/osu.Game.Tests/Visual/Components/TestScenePreviewTrackManager.cs @@ -13,10 +13,17 @@ namespace osu.Game.Tests.Visual.Components { public class TestScenePreviewTrackManager : OsuTestScene, IPreviewTrackOwner { - private readonly TestPreviewTrackManager trackManager = new TestPreviewTrackManager(); + private readonly IAdjustableAudioComponent gameTrackAudio = new AudioAdjustments(); + + private readonly TestPreviewTrackManager trackManager; private AudioManager audio; + public TestScenePreviewTrackManager() + { + trackManager = new TestPreviewTrackManager(gameTrackAudio); + } + protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) { var dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); @@ -151,19 +158,19 @@ namespace osu.Game.Tests.Visual.Components audio.VolumeTrack.Value = 1; }); - AddAssert("game not muted", () => audio.Tracks.AggregateVolume.Value != 0); + AddAssert("game not muted", () => gameTrackAudio.AggregateVolume.Value != 0); AddStep("get track", () => Add(owner = new TestTrackOwner(track = getTrack()))); AddUntilStep("wait loaded", () => track.IsLoaded); AddStep("start track", () => track.Start()); - AddAssert("game is muted", () => audio.Tracks.AggregateVolume.Value == 0); + AddAssert("game is muted", () => gameTrackAudio.AggregateVolume.Value == 0); if (stopAnyPlaying) AddStep("stop any playing", () => trackManager.StopAnyPlaying(owner)); else AddStep("stop track", () => track.Stop()); - AddAssert("game not muted", () => audio.Tracks.AggregateVolume.Value != 0); + AddAssert("game not muted", () => gameTrackAudio.AggregateVolume.Value != 0); } [Test] @@ -224,6 +231,11 @@ namespace osu.Game.Tests.Visual.Components public new PreviewTrack CurrentTrack => base.CurrentTrack; + public TestPreviewTrackManager(IAdjustableAudioComponent mainTrackAdjustments) + : base(mainTrackAdjustments) + { + } + protected override TrackManagerPreviewTrack CreatePreviewTrack(IBeatmapSetInfo beatmapSetInfo, ITrackStore trackStore) => new TestPreviewTrack(beatmapSetInfo, trackStore); public override bool UpdateSubTree() diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs index 0441c5641e..74212de210 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs @@ -7,8 +7,8 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Testing; using osu.Framework.Utils; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Screens.Play.HUD; -using osu.Game.Users; using osuTK; namespace osu.Game.Tests.Visual.Gameplay @@ -39,7 +39,7 @@ namespace osu.Game.Tests.Visual.Gameplay playerScore.Value = 1222333; }); - AddStep("add local player", () => createLeaderboardScore(playerScore, new User { Username = "You", Id = 3 }, true)); + AddStep("add local player", () => createLeaderboardScore(playerScore, new APIUser { Username = "You", Id = 3 }, true)); AddStep("toggle expanded", () => leaderboard.Expanded.Value = !leaderboard.Expanded.Value); AddSliderStep("set player score", 50, 5000000, 1222333, v => playerScore.Value = v); } @@ -50,8 +50,8 @@ namespace osu.Game.Tests.Visual.Gameplay var player2Score = new BindableDouble(1234567); var player3Score = new BindableDouble(1111111); - AddStep("add player 2", () => createLeaderboardScore(player2Score, new User { Username = "Player 2" })); - AddStep("add player 3", () => createLeaderboardScore(player3Score, new User { Username = "Player 3" })); + AddStep("add player 2", () => createLeaderboardScore(player2Score, new APIUser { Username = "Player 2" })); + AddStep("add player 3", () => createLeaderboardScore(player3Score, new APIUser { Username = "Player 3" })); AddUntilStep("is player 2 position #1", () => leaderboard.CheckPositionByUsername("Player 2", 1)); AddUntilStep("is player position #2", () => leaderboard.CheckPositionByUsername("You", 2)); @@ -72,38 +72,38 @@ namespace osu.Game.Tests.Visual.Gameplay public void TestRandomScores() { int playerNumber = 1; - AddRepeatStep("add player with random score", () => createRandomScore(new User { Username = $"Player {playerNumber++}" }), 10); + AddRepeatStep("add player with random score", () => createRandomScore(new APIUser { Username = $"Player {playerNumber++}" }), 10); } [Test] public void TestExistingUsers() { - AddStep("add peppy", () => createRandomScore(new User { Username = "peppy", Id = 2 })); - AddStep("add smoogipoo", () => createRandomScore(new User { Username = "smoogipoo", Id = 1040328 })); - AddStep("add flyte", () => createRandomScore(new User { Username = "flyte", Id = 3103765 })); - AddStep("add frenzibyte", () => createRandomScore(new User { Username = "frenzibyte", Id = 14210502 })); + AddStep("add peppy", () => createRandomScore(new APIUser { Username = "peppy", Id = 2 })); + AddStep("add smoogipoo", () => createRandomScore(new APIUser { Username = "smoogipoo", Id = 1040328 })); + AddStep("add flyte", () => createRandomScore(new APIUser { Username = "flyte", Id = 3103765 })); + AddStep("add frenzibyte", () => createRandomScore(new APIUser { Username = "frenzibyte", Id = 14210502 })); } [Test] public void TestMaxHeight() { int playerNumber = 1; - AddRepeatStep("add 3 other players", () => createRandomScore(new User { Username = $"Player {playerNumber++}" }), 3); + AddRepeatStep("add 3 other players", () => createRandomScore(new APIUser { Username = $"Player {playerNumber++}" }), 3); checkHeight(4); - AddRepeatStep("add 4 other players", () => createRandomScore(new User { Username = $"Player {playerNumber++}" }), 4); + AddRepeatStep("add 4 other players", () => createRandomScore(new APIUser { Username = $"Player {playerNumber++}" }), 4); checkHeight(8); - AddRepeatStep("add 4 other players", () => createRandomScore(new User { Username = $"Player {playerNumber++}" }), 4); + AddRepeatStep("add 4 other players", () => createRandomScore(new APIUser { Username = $"Player {playerNumber++}" }), 4); checkHeight(8); void checkHeight(int panelCount) => AddAssert($"leaderboard height is {panelCount} panels high", () => leaderboard.DrawHeight == (GameplayLeaderboardScore.PANEL_HEIGHT + leaderboard.Spacing) * panelCount); } - private void createRandomScore(User user) => createLeaderboardScore(new BindableDouble(RNG.Next(0, 5_000_000)), user); + private void createRandomScore(APIUser user) => createLeaderboardScore(new BindableDouble(RNG.Next(0, 5_000_000)), user); - private void createLeaderboardScore(BindableDouble score, User user, bool isTracked = false) + private void createLeaderboardScore(BindableDouble score, APIUser user, bool isTracked = false) { var leaderboardScore = leaderboard.Add(user, isTracked); leaderboardScore.TotalScore.BindTo(score); diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneReplayDownloadButton.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneReplayDownloadButton.cs index 64d9addc77..d4036fefc0 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneReplayDownloadButton.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneReplayDownloadButton.cs @@ -7,15 +7,16 @@ using osu.Framework.Graphics; using osu.Game.Online; using osu.Game.Online.API.Requests.Responses; using osu.Game.Scoring; -using osu.Game.Users; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Testing; +using osu.Game.Database; using osu.Game.Graphics.UserInterface; using osu.Game.Rulesets; using osu.Game.Rulesets.Osu; using osu.Game.Screens.Ranking; using osuTK.Input; +using APIUser = osu.Game.Online.API.Requests.Responses.APIUser; namespace osu.Game.Tests.Visual.Gameplay { @@ -113,6 +114,36 @@ namespace osu.Game.Tests.Visual.Gameplay AddAssert("button is not enabled", () => !downloadButton.ChildrenOfType().First().Enabled.Value); } + [Resolved] + private ScoreManager scoreManager { get; set; } + + [Test] + public void TestScoreImportThenDelete() + { + ILive imported = null; + + AddStep("create button without replay", () => + { + Child = downloadButton = new TestReplayDownloadButton(getScoreInfo(false)) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }; + }); + + AddUntilStep("wait for load", () => downloadButton.IsLoaded); + + AddUntilStep("state is not downloaded", () => downloadButton.State.Value == DownloadState.NotDownloaded); + + AddStep("import score", () => imported = scoreManager.Import(getScoreInfo(true)).Result); + + AddUntilStep("state is available", () => downloadButton.State.Value == DownloadState.LocallyAvailable); + + AddStep("delete score", () => scoreManager.Delete(imported.Value)); + + AddUntilStep("state is not downloaded", () => downloadButton.State.Value == DownloadState.NotDownloaded); + } + [Test] public void CreateButtonWithNoScore() { @@ -139,7 +170,7 @@ namespace osu.Game.Tests.Visual.Gameplay RulesetID = 0, Beatmap = CreateAPIBeatmapSet(new OsuRuleset().RulesetInfo).Beatmaps.First(), HasReplay = replayAvailable, - User = new User + User = new APIUser { Id = 39828, Username = @"WubWoofWolf", diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSpectator.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSpectator.cs index 21c5d89aca..20e859dd2b 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSpectator.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSpectator.cs @@ -9,6 +9,7 @@ using osu.Framework.Screens; using osu.Framework.Testing; using osu.Game.Beatmaps; using osu.Game.Database; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Spectator; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu.Replays; @@ -18,13 +19,12 @@ using osu.Game.Screens.Play; using osu.Game.Tests.Beatmaps.IO; using osu.Game.Tests.Visual.Multiplayer; using osu.Game.Tests.Visual.Spectator; -using osu.Game.Users; namespace osu.Game.Tests.Visual.Gameplay { public class TestSceneSpectator : ScreenTestScene { - private readonly User streamingUser = new User { Id = MultiplayerTestScene.PLAYER_1_ID, Username = "Test user" }; + private readonly APIUser streamingUser = new APIUser { Id = MultiplayerTestScene.PLAYER_1_ID, Username = "Test user" }; [Cached(typeof(UserLookupCache))] private UserLookupCache lookupCache = new TestUserLookupCache(); diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorHost.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorHost.cs index 89fea1f92d..2a82c65c7c 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorHost.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorHost.cs @@ -4,11 +4,11 @@ using NUnit.Framework; using osu.Framework.Allocation; using osu.Game.Online.API; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Spectator; using osu.Game.Rulesets; using osu.Game.Rulesets.Mania; using osu.Game.Tests.Visual.Spectator; -using osu.Game.Users; namespace osu.Game.Tests.Visual.Gameplay { @@ -24,7 +24,7 @@ namespace osu.Game.Tests.Visual.Gameplay public override void SetUpSteps() { - AddStep("set dummy user", () => dummyAPIAccess.LocalUser.Value = new User + AddStep("set dummy user", () => dummyAPIAccess.LocalUser.Value = new APIUser { Id = dummy_user_id, Username = "DummyUser" diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneUnstableRateCounter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneUnstableRateCounter.cs new file mode 100644 index 0000000000..0dc25cf378 --- /dev/null +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneUnstableRateCounter.cs @@ -0,0 +1,98 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Testing; +using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Osu.Scoring; +using osu.Game.Rulesets.Scoring; +using osu.Game.Screens.Play.HUD; +using osuTK; + +namespace osu.Game.Tests.Visual.Gameplay +{ + public class TestSceneUnstableRateCounter : OsuTestScene + { + [Cached(typeof(ScoreProcessor))] + private TestScoreProcessor scoreProcessor = new TestScoreProcessor(); + + private readonly OsuHitWindows hitWindows = new OsuHitWindows(); + + private UnstableRateCounter counter; + + private double prev; + + [SetUpSteps] + public void SetUp() + { + AddStep("Reset Score Processor", () => scoreProcessor.Reset()); + } + + [Test] + public void TestBasic() + { + AddStep("Create Display", recreateDisplay); + + // Needs multiples 2 by the nature of UR, and went for 4 to be safe. + // Creates a 250 UR by placing a +25ms then a -25ms judgement, which then results in a 250 UR + AddRepeatStep("Set UR to 250", () => applyJudgement(25, true), 4); + + AddUntilStep("UR = 250", () => counter.Current.Value == 250.0); + + AddRepeatStep("Revert UR", () => + { + scoreProcessor.RevertResult( + new JudgementResult(new HitCircle { HitWindows = hitWindows }, new Judgement()) + { + TimeOffset = 25, + Type = HitResult.Perfect, + }); + }, 4); + + AddUntilStep("UR is 0", () => counter.Current.Value == 0.0); + AddUntilStep("Counter is invalid", () => counter.Child.Alpha == 0.3f); + + //Sets a UR of 0 by creating 10 10ms offset judgements. Since average = offset, UR = 0 + AddRepeatStep("Set UR to 0", () => applyJudgement(10, false), 10); + //Applies a UR of 100 by creating 10 -10ms offset judgements. At the 10th judgement, offset should be 100. + AddRepeatStep("Bring UR to 100", () => applyJudgement(-10, false), 10); + } + + private void recreateDisplay() + { + Clear(); + + Add(counter = new UnstableRateCounter + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Scale = new Vector2(5), + }); + } + + private void applyJudgement(double offsetMs, bool alt) + { + double placement = offsetMs; + + if (alt) + { + placement = prev > 0 ? -offsetMs : offsetMs; + prev = placement; + } + + scoreProcessor.ApplyResult(new JudgementResult(new HitCircle { HitWindows = hitWindows }, new Judgement()) + { + TimeOffset = placement, + Type = HitResult.Perfect, + }); + } + + private class TestScoreProcessor : ScoreProcessor + { + public void Reset() => base.Reset(false); + } + } +} diff --git a/osu.Game.Tests/Visual/Menus/TestSceneDisclaimer.cs b/osu.Game.Tests/Visual/Menus/TestSceneDisclaimer.cs index 9cbdee3632..db5891bd4e 100644 --- a/osu.Game.Tests/Visual/Menus/TestSceneDisclaimer.cs +++ b/osu.Game.Tests/Visual/Menus/TestSceneDisclaimer.cs @@ -3,8 +3,8 @@ using osu.Framework.Allocation; using osu.Game.Online.API; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Screens.Menu; -using osu.Game.Users; namespace osu.Game.Tests.Visual.Menus { @@ -17,7 +17,7 @@ namespace osu.Game.Tests.Visual.Menus AddStep("toggle support", () => { - ((DummyAPIAccess)API).LocalUser.Value = new User + ((DummyAPIAccess)API).LocalUser.Value = new APIUser { Username = API.LocalUser.Value.Username, Id = API.LocalUser.Value.Id + 1, diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs index 84a6e95883..721862c177 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs @@ -10,6 +10,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Testing; using osu.Framework.Utils; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Rooms; using osu.Game.Online.Rooms.RoomStatuses; using osu.Game.Overlays; @@ -17,7 +18,6 @@ using osu.Game.Rulesets.Osu; using osu.Game.Screens.OnlinePlay.Lounge; using osu.Game.Screens.OnlinePlay.Lounge.Components; using osu.Game.Tests.Beatmaps; -using osu.Game.Users; using osuTK; namespace osu.Game.Tests.Visual.Multiplayer @@ -174,11 +174,11 @@ namespace osu.Game.Tests.Visual.Multiplayer private DrawableRoom createLoungeRoom(Room room) { - room.Host.Value ??= new User { Username = "peppy", Id = 2 }; + room.Host.Value ??= new APIUser { Username = "peppy", Id = 2 }; if (room.RecentParticipants.Count == 0) { - room.RecentParticipants.AddRange(Enumerable.Range(0, 20).Select(i => new User + room.RecentParticipants.AddRange(Enumerable.Range(0, 20).Select(i => new APIUser { Id = i, Username = $"User {i}" diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomParticipantsList.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomParticipantsList.cs index 982dfc5cd9..60f47a01a9 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomParticipantsList.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomParticipantsList.cs @@ -5,10 +5,10 @@ using System.Linq; using NUnit.Framework; using osu.Framework.Graphics; using osu.Framework.Testing; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Rooms; using osu.Game.Screens.OnlinePlay.Lounge.Components; using osu.Game.Tests.Visual.OnlinePlay; -using osu.Game.Users; using osu.Game.Users.Drawables; namespace osu.Game.Tests.Visual.Multiplayer @@ -25,7 +25,7 @@ namespace osu.Game.Tests.Visual.Multiplayer Name = { Value = "test room" }, Host = { - Value = new User + Value = new APIUser { Id = 2, Username = "peppy", @@ -137,7 +137,7 @@ namespace osu.Game.Tests.Visual.Multiplayer private void addUser(int id) { - SelectedRoom.Value.RecentParticipants.Add(new User + SelectedRoom.Value.RecentParticipants.Add(new APIUser { Id = id, Username = $"User {id}" diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs index afd48d5191..8ac0a2cbe5 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs @@ -14,6 +14,7 @@ using osu.Framework.Testing; using osu.Game.Beatmaps; using osu.Game.Beatmaps.Drawables; using osu.Game.Graphics.Containers; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Rooms; using osu.Game.Overlays.BeatmapListing.Panels; using osu.Game.Rulesets; @@ -21,7 +22,6 @@ using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu.Mods; using osu.Game.Screens.OnlinePlay; using osu.Game.Tests.Beatmaps; -using osu.Game.Users; using osuTK; using osuTK.Input; @@ -294,7 +294,7 @@ namespace osu.Game.Tests.Visual.Multiplayer Metadata = new BeatmapMetadata { Artist = "Artist", - Author = new User { Username = "Creator name here" }, + Author = new APIUser { Username = "Creator name here" }, Title = "Long title used to check background colour", }, BeatmapSet = new BeatmapSetInfo() diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchLeaderboard.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchLeaderboard.cs index a7a5f3af39..955710bd50 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchLeaderboard.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchLeaderboard.cs @@ -10,8 +10,8 @@ using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Rooms; using osu.Game.Screens.OnlinePlay.Match.Components; using osu.Game.Tests.Visual.OnlinePlay; -using osu.Game.Users; using osuTK; +using APIUser = osu.Game.Online.API.Requests.Responses.APIUser; namespace osu.Game.Tests.Visual.Multiplayer { @@ -32,7 +32,7 @@ namespace osu.Game.Tests.Visual.Multiplayer new APIUserScoreAggregate { UserID = 2, - User = new User { Id = 2, Username = "peppy" }, + User = new APIUser { Id = 2, Username = "peppy" }, TotalScore = 995533, RoomID = 3, CompletedBeatmaps = 1, @@ -42,7 +42,7 @@ namespace osu.Game.Tests.Visual.Multiplayer new APIUserScoreAggregate { UserID = 1040328, - User = new User { Id = 1040328, Username = "smoogipoo" }, + User = new APIUser { Id = 1040328, Username = "smoogipoo" }, TotalScore = 981100, RoomID = 3, CompletedBeatmaps = 1, diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorLeaderboard.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorLeaderboard.cs index bd5320354e..a61e505970 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorLeaderboard.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorLeaderboard.cs @@ -6,11 +6,11 @@ using System.Linq; using NUnit.Framework; using osu.Framework.Testing; using osu.Framework.Timing; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Multiplayer; using osu.Game.Rulesets.Osu.Scoring; using osu.Game.Screens.OnlinePlay.Multiplayer.Spectate; using osu.Game.Screens.Play.HUD; -using osu.Game.Users; namespace osu.Game.Tests.Visual.Multiplayer { @@ -35,7 +35,7 @@ namespace osu.Game.Tests.Visual.Multiplayer foreach ((int userId, var _) in clocks) { SpectatorClient.StartPlay(userId, 0); - OnlinePlayDependencies.Client.AddUser(new User { Id = userId }); + OnlinePlayDependencies.Client.AddUser(new APIUser { Id = userId }); } }); diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs index 7ff8c82145..fdd01446b9 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs @@ -11,6 +11,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Testing; using osu.Game.Beatmaps; using osu.Game.Configuration; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Multiplayer; using osu.Game.Online.Multiplayer.MatchTypes.TeamVersus; using osu.Game.Rulesets.UI; @@ -19,7 +20,6 @@ using osu.Game.Screens.Play; using osu.Game.Screens.Play.HUD; using osu.Game.Screens.Play.PlayerSettings; using osu.Game.Tests.Beatmaps.IO; -using osu.Game.Users; using osuTK.Graphics; namespace osu.Game.Tests.Visual.Multiplayer @@ -59,8 +59,8 @@ namespace osu.Game.Tests.Visual.Multiplayer { AddStep("start players silently", () => { - OnlinePlayDependencies.Client.AddUser(new User { Id = PLAYER_1_ID }, true); - OnlinePlayDependencies.Client.AddUser(new User { Id = PLAYER_2_ID }, true); + OnlinePlayDependencies.Client.AddUser(new APIUser { Id = PLAYER_1_ID }, true); + OnlinePlayDependencies.Client.AddUser(new APIUser { Id = PLAYER_2_ID }, true); playingUsers.Add(new MultiplayerRoomUser(PLAYER_1_ID)); playingUsers.Add(new MultiplayerRoomUser(PLAYER_2_ID)); @@ -120,13 +120,13 @@ namespace osu.Game.Tests.Visual.Multiplayer { AddStep("start players", () => { - var player1 = OnlinePlayDependencies.Client.AddUser(new User { Id = PLAYER_1_ID }, true); + var player1 = OnlinePlayDependencies.Client.AddUser(new APIUser { Id = PLAYER_1_ID }, true); player1.MatchState = new TeamVersusUserState { TeamID = 0, }; - var player2 = OnlinePlayDependencies.Client.AddUser(new User { Id = PLAYER_2_ID }, true); + var player2 = OnlinePlayDependencies.Client.AddUser(new APIUser { Id = PLAYER_2_ID }, true); player2.MatchState = new TeamVersusUserState { TeamID = 1, @@ -367,7 +367,7 @@ namespace osu.Game.Tests.Visual.Multiplayer { var user = new MultiplayerRoomUser(id) { - User = new User { Id = id }, + User = new APIUser { Id = id }, }; OnlinePlayDependencies.Client.AddUser(user.User, true); diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs index 38cf9d662f..e831d5b564 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs @@ -17,6 +17,7 @@ using osu.Framework.Utils; using osu.Game.Beatmaps; using osu.Game.Database; using osu.Game.Graphics.UserInterface; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Multiplayer; using osu.Game.Online.Rooms; using osu.Game.Overlays.Mods; @@ -32,7 +33,6 @@ using osu.Game.Screens.Play; using osu.Game.Screens.Ranking; using osu.Game.Screens.Spectate; using osu.Game.Tests.Resources; -using osu.Game.Users; using osuTK.Input; namespace osu.Game.Tests.Visual.Multiplayer @@ -129,12 +129,12 @@ namespace osu.Game.Tests.Visual.Multiplayer private void addRandomPlayer() { int randomUser = RNG.Next(200000, 500000); - client.AddUser(new User { Id = randomUser, Username = $"user {randomUser}" }); + client.AddUser(new APIUser { Id = randomUser, Username = $"user {randomUser}" }); } private void removeLastUser() { - User lastUser = client.Room?.Users.Last().User; + APIUser lastUser = client.Room?.Users.Last().User; if (lastUser == null || lastUser == client.LocalUser?.User) return; @@ -144,7 +144,7 @@ namespace osu.Game.Tests.Visual.Multiplayer private void kickLastUser() { - User lastUser = client.Room?.Users.Last().User; + APIUser lastUser = client.Room?.Users.Last().User; if (lastUser == null || lastUser == client.LocalUser?.User) return; @@ -414,7 +414,7 @@ namespace osu.Game.Tests.Visual.Multiplayer AddStep("join other user (ready, host)", () => { - client.AddUser(new User { Id = MultiplayerTestScene.PLAYER_1_ID, Username = "Other" }); + client.AddUser(new APIUser { Id = MultiplayerTestScene.PLAYER_1_ID, Username = "Other" }); client.TransferHost(MultiplayerTestScene.PLAYER_1_ID); client.ChangeUserState(MultiplayerTestScene.PLAYER_1_ID, MultiplayerUserState.Ready); }); @@ -454,7 +454,7 @@ namespace osu.Game.Tests.Visual.Multiplayer AddStep("join other user (ready, host)", () => { - client.AddUser(new User { Id = MultiplayerTestScene.PLAYER_1_ID, Username = "Other" }); + client.AddUser(new APIUser { Id = MultiplayerTestScene.PLAYER_1_ID, Username = "Other" }); client.TransferHost(MultiplayerTestScene.PLAYER_1_ID); client.ChangeUserState(MultiplayerTestScene.PLAYER_1_ID, MultiplayerUserState.Ready); }); diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboard.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboard.cs index 832998d5d3..902629765f 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboard.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboard.cs @@ -11,6 +11,7 @@ using osu.Framework.Graphics; using osu.Framework.Utils; using osu.Game.Configuration; using osu.Game.Online.API; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Multiplayer; using osu.Game.Online.Spectator; using osu.Game.Replays.Legacy; @@ -20,7 +21,6 @@ using osu.Game.Scoring; using osu.Game.Screens.Play.HUD; using osu.Game.Tests.Visual.OnlinePlay; using osu.Game.Tests.Visual.Spectator; -using osu.Game.Users; namespace osu.Game.Tests.Visual.Multiplayer { @@ -58,7 +58,7 @@ namespace osu.Game.Tests.Visual.Multiplayer foreach (int user in users) { SpectatorClient.StartPlay(user, Beatmap.Value.BeatmapInfo.OnlineBeatmapID ?? 0); - multiplayerUsers.Add(OnlinePlayDependencies.Client.AddUser(new User { Id = user }, true)); + multiplayerUsers.Add(OnlinePlayDependencies.Client.AddUser(new APIUser { Id = user }, true)); } Children = new Drawable[] diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboardTeams.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboardTeams.cs index 3d48ddc7ca..af4e696fce 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboardTeams.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboardTeams.cs @@ -7,6 +7,7 @@ using NUnit.Framework; using osu.Framework.Graphics; using osu.Framework.Utils; using osu.Game.Online.API; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Multiplayer; using osu.Game.Online.Multiplayer.MatchTypes.TeamVersus; using osu.Game.Online.Rooms; @@ -15,7 +16,6 @@ using osu.Game.Screens.OnlinePlay.Multiplayer; using osu.Game.Screens.Play.HUD; using osu.Game.Tests.Visual.OnlinePlay; using osu.Game.Tests.Visual.Spectator; -using osu.Game.Users; namespace osu.Game.Tests.Visual.Multiplayer { @@ -62,7 +62,7 @@ namespace osu.Game.Tests.Visual.Multiplayer foreach (int user in users) { SpectatorClient.StartPlay(user, Beatmap.Value.BeatmapInfo.OnlineBeatmapID ?? 0); - var roomUser = OnlinePlayDependencies.Client.AddUser(new User { Id = user }, true); + var roomUser = OnlinePlayDependencies.Client.AddUser(new APIUser { Id = user }, true); roomUser.MatchState = new TeamVersusUserState { diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSubScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSubScreen.cs index 21364fe154..bb5735a3b5 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSubScreen.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSubScreen.cs @@ -9,6 +9,7 @@ using osu.Framework.Platform; using osu.Framework.Screens; using osu.Framework.Testing; using osu.Game.Beatmaps; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Multiplayer; using osu.Game.Online.Rooms; using osu.Game.Rulesets; @@ -18,7 +19,6 @@ using osu.Game.Screens.OnlinePlay.Multiplayer; using osu.Game.Screens.OnlinePlay.Multiplayer.Match; using osu.Game.Tests.Beatmaps; using osu.Game.Tests.Resources; -using osu.Game.Users; using osuTK.Input; namespace osu.Game.Tests.Visual.Multiplayer @@ -119,7 +119,7 @@ namespace osu.Game.Tests.Visual.Multiplayer AddStep("join other user (ready)", () => { - Client.AddUser(new User { Id = PLAYER_1_ID }); + Client.AddUser(new APIUser { Id = PLAYER_1_ID }); Client.ChangeUserState(PLAYER_1_ID, MultiplayerUserState.Ready); }); diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerParticipantsList.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerParticipantsList.cs index 2549681519..671b85164b 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerParticipantsList.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerParticipantsList.cs @@ -11,6 +11,7 @@ using osu.Framework.Testing; using osu.Framework.Utils; using osu.Game.Graphics.UserInterface; using osu.Game.Online; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Multiplayer; using osu.Game.Online.Rooms; using osu.Game.Rulesets.Mods; @@ -34,7 +35,7 @@ namespace osu.Game.Tests.Visual.Multiplayer { AddAssert("one unique panel", () => this.ChildrenOfType().Select(p => p.User).Distinct().Count() == 1); - AddStep("add user", () => Client.AddUser(new User + AddStep("add user", () => Client.AddUser(new APIUser { Id = 3, Username = "Second", @@ -63,11 +64,11 @@ namespace osu.Game.Tests.Visual.Multiplayer [Test] public void TestRemoveUser() { - User secondUser = null; + APIUser secondUser = null; AddStep("add a user", () => { - Client.AddUser(secondUser = new User + Client.AddUser(secondUser = new APIUser { Id = 3, Username = "Second", @@ -146,7 +147,7 @@ namespace osu.Game.Tests.Visual.Multiplayer [Test] public void TestCrownChangesStateWhenHostTransferred() { - AddStep("add user", () => Client.AddUser(new User + AddStep("add user", () => Client.AddUser(new APIUser { Id = 3, Username = "Second", @@ -165,7 +166,7 @@ namespace osu.Game.Tests.Visual.Multiplayer [Test] public void TestKickButtonOnlyPresentWhenHost() { - AddStep("add user", () => Client.AddUser(new User + AddStep("add user", () => Client.AddUser(new APIUser { Id = 3, Username = "Second", @@ -186,7 +187,7 @@ namespace osu.Game.Tests.Visual.Multiplayer [Test] public void TestKickButtonKicks() { - AddStep("add user", () => Client.AddUser(new User + AddStep("add user", () => Client.AddUser(new APIUser { Id = 3, Username = "Second", @@ -205,7 +206,7 @@ namespace osu.Game.Tests.Visual.Multiplayer { for (int i = 0; i < 20; i++) { - Client.AddUser(new User + Client.AddUser(new APIUser { Id = i, Username = $"User {i}", @@ -249,7 +250,7 @@ namespace osu.Game.Tests.Visual.Multiplayer { AddStep("add user", () => { - Client.AddUser(new User + Client.AddUser(new APIUser { Id = 0, Username = "User 0", @@ -295,7 +296,7 @@ namespace osu.Game.Tests.Visual.Multiplayer AddStep("add user with mods", () => { - Client.AddUser(new User + Client.AddUser(new APIUser { Id = 0, Username = "Baka", diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerReadyButton.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerReadyButton.cs index 820b403a10..e9612bf55c 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerReadyButton.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerReadyButton.cs @@ -14,12 +14,12 @@ using osu.Framework.Testing; using osu.Framework.Utils; using osu.Game.Beatmaps; using osu.Game.Graphics.UserInterface; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Multiplayer; using osu.Game.Online.Rooms; using osu.Game.Rulesets; using osu.Game.Screens.OnlinePlay.Multiplayer.Match; using osu.Game.Tests.Resources; -using osu.Game.Users; using osuTK; using osuTK.Input; @@ -108,7 +108,7 @@ namespace osu.Game.Tests.Visual.Multiplayer { AddStep("add second user as host", () => { - Client.AddUser(new User { Id = 2, Username = "Another user" }); + Client.AddUser(new APIUser { Id = 2, Username = "Another user" }); Client.TransferHost(2); }); @@ -128,7 +128,7 @@ namespace osu.Game.Tests.Visual.Multiplayer Client.TransferHost(Client.Room?.Users[0].UserID ?? 0); if (!allReady) - Client.AddUser(new User { Id = 2, Username = "Another user" }); + Client.AddUser(new APIUser { Id = 2, Username = "Another user" }); }); addClickButtonStep(); @@ -142,7 +142,7 @@ namespace osu.Game.Tests.Visual.Multiplayer { AddStep("add host", () => { - Client.AddUser(new User { Id = 2, Username = "Another user" }); + Client.AddUser(new APIUser { Id = 2, Username = "Another user" }); Client.TransferHost(2); }); @@ -158,7 +158,7 @@ namespace osu.Game.Tests.Visual.Multiplayer AddStep("setup", () => { Client.TransferHost(Client.Room?.Users[0].UserID ?? 0); - Client.AddUser(new User { Id = 2, Username = "Another user" }); + Client.AddUser(new APIUser { Id = 2, Username = "Another user" }); }); addClickButtonStep(); @@ -177,7 +177,7 @@ namespace osu.Game.Tests.Visual.Multiplayer { Client.TransferHost(Client.Room?.Users[0].UserID ?? 0); for (int i = 0; i < users; i++) - Client.AddUser(new User { Id = i, Username = "Another user" }); + Client.AddUser(new APIUser { Id = i, Username = "Another user" }); }); if (!isHost) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerResults.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerResults.cs index 5032cdaec7..c0b21c4421 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerResults.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerResults.cs @@ -3,11 +3,11 @@ using System; using NUnit.Framework; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Rooms; using osu.Game.Rulesets.Osu; using osu.Game.Scoring; using osu.Game.Screens.OnlinePlay.Multiplayer; -using osu.Game.Users; namespace osu.Game.Tests.Visual.Multiplayer { @@ -31,7 +31,7 @@ namespace osu.Game.Tests.Visual.Multiplayer MaxCombo = 500, Combo = 250, BeatmapInfo = beatmapInfo, - User = new User { Username = "Test user" }, + User = new APIUser { Username = "Test user" }, Date = DateTimeOffset.Now, OnlineScoreID = 12345, Ruleset = rulesetInfo, diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerSpectateButton.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerSpectateButton.cs index 3d08d5da9e..76c8de93c7 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerSpectateButton.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerSpectateButton.cs @@ -14,12 +14,12 @@ using osu.Framework.Platform; using osu.Framework.Testing; using osu.Game.Beatmaps; using osu.Game.Graphics.UserInterface; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Multiplayer; using osu.Game.Online.Rooms; using osu.Game.Rulesets; using osu.Game.Screens.OnlinePlay.Multiplayer.Match; using osu.Game.Tests.Resources; -using osu.Game.Users; using osuTK; using osuTK.Input; @@ -145,7 +145,7 @@ namespace osu.Game.Tests.Visual.Multiplayer [Test] public void TestReadyButtonEnabledWhenHostAndUsersReady() { - AddStep("add user", () => Client.AddUser(new User { Id = PLAYER_1_ID })); + AddStep("add user", () => Client.AddUser(new APIUser { Id = PLAYER_1_ID })); AddStep("set user ready", () => Client.ChangeUserState(PLAYER_1_ID, MultiplayerUserState.Ready)); addClickSpectateButtonStep(); @@ -157,7 +157,7 @@ namespace osu.Game.Tests.Visual.Multiplayer { AddStep("add user and transfer host", () => { - Client.AddUser(new User { Id = PLAYER_1_ID }); + Client.AddUser(new APIUser { Id = PLAYER_1_ID }); Client.TransferHost(PLAYER_1_ID); }); diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerTeamResults.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerTeamResults.cs index 99d5fd46e9..d391c39c89 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerTeamResults.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerTeamResults.cs @@ -5,11 +5,11 @@ using System; using System.Collections.Generic; using NUnit.Framework; using osu.Framework.Bindables; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Rooms; using osu.Game.Rulesets.Osu; using osu.Game.Scoring; using osu.Game.Screens.OnlinePlay.Multiplayer; -using osu.Game.Users; namespace osu.Game.Tests.Visual.Multiplayer { @@ -35,7 +35,7 @@ namespace osu.Game.Tests.Visual.Multiplayer MaxCombo = 500, Combo = 250, BeatmapInfo = beatmapInfo, - User = new User { Username = "Test user" }, + User = new APIUser { Username = "Test user" }, Date = DateTimeOffset.Now, OnlineScoreID = 12345, Ruleset = rulesetInfo, diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneRankRangePill.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneRankRangePill.cs index 9e03743e8d..823ac07cf7 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneRankRangePill.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneRankRangePill.cs @@ -3,8 +3,8 @@ using NUnit.Framework; using osu.Framework.Graphics; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Screens.OnlinePlay.Lounge.Components; -using osu.Game.Users; namespace osu.Game.Tests.Visual.Multiplayer { @@ -25,7 +25,7 @@ namespace osu.Game.Tests.Visual.Multiplayer { AddStep("add user", () => { - Client.AddUser(new User + Client.AddUser(new APIUser { Id = 2, Statistics = { GlobalRank = 1234 } @@ -41,19 +41,19 @@ namespace osu.Game.Tests.Visual.Multiplayer { AddStep("add users", () => { - Client.AddUser(new User + Client.AddUser(new APIUser { Id = 2, Statistics = { GlobalRank = 1234 } }); - Client.AddUser(new User + Client.AddUser(new APIUser { Id = 3, Statistics = { GlobalRank = 3333 } }); - Client.AddUser(new User + Client.AddUser(new APIUser { Id = 4, Statistics = { GlobalRank = 4321 } @@ -75,13 +75,13 @@ namespace osu.Game.Tests.Visual.Multiplayer { AddStep("add users", () => { - Client.AddUser(new User + Client.AddUser(new APIUser { Id = 2, Statistics = { GlobalRank = min } }); - Client.AddUser(new User + Client.AddUser(new APIUser { Id = 3, Statistics = { GlobalRank = max } diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneTeamVersus.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneTeamVersus.cs index ad92886bab..1efa8d6810 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneTeamVersus.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneTeamVersus.cs @@ -127,9 +127,13 @@ namespace osu.Game.Tests.Visual.Multiplayer AddAssert("room type is head to head", () => client.Room?.Settings.MatchType == MatchType.HeadToHead); + AddUntilStep("team displays are not displaying teams", () => multiplayerScreenStack.ChildrenOfType().All(d => d.DisplayedTeam == null)); + AddStep("change to team vs", () => client.ChangeSettings(matchType: MatchType.TeamVersus)); AddAssert("room type is team vs", () => client.Room?.Settings.MatchType == MatchType.TeamVersus); + + AddUntilStep("team displays are displaying teams", () => multiplayerScreenStack.ChildrenOfType().All(d => d.DisplayedTeam != null)); } private void createRoom(Func room) diff --git a/osu.Game.Tests/Visual/Online/TestSceneAccountCreationOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneAccountCreationOverlay.cs index 06cc613c17..8f0da8d182 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneAccountCreationOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneAccountCreationOverlay.cs @@ -8,6 +8,7 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Testing; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays; using osu.Game.Overlays.AccountCreation; using osu.Game.Overlays.Settings; @@ -20,7 +21,7 @@ namespace osu.Game.Tests.Visual.Online private readonly Container userPanelArea; private readonly AccountCreationOverlay accountCreation; - private IBindable localUser; + private IBindable localUser; public TestSceneAccountCreationOverlay() { diff --git a/osu.Game.Tests/Visual/Online/TestSceneBeatmapListingOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneBeatmapListingOverlay.cs index c7a065fdd7..cbb6dce4d6 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneBeatmapListingOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneBeatmapListingOverlay.cs @@ -14,8 +14,8 @@ using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays; using osu.Game.Overlays.BeatmapListing; using osu.Game.Scoring; -using osu.Game.Users; using osuTK.Input; +using APIUser = osu.Game.Online.API.Requests.Responses.APIUser; namespace osu.Game.Tests.Visual.Online { @@ -53,7 +53,7 @@ namespace osu.Game.Tests.Visual.Online }; // non-supporter user - api.LocalUser.Value = new User + api.LocalUser.Value = new APIUser { Username = "TestBot", Id = API.LocalUser.Value.Id + 1, diff --git a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs index 63ce057667..86863c0b5d 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs @@ -7,11 +7,11 @@ using osu.Game.Beatmaps; using osu.Game.Overlays; using osu.Game.Overlays.BeatmapSet; using osu.Game.Rulesets; -using osu.Game.Users; using System; using System.Collections.Generic; using System.Linq; using osu.Game.Online.API.Requests.Responses; +using APIUser = osu.Game.Online.API.Requests.Responses.APIUser; namespace osu.Game.Tests.Visual.Online { @@ -56,7 +56,7 @@ namespace osu.Game.Tests.Visual.Online Artist = @"naru narusegawa", Source = @"hinata sou", Tags = @"test tag tag more tag", - Author = new User + Author = new APIUser { Username = @"BanchoBot", Id = 3, diff --git a/osu.Game.Tests/Visual/Online/TestSceneChannelTabControl.cs b/osu.Game.Tests/Visual/Online/TestSceneChannelTabControl.cs index 73e1fc9b35..e6eaffc4c1 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneChannelTabControl.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneChannelTabControl.cs @@ -11,9 +11,9 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Framework.Utils; using osu.Game.Graphics.Sprites; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Chat; using osu.Game.Overlays.Chat.Tabs; -using osu.Game.Users; using osuTK.Graphics; namespace osu.Game.Tests.Visual.Online @@ -108,7 +108,7 @@ namespace osu.Game.Tests.Visual.Online } private void addRandomPrivateChannel() => - channelTabControl.AddChannel(new Channel(new User + channelTabControl.AddChannel(new Channel(new APIUser { Id = RNG.Next(1000, 10000000), Username = "Test User " + RNG.Next(1000) diff --git a/osu.Game.Tests/Visual/Online/TestSceneChatLineTruncation.cs b/osu.Game.Tests/Visual/Online/TestSceneChatLineTruncation.cs index 8408b7dd60..444bd7e5fb 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneChatLineTruncation.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneChatLineTruncation.cs @@ -6,9 +6,9 @@ using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Chat; using osu.Game.Overlays.Chat; -using osu.Game.Users; namespace osu.Game.Tests.Visual.Online { @@ -55,14 +55,14 @@ namespace osu.Game.Tests.Visual.Online { private static long messageCounter; - internal static readonly User TEST_SENDER_BACKGROUND = new User + internal static readonly APIUser TEST_SENDER_BACKGROUND = new APIUser { Username = @"i-am-important", Id = 42, Colour = "#250cc9", }; - internal static readonly User TEST_SENDER = new User + internal static readonly APIUser TEST_SENDER = new APIUser { Username = @"Somebody", Id = 1, @@ -75,7 +75,7 @@ namespace osu.Game.Tests.Visual.Online { Content = text; IsAction = isAction; - Sender = new User + Sender = new APIUser { Username = username ?? $"user {number}", Id = number, diff --git a/osu.Game.Tests/Visual/Online/TestSceneChatLink.cs b/osu.Game.Tests/Visual/Online/TestSceneChatLink.cs index 74f53ebdca..a03c00eb58 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneChatLink.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneChatLink.cs @@ -10,10 +10,10 @@ using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Graphics; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Chat; using osu.Game.Overlays; using osu.Game.Overlays.Chat; -using osu.Game.Users; using osuTK.Graphics; namespace osu.Game.Tests.Visual.Online @@ -168,14 +168,14 @@ namespace osu.Game.Tests.Visual.Online { private static long messageCounter; - internal static readonly User TEST_SENDER_BACKGROUND = new User + internal static readonly APIUser TEST_SENDER_BACKGROUND = new APIUser { Username = @"i-am-important", Id = 42, Colour = "#250cc9", }; - internal static readonly User TEST_SENDER = new User + internal static readonly APIUser TEST_SENDER = new APIUser { Username = @"Somebody", Id = 1, @@ -188,7 +188,7 @@ namespace osu.Game.Tests.Visual.Online { Content = text; IsAction = isAction; - Sender = new User + Sender = new APIUser { Username = $"User {number}", Id = number, diff --git a/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs index 99c3b398ab..7028ecf39f 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs @@ -18,12 +18,12 @@ using osu.Framework.Testing; using osu.Game.Graphics.UserInterface; using osu.Game.Online.API; using osu.Game.Online.API.Requests; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Chat; using osu.Game.Overlays; using osu.Game.Overlays.Chat; using osu.Game.Overlays.Chat.Selection; using osu.Game.Overlays.Chat.Tabs; -using osu.Game.Users; using osuTK.Input; namespace osu.Game.Tests.Visual.Online @@ -53,7 +53,7 @@ namespace osu.Game.Tests.Visual.Online public TestSceneChatOverlay() { channels = Enumerable.Range(1, 10) - .Select(index => new Channel(new User()) + .Select(index => new Channel(new APIUser()) { Name = $"Channel no. {index}", Topic = index == 3 ? null : $"We talk about the number {index} here", @@ -98,7 +98,7 @@ namespace osu.Game.Tests.Visual.Online case GetUserRequest getUser: if (getUser.Lookup.Equals("some body", StringComparison.OrdinalIgnoreCase)) { - getUser.TriggerSuccess(new User + getUser.TriggerSuccess(new APIUser { Username = "some body", Id = 1, @@ -149,7 +149,7 @@ namespace osu.Game.Tests.Visual.Online { ChannelId = channel1.Id, Content = "hello from channel 1!", - Sender = new User + Sender = new APIUser { Id = 2, Username = "test_user" diff --git a/osu.Game.Tests/Visual/Online/TestSceneCurrentlyPlayingDisplay.cs b/osu.Game.Tests/Visual/Online/TestSceneCurrentlyPlayingDisplay.cs index 2f11fec6d1..b5a03b558d 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCurrentlyPlayingDisplay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCurrentlyPlayingDisplay.cs @@ -9,6 +9,7 @@ using NUnit.Framework; using osu.Framework.Graphics; using osu.Framework.Testing; using osu.Game.Database; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Spectator; using osu.Game.Overlays.Dashboard; using osu.Game.Tests.Visual.Spectator; @@ -18,7 +19,7 @@ namespace osu.Game.Tests.Visual.Online { public class TestSceneCurrentlyPlayingDisplay : OsuTestScene { - private readonly User streamingUser = new User { Id = 2, Username = "Test user" }; + private readonly APIUser streamingUser = new APIUser { Id = 2, Username = "Test user" }; private TestSpectatorClient spectatorClient; private CurrentlyPlayingDisplay currentlyPlaying; @@ -83,13 +84,13 @@ namespace osu.Game.Tests.Visual.Online "pishifat" }; - protected override Task ComputeValueAsync(int lookup, CancellationToken token = default) + protected override Task ComputeValueAsync(int lookup, CancellationToken token = default) { // tests against failed lookups if (lookup == 13) - return Task.FromResult(null); + return Task.FromResult(null); - return Task.FromResult(new User + return Task.FromResult(new APIUser { Id = lookup, Username = usernames[lookup % usernames.Length], diff --git a/osu.Game.Tests/Visual/Online/TestSceneDirectDownloadButton.cs b/osu.Game.Tests/Visual/Online/TestSceneDirectDownloadButton.cs index 3d828077c8..a865bbe950 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneDirectDownloadButton.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneDirectDownloadButton.cs @@ -45,10 +45,10 @@ namespace osu.Game.Tests.Visual.Online AddStep("import soleily", () => beatmaps.Import(TestResources.GetQuickTestBeatmapForImport())); AddUntilStep("wait for beatmap import", () => beatmaps.GetAllUsableBeatmapSets().Any(b => b.OnlineBeatmapSetID == 241526)); - AddAssert("button state downloaded", () => downloadButton.DownloadState == DownloadState.LocallyAvailable); + AddUntilStep("button state downloaded", () => downloadButton.DownloadState == DownloadState.LocallyAvailable); createButtonWithBeatmap(createSoleily()); - AddAssert("button state downloaded", () => downloadButton.DownloadState == DownloadState.LocallyAvailable); + AddUntilStep("button state downloaded", () => downloadButton.DownloadState == DownloadState.LocallyAvailable); ensureSoleilyRemoved(); AddAssert("button state not downloaded", () => downloadButton.DownloadState == DownloadState.NotDownloaded); } diff --git a/osu.Game.Tests/Visual/Online/TestSceneDirectPanel.cs b/osu.Game.Tests/Visual/Online/TestSceneDirectPanel.cs index a3c8935fa8..01dde97d38 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneDirectPanel.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneDirectPanel.cs @@ -10,8 +10,8 @@ using osu.Game.Beatmaps; using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays.BeatmapListing.Panels; using osu.Game.Rulesets; -using osu.Game.Users; using osuTK; +using APIUser = osu.Game.Online.API.Requests.Responses.APIUser; namespace osu.Game.Tests.Visual.Online { @@ -74,7 +74,7 @@ namespace osu.Game.Tests.Visual.Online Title = "undownloadable beatmap", Artist = "test", Source = "more tests", - Author = new User + Author = new APIUser { Username = "BanchoBot", Id = 3, @@ -121,7 +121,7 @@ namespace osu.Game.Tests.Visual.Online Title = "undownloadable beatmap", Artist = "test", Source = "more tests", - Author = new User + Author = new APIUser { Username = "BanchoBot", Id = 3, diff --git a/osu.Game.Tests/Visual/Online/TestSceneFriendDisplay.cs b/osu.Game.Tests/Visual/Online/TestSceneFriendDisplay.cs index e8d9ff72af..471d361c4e 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneFriendDisplay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneFriendDisplay.cs @@ -7,6 +7,7 @@ using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays; using osu.Game.Overlays.Dashboard.Friends; using osu.Game.Users; @@ -44,9 +45,9 @@ namespace osu.Game.Tests.Visual.Online // No need to do anything, fetch is performed automatically. } - private List getUsers() => new List + private List getUsers() => new List { - new User + new APIUser { Username = "flyte", Id = 3103765, @@ -55,7 +56,7 @@ namespace osu.Game.Tests.Visual.Online Country = new Country { FlagName = "JP" }, CoverUrl = "https://osu.ppy.sh/images/headers/profile-covers/c6.jpg" }, - new User + new APIUser { Username = "peppy", Id = 2, @@ -66,7 +67,7 @@ namespace osu.Game.Tests.Visual.Online IsSupporter = true, SupportLevel = 3, }, - new User + new APIUser { Username = "Evast", Id = 8195163, diff --git a/osu.Game.Tests/Visual/Online/TestSceneHistoricalSection.cs b/osu.Game.Tests/Visual/Online/TestSceneHistoricalSection.cs index 3ecca85ef1..2639a6506c 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneHistoricalSection.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneHistoricalSection.cs @@ -7,9 +7,9 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; using osu.Game.Graphics.Containers; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays; using osu.Game.Overlays.Profile.Sections; -using osu.Game.Users; namespace osu.Game.Tests.Visual.Online { @@ -37,8 +37,8 @@ namespace osu.Game.Tests.Visual.Online Child = section = new HistoricalSection(), }); - AddStep("Show peppy", () => section.User.Value = new User { Id = 2 }); - AddStep("Show WubWoofWolf", () => section.User.Value = new User { Id = 39828 }); + AddStep("Show peppy", () => section.User.Value = new APIUser { Id = 2 }); + AddStep("Show WubWoofWolf", () => section.User.Value = new APIUser { Id = 39828 }); } } } diff --git a/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs b/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs index d193856217..175d2ea36b 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs @@ -15,14 +15,14 @@ using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Chat; using osu.Game.Overlays; using osu.Game.Overlays.Notifications; -using osu.Game.Users; using osuTK.Input; +using APIUser = osu.Game.Online.API.Requests.Responses.APIUser; namespace osu.Game.Tests.Visual.Online { public class TestSceneMessageNotifier : OsuManualInputManagerTestScene { - private User friend; + private APIUser friend; private Channel publicChannel; private Channel privateMessageChannel; private TestContainer testContainer; @@ -37,7 +37,7 @@ namespace osu.Game.Tests.Visual.Online daa.HandleRequest = dummyAPIHandleRequest; } - friend = new User { Id = 0, Username = "Friend" }; + friend = new APIUser { Id = 0, Username = "Friend" }; publicChannel = new Channel { Id = 1, Name = "osu" }; privateMessageChannel = new Channel(friend) { Id = 2, Name = friend.Username, Type = ChannelType.PM }; @@ -178,9 +178,9 @@ namespace osu.Game.Tests.Visual.Online AddAssert("1 notification fired", () => testContainer.NotificationOverlay.UnreadCount.Value == 1); } - private void receiveMessage(User sender, Channel channel, string content) => channel.AddNewMessages(createMessage(sender, channel, content)); + private void receiveMessage(APIUser sender, Channel channel, string content) => channel.AddNewMessages(createMessage(sender, channel, content)); - private Message createMessage(User sender, Channel channel, string content) => new Message(messageIdCounter++) + private Message createMessage(APIUser sender, Channel channel, string content) => new Message(messageIdCounter++) { Content = content, Sender = sender, diff --git a/osu.Game.Tests/Visual/Online/TestSceneOfflineCommentsContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneOfflineCommentsContainer.cs index 4f7947b69c..0587e8884f 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneOfflineCommentsContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneOfflineCommentsContainer.cs @@ -11,9 +11,9 @@ using osu.Game.Overlays.Comments; using osu.Game.Overlays; using osu.Framework.Allocation; using osu.Game.Online.API.Requests.Responses; -using osu.Game.Users; using JetBrains.Annotations; using osu.Framework.Testing; +using APIUser = osu.Game.Online.API.Requests.Responses.APIUser; namespace osu.Game.Tests.Visual.Online { @@ -154,9 +154,9 @@ namespace osu.Game.Tests.Visual.Online { 5 }, - Users = new List + Users = new List { - new User + new APIUser { Id = 1, Username = "Good_Admin" diff --git a/osu.Game.Tests/Visual/Online/TestScenePlayHistorySubsection.cs b/osu.Game.Tests/Visual/Online/TestScenePlayHistorySubsection.cs index cf5ecf5bf2..fecc1af03c 100644 --- a/osu.Game.Tests/Visual/Online/TestScenePlayHistorySubsection.cs +++ b/osu.Game.Tests/Visual/Online/TestScenePlayHistorySubsection.cs @@ -4,7 +4,6 @@ using osu.Game.Overlays.Profile.Sections.Historical; using osu.Framework.Bindables; using osu.Framework.Graphics; -using osu.Game.Users; using NUnit.Framework; using osu.Game.Overlays; using osu.Framework.Allocation; @@ -12,7 +11,7 @@ using System; using System.Linq; using osu.Framework.Testing; using osu.Framework.Graphics.Shapes; -using static osu.Game.Users.User; +using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Tests.Visual.Online { @@ -21,7 +20,7 @@ namespace osu.Game.Tests.Visual.Online [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Red); - private readonly Bindable user = new Bindable(); + private readonly Bindable user = new Bindable(); private readonly PlayHistorySubsection section; public TestScenePlayHistorySubsection() @@ -101,80 +100,80 @@ namespace osu.Game.Tests.Visual.Online private int getChartValuesLength() => this.ChildrenOfType().Single().Values.Length; - private static readonly User user_with_null_values = new User + private static readonly APIUser user_with_null_values = new APIUser { Id = 1 }; - private static readonly User user_with_empty_values = new User + private static readonly APIUser user_with_empty_values = new APIUser { Id = 2, - MonthlyPlaycounts = Array.Empty() + MonthlyPlaycounts = Array.Empty() }; - private static readonly User user_with_one_value = new User + private static readonly APIUser user_with_one_value = new APIUser { Id = 3, MonthlyPlaycounts = new[] { - new UserHistoryCount { Date = new DateTime(2010, 5, 1), Count = 100 } + new APIUserHistoryCount { Date = new DateTime(2010, 5, 1), Count = 100 } } }; - private static readonly User user_with_two_values = new User + private static readonly APIUser user_with_two_values = new APIUser { Id = 4, MonthlyPlaycounts = new[] { - new UserHistoryCount { Date = new DateTime(2010, 5, 1), Count = 1 }, - new UserHistoryCount { Date = new DateTime(2010, 6, 1), Count = 2 } + new APIUserHistoryCount { Date = new DateTime(2010, 5, 1), Count = 1 }, + new APIUserHistoryCount { Date = new DateTime(2010, 6, 1), Count = 2 } } }; - private static readonly User user_with_constant_values = new User + private static readonly APIUser user_with_constant_values = new APIUser { Id = 5, MonthlyPlaycounts = new[] { - new UserHistoryCount { Date = new DateTime(2010, 5, 1), Count = 5 }, - new UserHistoryCount { Date = new DateTime(2010, 6, 1), Count = 5 }, - new UserHistoryCount { Date = new DateTime(2010, 7, 1), Count = 5 } + new APIUserHistoryCount { Date = new DateTime(2010, 5, 1), Count = 5 }, + new APIUserHistoryCount { Date = new DateTime(2010, 6, 1), Count = 5 }, + new APIUserHistoryCount { Date = new DateTime(2010, 7, 1), Count = 5 } } }; - private static readonly User user_with_zero_values = new User + private static readonly APIUser user_with_zero_values = new APIUser { Id = 6, MonthlyPlaycounts = new[] { - new UserHistoryCount { Date = new DateTime(2010, 5, 1), Count = 0 }, - new UserHistoryCount { Date = new DateTime(2010, 6, 1), Count = 0 }, - new UserHistoryCount { Date = new DateTime(2010, 7, 1), Count = 0 } + new APIUserHistoryCount { Date = new DateTime(2010, 5, 1), Count = 0 }, + new APIUserHistoryCount { Date = new DateTime(2010, 6, 1), Count = 0 }, + new APIUserHistoryCount { Date = new DateTime(2010, 7, 1), Count = 0 } } }; - private static readonly User user_with_filled_values = new User + private static readonly APIUser user_with_filled_values = new APIUser { Id = 7, MonthlyPlaycounts = new[] { - new UserHistoryCount { Date = new DateTime(2010, 5, 1), Count = 1000 }, - new UserHistoryCount { Date = new DateTime(2010, 6, 1), Count = 20 }, - new UserHistoryCount { Date = new DateTime(2010, 7, 1), Count = 20000 }, - new UserHistoryCount { Date = new DateTime(2010, 8, 1), Count = 30 }, - new UserHistoryCount { Date = new DateTime(2010, 9, 1), Count = 50 }, - new UserHistoryCount { Date = new DateTime(2010, 10, 1), Count = 2000 }, - new UserHistoryCount { Date = new DateTime(2010, 11, 1), Count = 2100 } + new APIUserHistoryCount { Date = new DateTime(2010, 5, 1), Count = 1000 }, + new APIUserHistoryCount { Date = new DateTime(2010, 6, 1), Count = 20 }, + new APIUserHistoryCount { Date = new DateTime(2010, 7, 1), Count = 20000 }, + new APIUserHistoryCount { Date = new DateTime(2010, 8, 1), Count = 30 }, + new APIUserHistoryCount { Date = new DateTime(2010, 9, 1), Count = 50 }, + new APIUserHistoryCount { Date = new DateTime(2010, 10, 1), Count = 2000 }, + new APIUserHistoryCount { Date = new DateTime(2010, 11, 1), Count = 2100 } } }; - private static readonly User user_with_missing_values = new User + private static readonly APIUser user_with_missing_values = new APIUser { Id = 8, MonthlyPlaycounts = new[] { - new UserHistoryCount { Date = new DateTime(2020, 1, 1), Count = 100 }, - new UserHistoryCount { Date = new DateTime(2020, 7, 1), Count = 200 } + new APIUserHistoryCount { Date = new DateTime(2020, 1, 1), Count = 100 }, + new APIUserHistoryCount { Date = new DateTime(2020, 7, 1), Count = 200 } } }; } diff --git a/osu.Game.Tests/Visual/Online/TestSceneProfileRulesetSelector.cs b/osu.Game.Tests/Visual/Online/TestSceneProfileRulesetSelector.cs index 6a847e4269..cbbe8b8eac 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneProfileRulesetSelector.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneProfileRulesetSelector.cs @@ -7,10 +7,10 @@ using osu.Game.Rulesets.Catch; using osu.Game.Rulesets.Mania; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Taiko; -using osu.Game.Users; using osu.Framework.Bindables; using osu.Game.Overlays; using osu.Framework.Allocation; +using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Tests.Visual.Online { @@ -22,7 +22,7 @@ namespace osu.Game.Tests.Visual.Online public TestSceneProfileRulesetSelector() { ProfileRulesetSelector selector; - var user = new Bindable(); + var user = new Bindable(); Child = selector = new ProfileRulesetSelector { @@ -36,10 +36,10 @@ namespace osu.Game.Tests.Visual.Online AddStep("set taiko as default", () => selector.SetDefaultRuleset(new TaikoRuleset().RulesetInfo)); AddStep("set catch as default", () => selector.SetDefaultRuleset(new CatchRuleset().RulesetInfo)); - AddStep("User with osu as default", () => user.Value = new User { PlayMode = "osu" }); - AddStep("User with mania as default", () => user.Value = new User { PlayMode = "mania" }); - AddStep("User with taiko as default", () => user.Value = new User { PlayMode = "taiko" }); - AddStep("User with catch as default", () => user.Value = new User { PlayMode = "fruits" }); + AddStep("User with osu as default", () => user.Value = new APIUser { PlayMode = "osu" }); + AddStep("User with mania as default", () => user.Value = new APIUser { PlayMode = "mania" }); + AddStep("User with taiko as default", () => user.Value = new APIUser { PlayMode = "taiko" }); + AddStep("User with catch as default", () => user.Value = new APIUser { PlayMode = "fruits" }); AddStep("null user", () => user.Value = null); } } diff --git a/osu.Game.Tests/Visual/Online/TestSceneRankGraph.cs b/osu.Game.Tests/Visual/Online/TestSceneRankGraph.cs index f577140e17..61574a7f23 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneRankGraph.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneRankGraph.cs @@ -7,6 +7,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays; using osu.Game.Overlays.Profile.Header.Components; using osu.Game.Users; @@ -81,7 +82,7 @@ namespace osu.Game.Tests.Visual.Online { GlobalRank = 89000, PP = 12345, - RankHistory = new User.RankHistoryData + RankHistory = new APIRankHistory { Data = data, } @@ -94,7 +95,7 @@ namespace osu.Game.Tests.Visual.Online { GlobalRank = 89000, PP = 12345, - RankHistory = new User.RankHistoryData + RankHistory = new APIRankHistory { Data = dataWithZeros, } @@ -107,7 +108,7 @@ namespace osu.Game.Tests.Visual.Online { GlobalRank = 12000, PP = 12345, - RankHistory = new User.RankHistoryData + RankHistory = new APIRankHistory { Data = smallData, } @@ -120,7 +121,7 @@ namespace osu.Game.Tests.Visual.Online { GlobalRank = 12000, PP = 12345, - RankHistory = new User.RankHistoryData + RankHistory = new APIRankHistory { Data = edgyData, } diff --git a/osu.Game.Tests/Visual/Online/TestSceneScoresContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneScoresContainer.cs index 23899154c4..50969aad9b 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneScoresContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneScoresContainer.cs @@ -15,6 +15,7 @@ using osu.Game.Rulesets.Osu.Mods; using osu.Game.Scoring; using osu.Game.Users; using osuTK.Graphics; +using APIUser = osu.Game.Online.API.Requests.Responses.APIUser; namespace osu.Game.Tests.Visual.Online { @@ -50,7 +51,7 @@ namespace osu.Game.Tests.Visual.Online { new APIScoreInfo { - User = new User + User = new APIUser { Id = 6602580, Username = @"waaiiru", @@ -75,7 +76,7 @@ namespace osu.Game.Tests.Visual.Online }, new APIScoreInfo { - User = new User + User = new APIUser { Id = 4608074, Username = @"Skycries", @@ -99,7 +100,7 @@ namespace osu.Game.Tests.Visual.Online }, new APIScoreInfo { - User = new User + User = new APIUser { Id = 1014222, Username = @"eLy", @@ -122,7 +123,7 @@ namespace osu.Game.Tests.Visual.Online }, new APIScoreInfo { - User = new User + User = new APIUser { Id = 1541390, Username = @"Toukai", @@ -144,7 +145,7 @@ namespace osu.Game.Tests.Visual.Online }, new APIScoreInfo { - User = new User + User = new APIUser { Id = 7151382, Username = @"Mayuri Hana", @@ -167,7 +168,7 @@ namespace osu.Game.Tests.Visual.Online { Score = new APIScoreInfo { - User = new User + User = new APIUser { Id = 7151382, Username = @"Mayuri Hana", @@ -190,7 +191,7 @@ namespace osu.Game.Tests.Visual.Online { Score = new APIScoreInfo { - User = new User + User = new APIUser { Id = 7151382, Username = @"Mayuri Hana", @@ -215,7 +216,7 @@ namespace osu.Game.Tests.Visual.Online { new APIScoreInfo { - User = new User + User = new APIUser { Id = 6602580, Username = @"waaiiru", diff --git a/osu.Game.Tests/Visual/Online/TestSceneStandAloneChatDisplay.cs b/osu.Game.Tests/Visual/Online/TestSceneStandAloneChatDisplay.cs index b3b8d75c46..b7bce012ce 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneStandAloneChatDisplay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneStandAloneChatDisplay.cs @@ -4,13 +4,13 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Game.Online.Chat; -using osu.Game.Users; using osuTK; using System; using System.Linq; using NUnit.Framework; using osu.Framework.Graphics.Containers; using osu.Game.Graphics.Containers; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays.Chat; using osuTK.Input; @@ -18,26 +18,26 @@ namespace osu.Game.Tests.Visual.Online { public class TestSceneStandAloneChatDisplay : OsuManualInputManagerTestScene { - private readonly User admin = new User + private readonly APIUser admin = new APIUser { Username = "HappyStick", Id = 2, Colour = "f2ca34" }; - private readonly User redUser = new User + private readonly APIUser redUser = new APIUser { Username = "BanchoBot", Id = 3, }; - private readonly User blueUser = new User + private readonly APIUser blueUser = new APIUser { Username = "Zallius", Id = 4, }; - private readonly User longUsernameUser = new User + private readonly APIUser longUsernameUser = new APIUser { Username = "Very Long Long Username", Id = 5, diff --git a/osu.Game.Tests/Visual/Online/TestSceneUserHistoryGraph.cs b/osu.Game.Tests/Visual/Online/TestSceneUserHistoryGraph.cs index 484c59695e..3f4a5cd420 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneUserHistoryGraph.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneUserHistoryGraph.cs @@ -2,11 +2,11 @@ // See the LICENCE file in the repository root for full licence text. using System; -using osu.Game.Overlays.Profile.Sections.Historical; -using osu.Framework.Graphics; -using osu.Game.Overlays; using osu.Framework.Allocation; -using static osu.Game.Users.User; +using osu.Framework.Graphics; +using osu.Game.Online.API.Requests.Responses; +using osu.Game.Overlays; +using osu.Game.Overlays.Profile.Sections.Historical; namespace osu.Game.Tests.Visual.Online { @@ -29,28 +29,28 @@ namespace osu.Game.Tests.Visual.Online var values = new[] { - new UserHistoryCount { Date = new DateTime(2000, 1, 1), Count = 10 }, - new UserHistoryCount { Date = new DateTime(2000, 2, 1), Count = 20 }, - new UserHistoryCount { Date = new DateTime(2000, 3, 1), Count = 100 }, - new UserHistoryCount { Date = new DateTime(2000, 4, 1), Count = 15 }, - new UserHistoryCount { Date = new DateTime(2000, 5, 1), Count = 30 } + new APIUserHistoryCount { Date = new DateTime(2000, 1, 1), Count = 10 }, + new APIUserHistoryCount { Date = new DateTime(2000, 2, 1), Count = 20 }, + new APIUserHistoryCount { Date = new DateTime(2000, 3, 1), Count = 100 }, + new APIUserHistoryCount { Date = new DateTime(2000, 4, 1), Count = 15 }, + new APIUserHistoryCount { Date = new DateTime(2000, 5, 1), Count = 30 } }; var moreValues = new[] { - new UserHistoryCount { Date = new DateTime(2010, 5, 1), Count = 1000 }, - new UserHistoryCount { Date = new DateTime(2010, 6, 1), Count = 20 }, - new UserHistoryCount { Date = new DateTime(2010, 7, 1), Count = 20000 }, - new UserHistoryCount { Date = new DateTime(2010, 8, 1), Count = 30 }, - new UserHistoryCount { Date = new DateTime(2010, 9, 1), Count = 50 }, - new UserHistoryCount { Date = new DateTime(2010, 10, 1), Count = 2000 }, - new UserHistoryCount { Date = new DateTime(2010, 11, 1), Count = 2100 } + new APIUserHistoryCount { Date = new DateTime(2010, 5, 1), Count = 1000 }, + new APIUserHistoryCount { Date = new DateTime(2010, 6, 1), Count = 20 }, + new APIUserHistoryCount { Date = new DateTime(2010, 7, 1), Count = 20000 }, + new APIUserHistoryCount { Date = new DateTime(2010, 8, 1), Count = 30 }, + new APIUserHistoryCount { Date = new DateTime(2010, 9, 1), Count = 50 }, + new APIUserHistoryCount { Date = new DateTime(2010, 10, 1), Count = 2000 }, + new APIUserHistoryCount { Date = new DateTime(2010, 11, 1), Count = 2100 } }; AddStep("Set fake values", () => graph.Values = values); AddStep("Set more values", () => graph.Values = moreValues); AddStep("Set null values", () => graph.Values = null); - AddStep("Set empty values", () => graph.Values = Array.Empty()); + AddStep("Set empty values", () => graph.Values = Array.Empty()); } } } diff --git a/osu.Game.Tests/Visual/Online/TestSceneUserPanel.cs b/osu.Game.Tests/Visual/Online/TestSceneUserPanel.cs index a048ae2c54..19e06beaad 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneUserPanel.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneUserPanel.cs @@ -7,6 +7,7 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Rulesets; using osu.Game.Users; using osuTK; @@ -42,27 +43,27 @@ namespace osu.Game.Tests.Visual.Online Spacing = new Vector2(10f), Children = new Drawable[] { - new UserBrickPanel(new User + new UserBrickPanel(new APIUser { Username = @"flyte", Id = 3103765, CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c6.jpg" }), - new UserBrickPanel(new User + new UserBrickPanel(new APIUser { Username = @"peppy", Id = 2, Colour = "99EB47", CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c3.jpg", }), - flyte = new UserGridPanel(new User + flyte = new UserGridPanel(new APIUser { Username = @"flyte", Id = 3103765, Country = new Country { FlagName = @"JP" }, CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c6.jpg" }) { Width = 300 }, - peppy = new UserGridPanel(new User + peppy = new UserGridPanel(new APIUser { Username = @"peppy", Id = 2, @@ -71,7 +72,7 @@ namespace osu.Game.Tests.Visual.Online IsSupporter = true, SupportLevel = 3, }) { Width = 300 }, - evast = new TestUserListPanel(new User + evast = new TestUserListPanel(new APIUser { Username = @"Evast", Id = 8195163, @@ -134,7 +135,7 @@ namespace osu.Game.Tests.Visual.Online private class TestUserListPanel : UserListPanel { - public TestUserListPanel(User user) + public TestUserListPanel(APIUser user) : base(user) { } diff --git a/osu.Game.Tests/Visual/Online/TestSceneUserProfileHeader.cs b/osu.Game.Tests/Visual/Online/TestSceneUserProfileHeader.cs index 04b741b2bb..76997bded7 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneUserProfileHeader.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneUserProfileHeader.cs @@ -5,6 +5,7 @@ using System; using osu.Framework.Allocation; using osu.Game.Online.API; using osu.Game.Online.API.Requests; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays; using osu.Game.Overlays.Profile; using osu.Game.Users; @@ -30,26 +31,26 @@ namespace osu.Game.Tests.Visual.Online AddStep("Show test dummy", () => header.User.Value = TestSceneUserProfileOverlay.TEST_USER); - AddStep("Show null dummy", () => header.User.Value = new User + AddStep("Show null dummy", () => header.User.Value = new APIUser { Username = "Null" }); - AddStep("Show online dummy", () => header.User.Value = new User + AddStep("Show online dummy", () => header.User.Value = new APIUser { Username = "IAmOnline", LastVisit = DateTimeOffset.Now, IsOnline = true, }); - AddStep("Show offline dummy", () => header.User.Value = new User + AddStep("Show offline dummy", () => header.User.Value = new APIUser { Username = "IAmOffline", LastVisit = DateTimeOffset.Now, IsOnline = false, }); - addOnlineStep("Show ppy", new User + addOnlineStep("Show ppy", new APIUser { Username = @"peppy", Id = 2, @@ -58,7 +59,7 @@ namespace osu.Game.Tests.Visual.Online CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c3.jpg" }); - addOnlineStep("Show flyte", new User + addOnlineStep("Show flyte", new APIUser { Username = @"flyte", Id = 3103765, @@ -67,7 +68,7 @@ namespace osu.Game.Tests.Visual.Online }); } - private void addOnlineStep(string name, User fallback) + private void addOnlineStep(string name, APIUser fallback) { AddStep(name, () => { diff --git a/osu.Game.Tests/Visual/Online/TestSceneUserProfileOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneUserProfileOverlay.cs index 70271b0b08..ce8136199f 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneUserProfileOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneUserProfileOverlay.cs @@ -6,6 +6,7 @@ using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; using osu.Game.Online.API; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays; using osu.Game.Overlays.Profile; using osu.Game.Users; @@ -22,7 +23,7 @@ namespace osu.Game.Tests.Visual.Online [Resolved] private IAPIProvider api { get; set; } - public static readonly User TEST_USER = new User + public static readonly APIUser TEST_USER = new APIUser { Username = @"Somebody", Id = 1, @@ -41,7 +42,7 @@ namespace osu.Game.Tests.Visual.Online Current = 727, Progress = 69, }, - RankHistory = new User.RankHistoryData + RankHistory = new APIRankHistory { Mode = @"osu", Data = Enumerable.Range(2345, 45).Concat(Enumerable.Range(2109, 40)).ToArray() @@ -58,7 +59,7 @@ namespace osu.Game.Tests.Visual.Online }, Title = "osu!volunteer", Colour = "ff0000", - Achievements = Array.Empty(), + Achievements = Array.Empty(), }; public TestSceneUserProfileOverlay() @@ -70,42 +71,42 @@ namespace osu.Game.Tests.Visual.Online { base.LoadComplete(); - AddStep("Show offline dummy", () => profile.ShowUser(TEST_USER, false)); + AddStep("Show offline dummy", () => profile.ShowUser(TEST_USER)); - AddStep("Show null dummy", () => profile.ShowUser(new User + AddStep("Show null dummy", () => profile.ShowUser(new APIUser { Username = @"Null", Id = 1, - }, false)); + })); - AddStep("Show ppy", () => profile.ShowUser(new User + AddStep("Show ppy", () => profile.ShowUser(new APIUser { Username = @"peppy", Id = 2, IsSupporter = true, Country = new Country { FullName = @"Australia", FlagName = @"AU" }, CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c3.jpg" - }, api.IsLoggedIn)); + })); - AddStep("Show flyte", () => profile.ShowUser(new User + AddStep("Show flyte", () => profile.ShowUser(new APIUser { Username = @"flyte", Id = 3103765, Country = new Country { FullName = @"Japan", FlagName = @"JP" }, CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c6.jpg" - }, api.IsLoggedIn)); + })); - AddStep("Show bancho", () => profile.ShowUser(new User + AddStep("Show bancho", () => profile.ShowUser(new APIUser { Username = @"BanchoBot", Id = 3, IsBot = true, Country = new Country { FullName = @"Saint Helena", FlagName = @"SH" }, CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c4.jpg" - }, api.IsLoggedIn)); + })); - AddStep("Show ppy from username", () => profile.ShowUser(@"peppy")); - AddStep("Show flyte from username", () => profile.ShowUser(@"flyte")); + AddStep("Show ppy from username", () => profile.ShowUser(new APIUser { Username = @"peppy" })); + AddStep("Show flyte from username", () => profile.ShowUser(new APIUser { Username = @"flyte" })); AddStep("Hide", profile.Hide); AddStep("Show without reload", profile.Show); diff --git a/osu.Game.Tests/Visual/Online/TestSceneUserProfilePreviousUsernames.cs b/osu.Game.Tests/Visual/Online/TestSceneUserProfilePreviousUsernames.cs index b5d2d15392..30774689a2 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneUserProfilePreviousUsernames.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneUserProfilePreviousUsernames.cs @@ -4,8 +4,8 @@ using System; using NUnit.Framework; using osu.Framework.Graphics; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays.Profile.Header.Components; -using osu.Game.Users; namespace osu.Game.Tests.Visual.Online { @@ -48,13 +48,13 @@ namespace osu.Game.Tests.Visual.Online AddUntilStep("Is hidden", () => container.Alpha == 0); } - private static readonly User[] users = + private static readonly APIUser[] users = { - new User { Id = 1, PreviousUsernames = new[] { "username1" } }, - new User { Id = 2, PreviousUsernames = new[] { "longusername", "longerusername" } }, - new User { Id = 3, PreviousUsernames = new[] { "test", "angelsim", "verylongusername" } }, - new User { Id = 4, PreviousUsernames = new[] { "ihavenoidea", "howcani", "makethistext", "anylonger" } }, - new User { Id = 5, PreviousUsernames = Array.Empty() }, + new APIUser { Id = 1, PreviousUsernames = new[] { "username1" } }, + new APIUser { Id = 2, PreviousUsernames = new[] { "longusername", "longerusername" } }, + new APIUser { Id = 3, PreviousUsernames = new[] { "test", "angelsim", "verylongusername" } }, + new APIUser { Id = 4, PreviousUsernames = new[] { "ihavenoidea", "howcani", "makethistext", "anylonger" } }, + new APIUser { Id = 5, PreviousUsernames = Array.Empty() }, null }; } diff --git a/osu.Game.Tests/Visual/Online/TestSceneUserRanks.cs b/osu.Game.Tests/Visual/Online/TestSceneUserRanks.cs index c22cff4af6..b9272e7294 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneUserRanks.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneUserRanks.cs @@ -8,9 +8,9 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; using osu.Game.Graphics.Containers; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays; using osu.Game.Overlays.Profile.Sections; -using osu.Game.Users; namespace osu.Game.Tests.Visual.Online { @@ -44,7 +44,7 @@ namespace osu.Game.Tests.Visual.Online } }); - AddStep("Show cookiezi", () => ranks.User.Value = new User { Id = 124493 }); + AddStep("Show cookiezi", () => ranks.User.Value = new APIUser { Id = 124493 }); } } } diff --git a/osu.Game.Tests/Visual/Online/TestSceneUserRequest.cs b/osu.Game.Tests/Visual/Online/TestSceneUserRequest.cs index 15cfd3ee54..e7b6a94642 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneUserRequest.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneUserRequest.cs @@ -9,10 +9,10 @@ using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Game.Rulesets; using osu.Game.Rulesets.Mania; -using osu.Game.Users; using osu.Framework.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Rulesets.Taiko; namespace osu.Game.Tests.Visual.Online @@ -23,7 +23,7 @@ namespace osu.Game.Tests.Visual.Online [Resolved] private IAPIProvider api { get; set; } - private readonly Bindable user = new Bindable(); + private readonly Bindable user = new Bindable(); private GetUserRequest request; private readonly LoadingLayer loading; @@ -71,7 +71,7 @@ namespace osu.Game.Tests.Visual.Online private class UserTestContainer : FillFlowContainer { - public readonly Bindable User = new Bindable(); + public readonly Bindable User = new Bindable(); public UserTestContainer() { @@ -85,7 +85,7 @@ namespace osu.Game.Tests.Visual.Online User.BindValueChanged(onUserUpdate, true); } - private void onUserUpdate(ValueChangedEvent user) + private void onUserUpdate(ValueChangedEvent user) { Clear(); diff --git a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsParticipantsList.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsParticipantsList.cs index 76a78c0a3c..1288b9e765 100644 --- a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsParticipantsList.cs +++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsParticipantsList.cs @@ -3,6 +3,7 @@ using NUnit.Framework; using osu.Framework.Graphics; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Rooms; using osu.Game.Screens.OnlinePlay.Components; using osu.Game.Tests.Visual.OnlinePlay; @@ -19,7 +20,7 @@ namespace osu.Game.Tests.Visual.Playlists for (int i = 0; i < 50; i++) { - SelectedRoom.Value.RecentParticipants.Add(new User + SelectedRoom.Value.RecentParticipants.Add(new APIUser { Username = "peppy", Statistics = new UserStatistics { GlobalRank = 1234 }, diff --git a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsResultsScreen.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsResultsScreen.cs index d948aebbbf..4284bc6358 100644 --- a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsResultsScreen.cs +++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsResultsScreen.cs @@ -14,6 +14,7 @@ using osu.Game.Graphics.Containers; using osu.Game.Graphics.UserInterface; using osu.Game.Online.API; using osu.Game.Online.API.Requests; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Rooms; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Scoring; @@ -21,7 +22,6 @@ using osu.Game.Scoring; using osu.Game.Screens.OnlinePlay.Playlists; using osu.Game.Screens.Ranking; using osu.Game.Tests.Beatmaps; -using osu.Game.Users; namespace osu.Game.Tests.Visual.Playlists { @@ -260,7 +260,7 @@ namespace osu.Game.Tests.Visual.Playlists Rank = userScore.Rank, MaxCombo = userScore.MaxCombo, TotalScore = userScore.TotalScore - i, - User = new User + User = new APIUser { Id = 2, Username = $"peppy{i}", @@ -278,7 +278,7 @@ namespace osu.Game.Tests.Visual.Playlists Rank = userScore.Rank, MaxCombo = userScore.MaxCombo, TotalScore = userScore.TotalScore + i, - User = new User + User = new APIUser { Id = 2, Username = $"peppy{i}", @@ -314,7 +314,7 @@ namespace osu.Game.Tests.Visual.Playlists Rank = ScoreRank.X, MaxCombo = 1000, TotalScore = startTotalScore + (sort == "score_asc" ? i : -i), - User = new User + User = new APIUser { Id = 2, Username = $"peppy{i}", diff --git a/osu.Game.Tests/Visual/Ranking/TestSceneAccuracyCircle.cs b/osu.Game.Tests/Visual/Ranking/TestSceneAccuracyCircle.cs index df8500fab2..944941723e 100644 --- a/osu.Game.Tests/Visual/Ranking/TestSceneAccuracyCircle.cs +++ b/osu.Game.Tests/Visual/Ranking/TestSceneAccuracyCircle.cs @@ -8,6 +8,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu.Mods; @@ -15,7 +16,6 @@ using osu.Game.Rulesets.Scoring; using osu.Game.Scoring; using osu.Game.Screens.Ranking.Expanded.Accuracy; using osu.Game.Tests.Beatmaps; -using osu.Game.Users; using osuTK; namespace osu.Game.Tests.Visual.Ranking @@ -66,7 +66,7 @@ namespace osu.Game.Tests.Visual.Ranking private ScoreInfo createScore(double accuracy, ScoreRank rank) => new ScoreInfo { - User = new User + User = new APIUser { Id = 2, Username = "peppy", diff --git a/osu.Game.Tests/Visual/Ranking/TestSceneExpandedPanelMiddleContent.cs b/osu.Game.Tests/Visual/Ranking/TestSceneExpandedPanelMiddleContent.cs index 899f351a2a..9983993d9c 100644 --- a/osu.Game.Tests/Visual/Ranking/TestSceneExpandedPanelMiddleContent.cs +++ b/osu.Game.Tests/Visual/Ranking/TestSceneExpandedPanelMiddleContent.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System.Linq; +using JetBrains.Annotations; using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; @@ -11,6 +12,7 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Testing; using osu.Game.Beatmaps; using osu.Game.Graphics.Sprites; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu; @@ -18,7 +20,6 @@ using osu.Game.Scoring; using osu.Game.Screens.Ranking; using osu.Game.Screens.Ranking.Expanded; using osu.Game.Tests.Beatmaps; -using osu.Game.Users; using osuTK; namespace osu.Game.Tests.Visual.Ranking @@ -31,7 +32,7 @@ namespace osu.Game.Tests.Visual.Ranking [Test] public void TestMapWithKnownMapper() { - var author = new User { Username = "mapper_name" }; + var author = new APIUser { Username = "mapper_name" }; AddStep("show example score", () => showPanel(new TestScoreInfo(new OsuRuleset().RulesetInfo) { @@ -42,7 +43,7 @@ namespace osu.Game.Tests.Visual.Ranking [Test] public void TestExcessMods() { - var author = new User { Username = "mapper_name" }; + var author = new APIUser { Username = "mapper_name" }; AddStep("show excess mods score", () => showPanel(new TestScoreInfo(new OsuRuleset().RulesetInfo, true) { @@ -57,7 +58,7 @@ namespace osu.Game.Tests.Visual.Ranking { AddStep("show example score", () => showPanel(new TestScoreInfo(new OsuRuleset().RulesetInfo) { - BeatmapInfo = createTestBeatmap(null) + BeatmapInfo = createTestBeatmap(new APIUser()) })); AddAssert("mapped by text not present", () => @@ -74,7 +75,7 @@ namespace osu.Game.Tests.Visual.Ranking var ruleset = new OsuRuleset(); var mods = new Mod[] { ruleset.GetAutoplayMod() }; - var beatmap = createTestBeatmap(null); + var beatmap = createTestBeatmap(new APIUser()); showPanel(new TestScoreInfo(ruleset.RulesetInfo) { @@ -90,7 +91,7 @@ namespace osu.Game.Tests.Visual.Ranking private void showPanel(ScoreInfo score) => Child = new ExpandedPanelMiddleContentContainer(score); - private BeatmapInfo createTestBeatmap(User author) + private BeatmapInfo createTestBeatmap([NotNull] APIUser author) { var beatmap = new TestBeatmap(rulesetStore.GetRuleset(0)).BeatmapInfo; diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs index 7a38d213d9..9a142f3ca8 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs @@ -400,7 +400,7 @@ namespace osu.Game.Tests.Visual.SongSelect loadBeatmaps(); AddStep("Sort by author", () => carousel.Filter(new FilterCriteria { Sort = SortMode.Author }, false)); - AddAssert("Check zzzzz is at bottom", () => carousel.BeatmapSets.Last().Metadata.AuthorString == "zzzzz"); + AddAssert("Check zzzzz is at bottom", () => carousel.BeatmapSets.Last().Metadata.Author.Username == "zzzzz"); AddStep("Sort by artist", () => carousel.Filter(new FilterCriteria { Sort = SortMode.Artist }, false)); AddAssert($"Check #{set_count} is at bottom", () => carousel.BeatmapSets.Last().Metadata.Title.EndsWith($"#{set_count}!", StringComparison.Ordinal)); } diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs index 13b769c80a..855a59b5f5 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs @@ -10,6 +10,7 @@ using osu.Framework.Graphics; using osu.Framework.Platform; using osu.Framework.Testing; using osu.Game.Beatmaps; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Leaderboards; using osu.Game.Overlays; using osu.Game.Rulesets; @@ -133,7 +134,7 @@ namespace osu.Game.Tests.Visual.SongSelect MaxCombo = 244, TotalScore = 1707827, Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock() }, - User = new User + User = new APIUser { Id = 6602580, Username = @"waaiiru", @@ -156,7 +157,7 @@ namespace osu.Game.Tests.Visual.SongSelect MaxCombo = 244, TotalScore = 1707827, Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), }, - User = new User + User = new APIUser { Id = 6602580, Username = @"waaiiru", @@ -198,7 +199,7 @@ namespace osu.Game.Tests.Visual.SongSelect TotalScore = 1707827, //Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), }, BeatmapInfo = beatmapInfo, - User = new User + User = new APIUser { Id = 6602580, Username = @"waaiiru", @@ -217,7 +218,7 @@ namespace osu.Game.Tests.Visual.SongSelect TotalScore = 1707827, //Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), }, BeatmapInfo = beatmapInfo, - User = new User + User = new APIUser { Id = 4608074, Username = @"Skycries", @@ -236,7 +237,7 @@ namespace osu.Game.Tests.Visual.SongSelect TotalScore = 1707827, //Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), }, BeatmapInfo = beatmapInfo, - User = new User + User = new APIUser { Id = 1014222, Username = @"eLy", @@ -255,7 +256,7 @@ namespace osu.Game.Tests.Visual.SongSelect TotalScore = 1707827, //Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), }, BeatmapInfo = beatmapInfo, - User = new User + User = new APIUser { Id = 1541390, Username = @"Toukai", @@ -274,7 +275,7 @@ namespace osu.Game.Tests.Visual.SongSelect TotalScore = 1707827, //Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), }, BeatmapInfo = beatmapInfo, - User = new User + User = new APIUser { Id = 2243452, Username = @"Satoruu", @@ -293,7 +294,7 @@ namespace osu.Game.Tests.Visual.SongSelect TotalScore = 1707827, //Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), }, BeatmapInfo = beatmapInfo, - User = new User + User = new APIUser { Id = 2705430, Username = @"Mooha", @@ -312,7 +313,7 @@ namespace osu.Game.Tests.Visual.SongSelect TotalScore = 1707827, //Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), }, BeatmapInfo = beatmapInfo, - User = new User + User = new APIUser { Id = 7151382, Username = @"Mayuri Hana", @@ -331,7 +332,7 @@ namespace osu.Game.Tests.Visual.SongSelect TotalScore = 1707827, //Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), }, BeatmapInfo = beatmapInfo, - User = new User + User = new APIUser { Id = 2051389, Username = @"FunOrange", @@ -350,7 +351,7 @@ namespace osu.Game.Tests.Visual.SongSelect TotalScore = 1707827, //Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), }, BeatmapInfo = beatmapInfo, - User = new User + User = new APIUser { Id = 6169483, Username = @"-Hebel-", @@ -369,7 +370,7 @@ namespace osu.Game.Tests.Visual.SongSelect TotalScore = 1707827, //Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), }, BeatmapInfo = beatmapInfo, - User = new User + User = new APIUser { Id = 6702666, Username = @"prhtnsm", diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs index c22b6a54e9..68d5836cac 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs @@ -9,6 +9,7 @@ using osu.Framework.Testing; using osu.Game.Beatmaps; using osu.Game.Online.API; using osu.Game.Online.API.Requests; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Rulesets; using osu.Game.Rulesets.Catch; using osu.Game.Rulesets.Mania; @@ -40,9 +41,9 @@ namespace osu.Game.Tests.Visual.SongSelect base.SetUpSteps(); - User getUser(int? rulesetID) + APIUser getUser(int? rulesetID) { - return new User + return new APIUser { Username = @"Dummy", Id = 1001, diff --git a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs index 4811fc979e..4861354921 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs @@ -18,6 +18,7 @@ using osu.Framework.Testing; using osu.Game.Beatmaps; using osu.Game.Configuration; using osu.Game.Graphics.UserInterface; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; @@ -29,7 +30,6 @@ using osu.Game.Screens.Play; using osu.Game.Screens.Select; using osu.Game.Screens.Select.Carousel; using osu.Game.Screens.Select.Filter; -using osu.Game.Users; using osuTK.Input; namespace osu.Game.Tests.Visual.SongSelect @@ -807,7 +807,7 @@ namespace osu.Game.Tests.Visual.SongSelect songSelect.PresentScore(new ScoreInfo { - User = new User { Username = "woo" }, + User = new APIUser { Username = "woo" }, BeatmapInfo = getPresentBeatmap(), Ruleset = getPresentBeatmap().Ruleset }); @@ -839,7 +839,7 @@ namespace osu.Game.Tests.Visual.SongSelect songSelect.PresentScore(new ScoreInfo { - User = new User { Username = "woo" }, + User = new APIUser { Username = "woo" }, BeatmapInfo = getPresentBeatmap(), Ruleset = getPresentBeatmap().Ruleset }); diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneUserTopScoreContainer.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneUserTopScoreContainer.cs index b8b8792b9b..7af9e9eb40 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneUserTopScoreContainer.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneUserTopScoreContainer.cs @@ -5,6 +5,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; +using osu.Game.Online.API.Requests.Responses; using osuTK.Graphics; using osu.Game.Online.Leaderboards; using osu.Game.Overlays; @@ -60,7 +61,7 @@ namespace osu.Game.Tests.Visual.SongSelect MaxCombo = 244, TotalScore = 1707827, Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), }, - User = new User + User = new APIUser { Id = 6602580, Username = @"waaiiru", @@ -78,7 +79,7 @@ namespace osu.Game.Tests.Visual.SongSelect Accuracy = 1, MaxCombo = 244, TotalScore = 1707827, - User = new User + User = new APIUser { Id = 4608074, Username = @"Skycries", @@ -96,7 +97,7 @@ namespace osu.Game.Tests.Visual.SongSelect Accuracy = 1, MaxCombo = 244, TotalScore = 1707827, - User = new User + User = new APIUser { Id = 1541390, Username = @"Toukai", diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneDashboardBeatmapListing.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneDashboardBeatmapListing.cs index 06c64a566e..17ac812eb0 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneDashboardBeatmapListing.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneDashboardBeatmapListing.cs @@ -7,11 +7,11 @@ using osu.Game.Overlays.Dashboard.Home; using osu.Game.Beatmaps; using osu.Game.Overlays; using osu.Framework.Allocation; -using osu.Game.Users; using System; using osu.Framework.Graphics.Shapes; using System.Collections.Generic; using osu.Game.Online.API.Requests.Responses; +using APIUser = osu.Game.Online.API.Requests.Responses.APIUser; namespace osu.Game.Tests.Visual.UserInterface { @@ -62,7 +62,7 @@ namespace osu.Game.Tests.Visual.UserInterface { Title = "Very Long Title (TV size) [TATOE]", Artist = "This artist has a really long name how is this possible", - Author = new User + Author = new APIUser { Username = "author", Id = 100 @@ -77,7 +77,7 @@ namespace osu.Game.Tests.Visual.UserInterface { Title = "Very Long Title (TV size) [TATOE]", Artist = "This artist has a really long name how is this possible", - Author = new User + Author = new APIUser { Username = "author", Id = 100 @@ -96,7 +96,7 @@ namespace osu.Game.Tests.Visual.UserInterface { Title = "Very Long Title (TV size) [TATOE]", Artist = "This artist has a really long name how is this possible", - Author = new User + Author = new APIUser { Username = "author", Id = 100 @@ -111,7 +111,7 @@ namespace osu.Game.Tests.Visual.UserInterface { Title = "Very Long Title (TV size) [TATOE]", Artist = "This artist has a really long name how is this possible", - Author = new User + Author = new APIUser { Username = "author", Id = 100 diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs index 9a75d3c309..07759d598e 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs @@ -15,13 +15,13 @@ using osu.Game.Beatmaps; using osu.Game.Database; using osu.Game.Graphics.Cursor; using osu.Game.Graphics.UserInterface; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Leaderboards; using osu.Game.Overlays; using osu.Game.Rulesets; using osu.Game.Scoring; using osu.Game.Screens.Select.Leaderboards; using osu.Game.Tests.Resources; -using osu.Game.Users; using osuTK; using osuTK.Input; @@ -64,7 +64,7 @@ namespace osu.Game.Tests.Visual.UserInterface ID = 1, Title = "TestSong", Artist = "TestArtist", - Author = new User + Author = new APIUser { Username = "TestAuthor" }, @@ -98,7 +98,7 @@ namespace osu.Game.Tests.Visual.UserInterface TotalScore = RNG.Next(1, 1000000), MaxCombo = RNG.Next(1, 1000), Rank = ScoreRank.XH, - User = new User { Username = "TestUser" }, + User = new APIUser { Username = "TestUser" }, }; importedScores.Add(scoreManager.Import(score).Result.Value); diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneFriendsOnlineStatusControl.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneFriendsOnlineStatusControl.cs index 9fa5c83dba..ea3cfbd497 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneFriendsOnlineStatusControl.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneFriendsOnlineStatusControl.cs @@ -6,9 +6,9 @@ using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays; using osu.Game.Overlays.Dashboard.Friends; -using osu.Game.Users; namespace osu.Game.Tests.Visual.UserInterface { @@ -29,17 +29,17 @@ namespace osu.Game.Tests.Visual.UserInterface [Test] public void Populate() { - AddStep("Populate", () => control.Populate(new List + AddStep("Populate", () => control.Populate(new List { - new User + new APIUser { IsOnline = true }, - new User + new APIUser { IsOnline = false }, - new User + new APIUser { IsOnline = false } diff --git a/osu.Game.Tournament.Tests/Components/TestSceneDrawableTournamentTeam.cs b/osu.Game.Tournament.Tests/Components/TestSceneDrawableTournamentTeam.cs index 376c59ec2d..bb47683be1 100644 --- a/osu.Game.Tournament.Tests/Components/TestSceneDrawableTournamentTeam.cs +++ b/osu.Game.Tournament.Tests/Components/TestSceneDrawableTournamentTeam.cs @@ -3,13 +3,13 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Tests.Visual; using osu.Game.Tournament.Components; using osu.Game.Tournament.Models; using osu.Game.Tournament.Screens.Drawings.Components; using osu.Game.Tournament.Screens.Gameplay.Components; using osu.Game.Tournament.Screens.Ladder.Components; -using osu.Game.Users; namespace osu.Game.Tournament.Tests.Components { @@ -24,13 +24,13 @@ namespace osu.Game.Tournament.Tests.Components FullName = { Value = "Australia" }, Players = { - new User { Username = "ASecretBox" }, - new User { Username = "Dereban" }, - new User { Username = "mReKk" }, - new User { Username = "uyghti" }, - new User { Username = "Parkes" }, - new User { Username = "Shiroha" }, - new User { Username = "Jordan The Bear" }, + new APIUser { Username = "ASecretBox" }, + new APIUser { Username = "Dereban" }, + new APIUser { Username = "mReKk" }, + new APIUser { Username = "uyghti" }, + new APIUser { Username = "Parkes" }, + new APIUser { Username = "Shiroha" }, + new APIUser { Username = "Jordan The Bear" }, } }; diff --git a/osu.Game.Tournament.Tests/Components/TestSceneTournamentMatchChatDisplay.cs b/osu.Game.Tournament.Tests/Components/TestSceneTournamentMatchChatDisplay.cs index 9905e17824..05989566c3 100644 --- a/osu.Game.Tournament.Tests/Components/TestSceneTournamentMatchChatDisplay.cs +++ b/osu.Game.Tournament.Tests/Components/TestSceneTournamentMatchChatDisplay.cs @@ -4,12 +4,12 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Chat; using osu.Game.Tests.Visual; using osu.Game.Tournament.Components; using osu.Game.Tournament.IPC; using osu.Game.Tournament.Models; -using osu.Game.Users; namespace osu.Game.Tournament.Tests.Components { @@ -18,20 +18,20 @@ namespace osu.Game.Tournament.Tests.Components private readonly Channel testChannel = new Channel(); private readonly Channel testChannel2 = new Channel(); - private readonly User admin = new User + private readonly APIUser admin = new APIUser { Username = "HappyStick", Id = 2, Colour = "f2ca34" }; - private readonly User redUser = new User + private readonly APIUser redUser = new APIUser { Username = "BanchoBot", Id = 3, }; - private readonly User blueUser = new User + private readonly APIUser blueUser = new APIUser { Username = "Zallius", Id = 4, @@ -57,11 +57,11 @@ namespace osu.Game.Tournament.Tests.Components { Team1 = { - Value = new TournamentTeam { Players = new BindableList { redUser } } + Value = new TournamentTeam { Players = new BindableList { redUser } } }, Team2 = { - Value = new TournamentTeam { Players = new BindableList { blueUser } } + Value = new TournamentTeam { Players = new BindableList { blueUser } } } }; diff --git a/osu.Game.Tournament.Tests/TournamentTestScene.cs b/osu.Game.Tournament.Tests/TournamentTestScene.cs index 81741a43a9..8c05b4e915 100644 --- a/osu.Game.Tournament.Tests/TournamentTestScene.cs +++ b/osu.Game.Tournament.Tests/TournamentTestScene.cs @@ -14,6 +14,7 @@ using osu.Game.Tournament.IO; using osu.Game.Tournament.IPC; using osu.Game.Tournament.Models; using osu.Game.Users; +using APIUser = osu.Game.Online.API.Requests.Responses.APIUser; namespace osu.Game.Tournament.Tests { @@ -120,11 +121,11 @@ namespace osu.Game.Tournament.Tests }, Players = { - new User { Username = "Hello", Statistics = new UserStatistics { GlobalRank = 12 } }, - new User { Username = "Hello", Statistics = new UserStatistics { GlobalRank = 16 } }, - new User { Username = "Hello", Statistics = new UserStatistics { GlobalRank = 20 } }, - new User { Username = "Hello", Statistics = new UserStatistics { GlobalRank = 24 } }, - new User { Username = "Hello", Statistics = new UserStatistics { GlobalRank = 30 } }, + new APIUser { Username = "Hello", Statistics = new UserStatistics { GlobalRank = 12 } }, + new APIUser { Username = "Hello", Statistics = new UserStatistics { GlobalRank = 16 } }, + new APIUser { Username = "Hello", Statistics = new UserStatistics { GlobalRank = 20 } }, + new APIUser { Username = "Hello", Statistics = new UserStatistics { GlobalRank = 24 } }, + new APIUser { Username = "Hello", Statistics = new UserStatistics { GlobalRank = 30 } }, } } }, @@ -137,11 +138,11 @@ namespace osu.Game.Tournament.Tests FullName = { Value = "United States" }, Players = { - new User { Username = "Hello" }, - new User { Username = "Hello" }, - new User { Username = "Hello" }, - new User { Username = "Hello" }, - new User { Username = "Hello" }, + new APIUser { Username = "Hello" }, + new APIUser { Username = "Hello" }, + new APIUser { Username = "Hello" }, + new APIUser { Username = "Hello" }, + new APIUser { Username = "Hello" }, } } }, diff --git a/osu.Game.Tournament/Components/DrawableTeamWithPlayers.cs b/osu.Game.Tournament/Components/DrawableTeamWithPlayers.cs index e949bf9881..4d9afc23ac 100644 --- a/osu.Game.Tournament/Components/DrawableTeamWithPlayers.cs +++ b/osu.Game.Tournament/Components/DrawableTeamWithPlayers.cs @@ -5,8 +5,8 @@ using System.Linq; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Graphics; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Tournament.Models; -using osu.Game.Users; using osuTK; using osuTK.Graphics; @@ -54,7 +54,7 @@ namespace osu.Game.Tournament.Components }, }; - TournamentSpriteText createPlayerText(User p) => + TournamentSpriteText createPlayerText(APIUser p) => new TournamentSpriteText { Text = p.Username, diff --git a/osu.Game.Tournament/Components/TournamentBeatmapPanel.cs b/osu.Game.Tournament/Components/TournamentBeatmapPanel.cs index f3550f7465..364cccd076 100644 --- a/osu.Game.Tournament/Components/TournamentBeatmapPanel.cs +++ b/osu.Game.Tournament/Components/TournamentBeatmapPanel.cs @@ -93,7 +93,7 @@ namespace osu.Game.Tournament.Components }, new TournamentSpriteText { - Text = Beatmap.Metadata.Author, + Text = Beatmap.Metadata.Author.Username, Padding = new MarginPadding { Right = 20 }, Font = OsuFont.Torus.With(weight: FontWeight.Bold, size: 14) }, diff --git a/osu.Game.Tournament/Models/TournamentTeam.cs b/osu.Game.Tournament/Models/TournamentTeam.cs index d895e4b538..24dee3b372 100644 --- a/osu.Game.Tournament/Models/TournamentTeam.cs +++ b/osu.Game.Tournament/Models/TournamentTeam.cs @@ -5,7 +5,7 @@ using System; using System.Linq; using Newtonsoft.Json; using osu.Framework.Bindables; -using osu.Game.Users; +using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Tournament.Models { @@ -57,7 +57,7 @@ namespace osu.Game.Tournament.Models }; [JsonProperty] - public BindableList Players { get; set; } = new BindableList(); + public BindableList Players { get; set; } = new BindableList(); public TournamentTeam() { diff --git a/osu.Game.Tournament/Screens/Editors/TeamEditorScreen.cs b/osu.Game.Tournament/Screens/Editors/TeamEditorScreen.cs index 0d2e64f300..6adddb5204 100644 --- a/osu.Game.Tournament/Screens/Editors/TeamEditorScreen.cs +++ b/osu.Game.Tournament/Screens/Editors/TeamEditorScreen.cs @@ -13,6 +13,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; using osu.Game.Online.API; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays.Settings; using osu.Game.Tournament.Components; using osu.Game.Tournament.Models; @@ -199,14 +200,14 @@ namespace osu.Game.Tournament.Screens.Editors public void CreateNew() { - var user = new User(); + var user = new APIUser(); team.Players.Add(user); flow.Add(new PlayerRow(team, user)); } public class PlayerRow : CompositeDrawable { - private readonly User user; + private readonly APIUser user; [Resolved] protected IAPIProvider API { get; private set; } @@ -218,7 +219,7 @@ namespace osu.Game.Tournament.Screens.Editors private readonly Container drawableContainer; - public PlayerRow(TournamentTeam team, User user) + public PlayerRow(TournamentTeam team, APIUser user) { this.user = user; diff --git a/osu.Game.Tournament/TournamentGameBase.cs b/osu.Game.Tournament/TournamentGameBase.cs index ee281466a2..d2f146c4c2 100644 --- a/osu.Game.Tournament/TournamentGameBase.cs +++ b/osu.Game.Tournament/TournamentGameBase.cs @@ -18,8 +18,8 @@ using osu.Game.Online.API.Requests.Responses; using osu.Game.Tournament.IO; using osu.Game.Tournament.IPC; using osu.Game.Tournament.Models; -using osu.Game.Users; using osuTK.Input; +using APIUser = osu.Game.Online.API.Requests.Responses.APIUser; namespace osu.Game.Tournament { @@ -241,7 +241,7 @@ namespace osu.Game.Tournament private void updateLoadProgressMessage(string s) => Schedule(() => initialisationText.Text = s); - public void PopulateUser(User user, Action success = null, Action failure = null, bool immediate = false) + public void PopulateUser(APIUser user, Action success = null, Action failure = null, bool immediate = false) { var req = new GetUserRequest(user.Id, Ruleset.Value); diff --git a/osu.Game/Audio/PreviewTrackManager.cs b/osu.Game/Audio/PreviewTrackManager.cs index ca63add31d..fd9d5a97c6 100644 --- a/osu.Game/Audio/PreviewTrackManager.cs +++ b/osu.Game/Audio/PreviewTrackManager.cs @@ -1,13 +1,8 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System; -using System.Collections.Generic; -using System.IO; -using System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Audio; -using osu.Framework.Audio.Mixing; using osu.Framework.Audio.Track; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -19,27 +14,26 @@ namespace osu.Game.Audio { public class PreviewTrackManager : Component { + private readonly IAdjustableAudioComponent mainTrackAdjustments; + private readonly BindableDouble muteBindable = new BindableDouble(); [Resolved] private AudioManager audio { get; set; } - private PreviewTrackStore trackStore; + private ITrackStore trackStore; protected TrackManagerPreviewTrack CurrentTrack; - private readonly BindableNumber globalTrackVolumeAdjust = new BindableNumber(OsuGameBase.GLOBAL_TRACK_VOLUME_ADJUST); + public PreviewTrackManager(IAdjustableAudioComponent mainTrackAdjustments) + { + this.mainTrackAdjustments = mainTrackAdjustments; + } [BackgroundDependencyLoader] private void load(AudioManager audioManager) { - // this is a temporary solution to get around muting ourselves. - // todo: update this once we have a BackgroundTrackManager or similar. - trackStore = new PreviewTrackStore(audioManager.TrackMixer, new OnlineStore()); - - audio.AddItem(trackStore); - trackStore.AddAdjustment(AdjustableProperty.Volume, globalTrackVolumeAdjust); - trackStore.AddAdjustment(AdjustableProperty.Volume, audio.VolumeTrack); + trackStore = audioManager.GetTrackStore(new OnlineStore()); } /// @@ -55,7 +49,7 @@ namespace osu.Game.Audio { CurrentTrack?.Stop(); CurrentTrack = track; - audio.Tracks.AddAdjustment(AdjustableProperty.Volume, muteBindable); + mainTrackAdjustments.AddAdjustment(AdjustableProperty.Volume, muteBindable); }); track.Stopped += () => Schedule(() => @@ -64,7 +58,7 @@ namespace osu.Game.Audio return; CurrentTrack = null; - audio.Tracks.RemoveAdjustment(AdjustableProperty.Volume, muteBindable); + mainTrackAdjustments.RemoveAdjustment(AdjustableProperty.Volume, muteBindable); }); return track; @@ -116,52 +110,5 @@ namespace osu.Game.Audio protected override Track GetTrack() => trackManager.Get($"https://b.ppy.sh/preview/{beatmapSetInfo.OnlineID}.mp3"); } - - private class PreviewTrackStore : AudioCollectionManager, ITrackStore - { - private readonly AudioMixer defaultMixer; - private readonly IResourceStore store; - - internal PreviewTrackStore(AudioMixer defaultMixer, IResourceStore store) - { - this.defaultMixer = defaultMixer; - this.store = store; - } - - public Track GetVirtual(double length = double.PositiveInfinity) - { - if (IsDisposed) throw new ObjectDisposedException($"Cannot retrieve items for an already disposed {nameof(PreviewTrackStore)}"); - - var track = new TrackVirtual(length); - AddItem(track); - return track; - } - - public Track Get(string name) - { - if (IsDisposed) throw new ObjectDisposedException($"Cannot retrieve items for an already disposed {nameof(PreviewTrackStore)}"); - - if (string.IsNullOrEmpty(name)) return null; - - var dataStream = store.GetStream(name); - - if (dataStream == null) - return null; - - // Todo: This is quite unsafe. TrackBass shouldn't be exposed as public. - Track track = new TrackBass(dataStream); - - defaultMixer.Add(track); - AddItem(track); - - return track; - } - - public Task GetAsync(string name) => Task.Run(() => Get(name)); - - public Stream GetStream(string name) => store.GetStream(name); - - public IEnumerable GetAvailableResources() => store.GetAvailableResources(); - } } } diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index e0e5b5e63d..48a6663adb 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -10,7 +10,8 @@ using System.Threading; using System.Threading.Tasks; using JetBrains.Annotations; using osu.Framework.Audio; -using osu.Framework.Bindables; +using osu.Framework.Audio.Mixing; +using osu.Framework.Audio.Track; using osu.Framework.IO.Stores; using osu.Framework.Platform; using osu.Framework.Testing; @@ -18,10 +19,10 @@ using osu.Game.Database; using osu.Game.IO; using osu.Game.IO.Archives; using osu.Game.Online.API; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays.Notifications; using osu.Game.Rulesets; using osu.Game.Skinning; -using osu.Game.Users; namespace osu.Game.Beatmaps { @@ -31,18 +32,23 @@ namespace osu.Game.Beatmaps [ExcludeFromDynamicCompile] public class BeatmapManager : IModelDownloader, IModelManager, IModelFileManager, IModelImporter, IWorkingBeatmapCache, IDisposable { + public ITrackStore BeatmapTrackStore { get; } + private readonly BeatmapModelManager beatmapModelManager; private readonly BeatmapModelDownloader beatmapModelDownloader; private readonly WorkingBeatmapCache workingBeatmapCache; private readonly BeatmapOnlineLookupQueue onlineBeatmapLookupQueue; - public BeatmapManager(Storage storage, IDatabaseContextFactory contextFactory, RulesetStore rulesets, IAPIProvider api, [NotNull] AudioManager audioManager, IResourceStore resources, GameHost host = null, - WorkingBeatmap defaultBeatmap = null, bool performOnlineLookups = false) + public BeatmapManager(Storage storage, IDatabaseContextFactory contextFactory, RulesetStore rulesets, IAPIProvider api, [NotNull] AudioManager audioManager, IResourceStore gameResources, GameHost host = null, WorkingBeatmap defaultBeatmap = null, bool performOnlineLookups = false, AudioMixer mainTrackMixer = null) { + var userResources = new FileStore(contextFactory, storage).Store; + + BeatmapTrackStore = audioManager.GetTrackStore(userResources); + beatmapModelManager = CreateBeatmapModelManager(storage, contextFactory, rulesets, api, host); beatmapModelDownloader = CreateBeatmapModelDownloader(beatmapModelManager, api, host); - workingBeatmapCache = CreateWorkingBeatmapCache(audioManager, resources, new FileStore(contextFactory, storage).Store, defaultBeatmap, host); + workingBeatmapCache = CreateWorkingBeatmapCache(audioManager, gameResources, userResources, defaultBeatmap, host); workingBeatmapCache.BeatmapManager = beatmapModelManager; beatmapModelManager.WorkingBeatmapCache = workingBeatmapCache; @@ -59,8 +65,10 @@ namespace osu.Game.Beatmaps return new BeatmapModelDownloader(modelManager, api, host); } - protected virtual WorkingBeatmapCache CreateWorkingBeatmapCache(AudioManager audioManager, IResourceStore resources, IResourceStore storage, WorkingBeatmap defaultBeatmap, GameHost host) => - new WorkingBeatmapCache(audioManager, resources, storage, defaultBeatmap, host); + protected virtual WorkingBeatmapCache CreateWorkingBeatmapCache(AudioManager audioManager, IResourceStore resources, IResourceStore storage, WorkingBeatmap defaultBeatmap, GameHost host) + { + return new WorkingBeatmapCache(BeatmapTrackStore, audioManager, resources, storage, defaultBeatmap, host); + } protected virtual BeatmapModelManager CreateBeatmapModelManager(Storage storage, IDatabaseContextFactory contextFactory, RulesetStore rulesets, IAPIProvider api, GameHost host) => new BeatmapModelManager(storage, contextFactory, rulesets, host); @@ -68,7 +76,7 @@ namespace osu.Game.Beatmaps /// /// Create a new . /// - public WorkingBeatmap CreateNew(RulesetInfo ruleset, User user) + public WorkingBeatmap CreateNew(RulesetInfo ruleset, APIUser user) { var metadata = new BeatmapMetadata { @@ -101,12 +109,20 @@ namespace osu.Game.Beatmaps /// /// Fired when a single difficulty has been hidden. /// - public IBindable> BeatmapHidden => beatmapModelManager.BeatmapHidden; + public event Action BeatmapHidden + { + add => beatmapModelManager.BeatmapHidden += value; + remove => beatmapModelManager.BeatmapHidden -= value; + } /// /// Fired when a single difficulty has been restored. /// - public IBindable> BeatmapRestored => beatmapModelManager.BeatmapRestored; + public event Action BeatmapRestored + { + add => beatmapModelManager.BeatmapRestored += value; + remove => beatmapModelManager.BeatmapRestored -= value; + } /// /// Saves an file against a given . @@ -198,9 +214,17 @@ namespace osu.Game.Beatmaps return beatmapModelManager.IsAvailableLocally(model); } - public IBindable> ItemUpdated => beatmapModelManager.ItemUpdated; + public event Action ItemUpdated + { + add => beatmapModelManager.ItemUpdated += value; + remove => beatmapModelManager.ItemUpdated -= value; + } - public IBindable> ItemRemoved => beatmapModelManager.ItemRemoved; + public event Action ItemRemoved + { + add => beatmapModelManager.ItemRemoved += value; + remove => beatmapModelManager.ItemRemoved -= value; + } public Task ImportFromStableAsync(StableStorage stableStorage) { @@ -246,20 +270,24 @@ namespace osu.Game.Beatmaps #region Implementation of IModelDownloader - public IBindable>> DownloadBegan => beatmapModelDownloader.DownloadBegan; - - public IBindable>> DownloadFailed => beatmapModelDownloader.DownloadFailed; - - public bool Download(IBeatmapSetInfo model, bool minimiseDownloadSize = false) + public event Action> DownloadBegan { - return beatmapModelDownloader.Download(model, minimiseDownloadSize); + add => beatmapModelDownloader.DownloadBegan += value; + remove => beatmapModelDownloader.DownloadBegan -= value; } - public ArchiveDownloadRequest GetExistingDownload(IBeatmapSetInfo model) + public event Action> DownloadFailed { - return beatmapModelDownloader.GetExistingDownload(model); + add => beatmapModelDownloader.DownloadFailed += value; + remove => beatmapModelDownloader.DownloadFailed -= value; } + public bool Download(IBeatmapSetInfo model, bool minimiseDownloadSize = false) => + beatmapModelDownloader.Download(model, minimiseDownloadSize); + + public ArchiveDownloadRequest GetExistingDownload(IBeatmapSetInfo model) => + beatmapModelDownloader.GetExistingDownload(model); + #endregion #region Implementation of ICanAcceptFiles diff --git a/osu.Game/Beatmaps/BeatmapMetadata.cs b/osu.Game/Beatmaps/BeatmapMetadata.cs index 5d3b4007ae..b395f16c24 100644 --- a/osu.Game/Beatmaps/BeatmapMetadata.cs +++ b/osu.Game/Beatmaps/BeatmapMetadata.cs @@ -7,6 +7,7 @@ using System.ComponentModel.DataAnnotations.Schema; using Newtonsoft.Json; using osu.Framework.Testing; using osu.Game.Database; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Users; #nullable enable @@ -36,41 +37,33 @@ namespace osu.Game.Beatmaps public List BeatmapSets { get; set; } = new List(); /// - /// Helper property to deserialize a username to . + /// The author of the beatmaps in this set. + /// + [JsonIgnore] + public APIUser Author = new APIUser(); + + /// + /// Helper property to deserialize a username to . /// [JsonProperty(@"user_id")] [Column("AuthorID")] public int AuthorID { - get => Author?.Id ?? 1; - set - { - Author ??= new User(); - Author.Id = value; - } + get => Author.Id; // This should not be used, but is required to make EF work correctly. + set => Author.Id = value; } /// - /// Helper property to deserialize a username to . + /// Helper property to deserialize a username to . /// [JsonProperty(@"creator")] [Column("Author")] public string AuthorString { - get => Author?.Username ?? string.Empty; - set - { - Author ??= new User(); - Author.Username = value; - } + get => Author.Username; // This should not be used, but is required to make EF work correctly. + set => Author.Username = value; } - /// - /// The author of the beatmaps in this set. - /// - [JsonIgnore] - public User? Author; - public string Source { get; set; } = string.Empty; [JsonProperty(@"tags")] @@ -90,6 +83,6 @@ namespace osu.Game.Beatmaps public override string ToString() => this.GetDisplayTitle(); - string IBeatmapMetadataInfo.Author => AuthorString; + IUser IBeatmapMetadataInfo.Author => Author; } } diff --git a/osu.Game/Beatmaps/BeatmapMetadataInfoExtensions.cs b/osu.Game/Beatmaps/BeatmapMetadataInfoExtensions.cs index fcaad17059..27cd7f8d9a 100644 --- a/osu.Game/Beatmaps/BeatmapMetadataInfoExtensions.cs +++ b/osu.Game/Beatmaps/BeatmapMetadataInfoExtensions.cs @@ -13,7 +13,7 @@ namespace osu.Game.Beatmaps /// public static string[] GetSearchableTerms(this IBeatmapMetadataInfo metadataInfo) => new[] { - metadataInfo.Author, + metadataInfo.Author.Username, metadataInfo.Artist, metadataInfo.ArtistUnicode, metadataInfo.Title, @@ -27,7 +27,7 @@ namespace osu.Game.Beatmaps /// public static string GetDisplayTitle(this IBeatmapMetadataInfo metadataInfo) { - string author = string.IsNullOrEmpty(metadataInfo.Author) ? string.Empty : $"({metadataInfo.Author})"; + string author = string.IsNullOrEmpty(metadataInfo.Author.Username) ? string.Empty : $"({metadataInfo.Author})"; return $"{metadataInfo.Artist} - {metadataInfo.Title} {author}".Trim(); } @@ -36,7 +36,7 @@ namespace osu.Game.Beatmaps /// public static RomanisableString GetDisplayTitleRomanisable(this IBeatmapMetadataInfo metadataInfo, bool includeCreator = true) { - string author = !includeCreator || string.IsNullOrEmpty(metadataInfo.Author) ? string.Empty : $"({metadataInfo.Author})"; + string author = !includeCreator || string.IsNullOrEmpty(metadataInfo.Author.Username) ? string.Empty : $"({metadataInfo.Author})"; string artistUnicode = string.IsNullOrEmpty(metadataInfo.ArtistUnicode) ? metadataInfo.Artist : metadataInfo.ArtistUnicode; string titleUnicode = string.IsNullOrEmpty(metadataInfo.TitleUnicode) ? metadataInfo.Title : metadataInfo.TitleUnicode; diff --git a/osu.Game/Beatmaps/BeatmapModelManager.cs b/osu.Game/Beatmaps/BeatmapModelManager.cs index f148d05aca..a654b05edb 100644 --- a/osu.Game/Beatmaps/BeatmapModelManager.cs +++ b/osu.Game/Beatmaps/BeatmapModelManager.cs @@ -11,7 +11,6 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; using osu.Framework.Audio.Track; -using osu.Framework.Bindables; using osu.Framework.Extensions; using osu.Framework.Graphics.Textures; using osu.Framework.Logging; @@ -37,14 +36,12 @@ namespace osu.Game.Beatmaps /// /// Fired when a single difficulty has been hidden. /// - public IBindable> BeatmapHidden => beatmapHidden; - - private readonly Bindable> beatmapHidden = new Bindable>(); + public event Action BeatmapHidden; /// /// Fired when a single difficulty has been restored. /// - public IBindable> BeatmapRestored => beatmapRestored; + public event Action BeatmapRestored; /// /// An online lookup queue component which handles populating online beatmap metadata. @@ -56,8 +53,6 @@ namespace osu.Game.Beatmaps /// public IWorkingBeatmapCache WorkingBeatmapCache { private get; set; } - private readonly Bindable> beatmapRestored = new Bindable>(); - public override IEnumerable HandledExtensions => new[] { ".osz" }; protected override string[] HashableFileTypes => new[] { ".osu" }; @@ -75,8 +70,8 @@ namespace osu.Game.Beatmaps this.rulesets = rulesets; beatmaps = (BeatmapStore)ModelStore; - beatmaps.BeatmapHidden += b => beatmapHidden.Value = new WeakReference(b); - beatmaps.BeatmapRestored += b => beatmapRestored.Value = new WeakReference(b); + beatmaps.BeatmapHidden += b => BeatmapHidden?.Invoke(b); + beatmaps.BeatmapRestored += b => BeatmapRestored?.Invoke(b); beatmaps.ItemRemoved += b => WorkingBeatmapCache?.Invalidate(b); beatmaps.ItemUpdated += obj => WorkingBeatmapCache?.Invalidate(obj); } @@ -194,7 +189,11 @@ namespace osu.Game.Beatmaps // Difficulty settings must be copied first due to the clone in `Beatmap<>.BeatmapInfo_Set`. // This should hopefully be temporary, assuming said clone is eventually removed. - beatmapInfo.BaseDifficulty.CopyFrom(beatmapContent.Difficulty); + + // Warning: The directionality here is important. Changes have to be copied *from* beatmapContent (which comes from editor and is being saved) + // *to* the beatmapInfo (which is a database model and needs to receive values without the taiko slider velocity multiplier for correct operation). + // CopyTo() will undo such adjustments, while CopyFrom() will not. + beatmapContent.Difficulty.CopyTo(beatmapInfo.BaseDifficulty); // All changes to metadata are made in the provided beatmapInfo, so this should be copied to the `IBeatmap` before encoding. beatmapContent.BeatmapInfo = beatmapInfo; diff --git a/osu.Game/Beatmaps/BeatmapSetHypeStatus.cs b/osu.Game/Beatmaps/BeatmapSetHypeStatus.cs new file mode 100644 index 0000000000..8a576e396a --- /dev/null +++ b/osu.Game/Beatmaps/BeatmapSetHypeStatus.cs @@ -0,0 +1,25 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using Newtonsoft.Json; + +namespace osu.Game.Beatmaps +{ + /// + /// Contains information about the current hype status of a beatmap set. + /// + public class BeatmapSetHypeStatus + { + /// + /// The current number of hypes that the set has received. + /// + [JsonProperty(@"current")] + public int Current { get; set; } + + /// + /// The number of hypes required so that the set is eligible for nomination. + /// + [JsonProperty(@"required")] + public int Required { get; set; } + } +} diff --git a/osu.Game/Beatmaps/BeatmapSetNominationStatus.cs b/osu.Game/Beatmaps/BeatmapSetNominationStatus.cs new file mode 100644 index 0000000000..6a19616a97 --- /dev/null +++ b/osu.Game/Beatmaps/BeatmapSetNominationStatus.cs @@ -0,0 +1,25 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using Newtonsoft.Json; + +namespace osu.Game.Beatmaps +{ + /// + /// Contains information about the current nomination status of a beatmap set. + /// + public class BeatmapSetNominationStatus + { + /// + /// The current number of nominations that the set has received. + /// + [JsonProperty(@"current")] + public int Current { get; set; } + + /// + /// The number of nominations required so that the map is eligible for qualification. + /// + [JsonProperty(@"required")] + public int Required { get; set; } + } +} diff --git a/osu.Game/Beatmaps/Drawables/Cards/BeatmapCard.cs b/osu.Game/Beatmaps/Drawables/Cards/BeatmapCard.cs index 8136ebbd70..71376c28f1 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/BeatmapCard.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/BeatmapCard.cs @@ -1,13 +1,17 @@ // 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 osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Events; using osu.Framework.Localisation; +using osu.Game.Beatmaps.Drawables.Cards.Buttons; +using osu.Game.Beatmaps.Drawables.Cards.Statistics; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; @@ -19,6 +23,7 @@ using osuTK; using osu.Game.Overlays.BeatmapListing.Panels; using osu.Game.Resources.Localisation.Web; using osuTK.Graphics; +using DownloadButton = osu.Game.Beatmaps.Drawables.Cards.Buttons.DownloadButton; namespace osu.Game.Beatmaps.Drawables.Cards { @@ -31,15 +36,19 @@ namespace osu.Game.Beatmaps.Drawables.Cards private const float corner_radius = 10; private readonly APIBeatmapSet beatmapSet; + private readonly Bindable favouriteState; private UpdateableOnlineBeatmapSetCover leftCover; - private FillFlowContainer iconArea; + private FillFlowContainer leftIconArea; + + private Container rightButtonArea; private Container mainContent; private BeatmapCardContentBackground mainContentBackground; private GridContainer titleContainer; private GridContainer artistContainer; + private FillFlowContainer statisticsContainer; [Resolved] private OverlayColourProvider colourProvider { get; set; } @@ -48,6 +57,7 @@ namespace osu.Game.Beatmaps.Drawables.Cards : base(HoverSampleSet.Submit) { this.beatmapSet = beatmapSet; + favouriteState = new Bindable(new BeatmapSetFavouriteState(beatmapSet.HasFavourited, beatmapSet.FavouriteCount)); } [BackgroundDependencyLoader] @@ -76,7 +86,7 @@ namespace osu.Game.Beatmaps.Drawables.Cards RelativeSizeAxes = Axes.Both, OnlineInfo = beatmapSet }, - iconArea = new FillFlowContainer + leftIconArea = new FillFlowContainer { Margin = new MarginPadding(5), AutoSizeAxes = Axes.Both, @@ -85,6 +95,27 @@ namespace osu.Game.Beatmaps.Drawables.Cards } } }, + rightButtonArea = new Container + { + Name = @"Right (button) area", + Width = 30, + RelativeSizeAxes = Axes.Y, + Origin = Anchor.TopRight, + Anchor = Anchor.TopRight, + Child = new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Direction = FillDirection.Vertical, + Spacing = new Vector2(0, 14), + Children = new BeatmapCardIconButton[] + { + new FavouriteButton(beatmapSet) { Current = favouriteState }, + new DownloadButton(beatmapSet) + } + } + }, mainContent = new Container { Name = @"Main content", @@ -176,6 +207,15 @@ namespace osu.Game.Beatmaps.Drawables.Cards d.AddText("mapped by ", t => t.Colour = colourProvider.Content2); d.AddUserLink(beatmapSet.Author); }), + statisticsContainer = new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(10, 0), + Alpha = 0, + ChildrenEnumerable = createStatistics() + } } }, new FillFlowContainer @@ -214,10 +254,10 @@ namespace osu.Game.Beatmaps.Drawables.Cards }; if (beatmapSet.HasVideo) - iconArea.Add(new IconPill(FontAwesome.Solid.Film)); + leftIconArea.Add(new IconPill(FontAwesome.Solid.Film)); if (beatmapSet.HasStoryboard) - iconArea.Add(new IconPill(FontAwesome.Solid.Image)); + leftIconArea.Add(new IconPill(FontAwesome.Solid.Image)); if (beatmapSet.HasExplicitContent) { @@ -265,6 +305,24 @@ namespace osu.Game.Beatmaps.Drawables.Cards return BeatmapsetsStrings.ShowDetailsByArtist(romanisableArtist); } + private IEnumerable createStatistics() + { + if (beatmapSet.HypeStatus != null) + yield return new HypesStatistic(beatmapSet.HypeStatus); + + // web does not show nominations unless hypes are also present. + // see: https://github.com/ppy/osu-web/blob/8ed7d071fd1d3eaa7e43cf0e4ff55ca2fef9c07c/resources/assets/lib/beatmapset-panel.tsx#L443 + if (beatmapSet.HypeStatus != null && beatmapSet.NominationStatus != null) + yield return new NominationsStatistic(beatmapSet.NominationStatus); + + yield return new FavouritesStatistic(beatmapSet) { Current = favouriteState }; + yield return new PlayCountStatistic(beatmapSet); + + var dateStatistic = BeatmapCardDateStatistic.CreateFor(beatmapSet); + if (dateStatistic != null) + yield return dateStatistic; + } + private void updateState() { float targetWidth = width - height; @@ -275,6 +333,8 @@ namespace osu.Game.Beatmaps.Drawables.Cards mainContentBackground.Dimmed.Value = IsHovered; leftCover.FadeColour(IsHovered ? OsuColour.Gray(0.2f) : Color4.White, TRANSITION_DURATION, Easing.OutQuint); + statisticsContainer.FadeTo(IsHovered ? 1 : 0, TRANSITION_DURATION, Easing.OutQuint); + rightButtonArea.FadeTo(IsHovered ? 1 : 0, TRANSITION_DURATION, Easing.OutQuint); } } } diff --git a/osu.Game/Beatmaps/Drawables/Cards/BeatmapSetFavouriteState.cs b/osu.Game/Beatmaps/Drawables/Cards/BeatmapSetFavouriteState.cs new file mode 100644 index 0000000000..82523cc865 --- /dev/null +++ b/osu.Game/Beatmaps/Drawables/Cards/BeatmapSetFavouriteState.cs @@ -0,0 +1,31 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Game.Beatmaps.Drawables.Cards.Buttons; +using osu.Game.Beatmaps.Drawables.Cards.Statistics; + +namespace osu.Game.Beatmaps.Drawables.Cards +{ + /// + /// Stores the current favourite state of a beatmap set. + /// Used to coordinate between and . + /// + public readonly struct BeatmapSetFavouriteState + { + /// + /// Whether the currently logged-in user has favourited this beatmap. + /// + public bool Favourited { get; } + + /// + /// The number of favourites that the beatmap set has received, including the currently logged-in user. + /// + public int FavouriteCount { get; } + + public BeatmapSetFavouriteState(bool favourited, int favouriteCount) + { + Favourited = favourited; + FavouriteCount = favouriteCount; + } + } +} diff --git a/osu.Game/Beatmaps/Drawables/Cards/Buttons/BeatmapCardIconButton.cs b/osu.Game/Beatmaps/Drawables/Cards/Buttons/BeatmapCardIconButton.cs new file mode 100644 index 0000000000..155259d859 --- /dev/null +++ b/osu.Game/Beatmaps/Drawables/Cards/Buttons/BeatmapCardIconButton.cs @@ -0,0 +1,46 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Sprites; +using osu.Game.Graphics.Containers; +using osu.Game.Overlays; +using osuTK; + +namespace osu.Game.Beatmaps.Drawables.Cards.Buttons +{ + public abstract class BeatmapCardIconButton : OsuHoverContainer + { + protected readonly SpriteIcon Icon; + + private float size; + + public new float Size + { + get => size; + set + { + size = value; + Icon.Size = new Vector2(size); + } + } + + protected BeatmapCardIconButton() + { + Add(Icon = new SpriteIcon()); + + AutoSizeAxes = Axes.Both; + Size = 12; + } + + [BackgroundDependencyLoader] + private void load(OverlayColourProvider colourProvider) + { + Anchor = Origin = Anchor.Centre; + + IdleColour = colourProvider.Light1; + HoverColour = colourProvider.Content1; + } + } +} diff --git a/osu.Game/Beatmaps/Drawables/Cards/Buttons/DownloadButton.cs b/osu.Game/Beatmaps/Drawables/Cards/Buttons/DownloadButton.cs new file mode 100644 index 0000000000..00c0ccc3ce --- /dev/null +++ b/osu.Game/Beatmaps/Drawables/Cards/Buttons/DownloadButton.cs @@ -0,0 +1,18 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Graphics.Sprites; +using osu.Game.Online.API.Requests.Responses; + +namespace osu.Game.Beatmaps.Drawables.Cards.Buttons +{ + public class DownloadButton : BeatmapCardIconButton + { + public DownloadButton(APIBeatmapSet beatmapSet) + { + Icon.Icon = FontAwesome.Solid.FileDownload; + } + + // TODO: implement behaviour + } +} diff --git a/osu.Game/Beatmaps/Drawables/Cards/Buttons/FavouriteButton.cs b/osu.Game/Beatmaps/Drawables/Cards/Buttons/FavouriteButton.cs new file mode 100644 index 0000000000..9fed2fde6f --- /dev/null +++ b/osu.Game/Beatmaps/Drawables/Cards/Buttons/FavouriteButton.cs @@ -0,0 +1,86 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.UserInterface; +using osu.Game.Online.API.Requests.Responses; +using osu.Framework.Logging; +using osu.Game.Online.API; +using osu.Game.Online.API.Requests; +using osu.Game.Resources.Localisation.Web; + +namespace osu.Game.Beatmaps.Drawables.Cards.Buttons +{ + public class FavouriteButton : BeatmapCardIconButton, IHasCurrentValue + { + private readonly BindableWithCurrent current; + + public Bindable Current + { + get => current.Current; + set => current.Current = value; + } + + private readonly APIBeatmapSet beatmapSet; + + private PostBeatmapFavouriteRequest favouriteRequest; + + [Resolved] + private IAPIProvider api { get; set; } + + public FavouriteButton(APIBeatmapSet beatmapSet) + { + current = new BindableWithCurrent(new BeatmapSetFavouriteState(beatmapSet.HasFavourited, beatmapSet.FavouriteCount)); + this.beatmapSet = beatmapSet; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + Action = toggleFavouriteStatus; + current.BindValueChanged(_ => updateState(), true); + } + + private void toggleFavouriteStatus() + { + var actionType = current.Value.Favourited ? BeatmapFavouriteAction.UnFavourite : BeatmapFavouriteAction.Favourite; + + favouriteRequest?.Cancel(); + favouriteRequest = new PostBeatmapFavouriteRequest(beatmapSet.OnlineID, actionType); + + Enabled.Value = false; + favouriteRequest.Success += () => + { + bool favourited = actionType == BeatmapFavouriteAction.Favourite; + + current.Value = new BeatmapSetFavouriteState(favourited, current.Value.FavouriteCount + (favourited ? 1 : -1)); + + Enabled.Value = true; + }; + favouriteRequest.Failure += e => + { + Logger.Error(e, $"Failed to {actionType.ToString().ToLower()} beatmap: {e.Message}"); + Enabled.Value = true; + }; + + api.Queue(favouriteRequest); + } + + private void updateState() + { + if (current.Value.Favourited) + { + Icon.Icon = FontAwesome.Solid.Heart; + TooltipText = BeatmapsetsStrings.ShowDetailsUnfavourite; + } + else + { + Icon.Icon = FontAwesome.Regular.Heart; + TooltipText = BeatmapsetsStrings.ShowDetailsFavourite; + } + } + } +} diff --git a/osu.Game/Beatmaps/Drawables/Cards/Statistics/BeatmapCardDateStatistic.cs b/osu.Game/Beatmaps/Drawables/Cards/Statistics/BeatmapCardDateStatistic.cs new file mode 100644 index 0000000000..8f2c4b538c --- /dev/null +++ b/osu.Game/Beatmaps/Drawables/Cards/Statistics/BeatmapCardDateStatistic.cs @@ -0,0 +1,55 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +#nullable enable + +using System; +using osu.Framework.Extensions.LocalisationExtensions; +using osu.Framework.Graphics.Cursor; +using osu.Framework.Graphics.Sprites; +using osu.Game.Graphics; + +namespace osu.Game.Beatmaps.Drawables.Cards.Statistics +{ + public class BeatmapCardDateStatistic : BeatmapCardStatistic + { + private readonly DateTimeOffset dateTime; + + private BeatmapCardDateStatistic(DateTimeOffset dateTime) + { + this.dateTime = dateTime; + + Icon = FontAwesome.Regular.CheckCircle; + Text = dateTime.ToLocalisableString(@"d MMM yyyy"); + } + + public override object TooltipContent => dateTime; + public override ITooltip GetCustomTooltip() => new DateTooltip(); + + public static BeatmapCardDateStatistic? CreateFor(IBeatmapSetOnlineInfo beatmapSetInfo) + { + var displayDate = displayDateFor(beatmapSetInfo); + + if (displayDate == null) + return null; + + return new BeatmapCardDateStatistic(displayDate.Value); + } + + private static DateTimeOffset? displayDateFor(IBeatmapSetOnlineInfo beatmapSetInfo) + { + // reference: https://github.com/ppy/osu-web/blob/ef432c11719fd1207bec5f9194b04f0033bdf02c/resources/assets/lib/beatmapset-panel.tsx#L36-L44 + switch (beatmapSetInfo.Status) + { + case BeatmapSetOnlineStatus.Ranked: + case BeatmapSetOnlineStatus.Approved: + case BeatmapSetOnlineStatus.Loved: + case BeatmapSetOnlineStatus.Qualified: + return beatmapSetInfo.Ranked; + + default: + return beatmapSetInfo.LastUpdated; + } + } + } +} diff --git a/osu.Game/Beatmaps/Drawables/Cards/Statistics/BeatmapCardStatistic.cs b/osu.Game/Beatmaps/Drawables/Cards/Statistics/BeatmapCardStatistic.cs new file mode 100644 index 0000000000..f46926284f --- /dev/null +++ b/osu.Game/Beatmaps/Drawables/Cards/Statistics/BeatmapCardStatistic.cs @@ -0,0 +1,80 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Cursor; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Localisation; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Overlays; +using osuTK; + +namespace osu.Game.Beatmaps.Drawables.Cards.Statistics +{ + /// + /// A single statistic shown on a beatmap card. + /// + public abstract class BeatmapCardStatistic : CompositeDrawable, IHasTooltip, IHasCustomTooltip + { + protected IconUsage Icon + { + get => spriteIcon.Icon; + set => spriteIcon.Icon = value; + } + + protected LocalisableString Text + { + get => spriteText.Text; + set => spriteText.Text = value; + } + + public LocalisableString TooltipText { get; protected set; } + + private readonly SpriteIcon spriteIcon; + private readonly OsuSpriteText spriteText; + + protected BeatmapCardStatistic() + { + AutoSizeAxes = Axes.Both; + + InternalChild = new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(5, 0), + Children = new Drawable[] + { + spriteIcon = new SpriteIcon + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Size = new Vector2(10), + Margin = new MarginPadding { Top = 1 } + }, + spriteText = new OsuSpriteText + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Font = OsuFont.Default.With(size: 14) + } + } + }; + } + + [BackgroundDependencyLoader] + private void load(OverlayColourProvider colourProvider) + { + spriteIcon.Colour = colourProvider.Content2; + } + + #region Tooltip implementation + + public virtual ITooltip GetCustomTooltip() => null; + public virtual object TooltipContent => null; + + #endregion + } +} diff --git a/osu.Game/Beatmaps/Drawables/Cards/Statistics/FavouritesStatistic.cs b/osu.Game/Beatmaps/Drawables/Cards/Statistics/FavouritesStatistic.cs new file mode 100644 index 0000000000..d924fd938b --- /dev/null +++ b/osu.Game/Beatmaps/Drawables/Cards/Statistics/FavouritesStatistic.cs @@ -0,0 +1,44 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using Humanizer; +using osu.Framework.Bindables; +using osu.Framework.Extensions.LocalisationExtensions; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.UserInterface; +using osu.Game.Resources.Localisation.Web; + +namespace osu.Game.Beatmaps.Drawables.Cards.Statistics +{ + /// + /// Shows the number of favourites that a beatmap set has received. + /// + public class FavouritesStatistic : BeatmapCardStatistic, IHasCurrentValue + { + private readonly BindableWithCurrent current; + + public Bindable Current + { + get => current.Current; + set => current.Current = value; + } + + public FavouritesStatistic(IBeatmapSetOnlineInfo onlineInfo) + { + current = new BindableWithCurrent(new BeatmapSetFavouriteState(onlineInfo.HasFavourited, onlineInfo.FavouriteCount)); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + current.BindValueChanged(_ => updateState(), true); + } + + private void updateState() + { + Icon = current.Value.Favourited ? FontAwesome.Solid.Heart : FontAwesome.Regular.Heart; + Text = current.Value.FavouriteCount.ToMetric(decimals: 1); + TooltipText = BeatmapsStrings.PanelFavourites(current.Value.FavouriteCount.ToLocalisableString(@"N0")); + } + } +} diff --git a/osu.Game/Beatmaps/Drawables/Cards/Statistics/HypesStatistic.cs b/osu.Game/Beatmaps/Drawables/Cards/Statistics/HypesStatistic.cs new file mode 100644 index 0000000000..3fe31c7a41 --- /dev/null +++ b/osu.Game/Beatmaps/Drawables/Cards/Statistics/HypesStatistic.cs @@ -0,0 +1,22 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Extensions.LocalisationExtensions; +using osu.Framework.Graphics.Sprites; +using osu.Game.Resources.Localisation.Web; + +namespace osu.Game.Beatmaps.Drawables.Cards.Statistics +{ + /// + /// Shows the number of current hypes that a map has received, as well as the number of hypes required for nomination. + /// + public class HypesStatistic : BeatmapCardStatistic + { + public HypesStatistic(BeatmapSetHypeStatus hypeStatus) + { + Icon = FontAwesome.Solid.Bullhorn; + Text = hypeStatus.Current.ToLocalisableString(); + TooltipText = BeatmapsStrings.HypeRequiredText(hypeStatus.Current.ToLocalisableString(), hypeStatus.Required.ToLocalisableString()); + } + } +} diff --git a/osu.Game/Beatmaps/Drawables/Cards/Statistics/NominationsStatistic.cs b/osu.Game/Beatmaps/Drawables/Cards/Statistics/NominationsStatistic.cs new file mode 100644 index 0000000000..f09269a615 --- /dev/null +++ b/osu.Game/Beatmaps/Drawables/Cards/Statistics/NominationsStatistic.cs @@ -0,0 +1,22 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Extensions.LocalisationExtensions; +using osu.Framework.Graphics.Sprites; +using osu.Game.Resources.Localisation.Web; + +namespace osu.Game.Beatmaps.Drawables.Cards.Statistics +{ + /// + /// Shows the number of current nominations that a map has received, as well as the number of nominations required for qualification. + /// + public class NominationsStatistic : BeatmapCardStatistic + { + public NominationsStatistic(BeatmapSetNominationStatus nominationStatus) + { + Icon = FontAwesome.Solid.ThumbsUp; + Text = nominationStatus.Current.ToLocalisableString(); + TooltipText = BeatmapsStrings.NominationsRequiredText(nominationStatus.Current.ToLocalisableString(), nominationStatus.Required.ToLocalisableString()); + } + } +} diff --git a/osu.Game/Beatmaps/Drawables/Cards/Statistics/PlayCountStatistic.cs b/osu.Game/Beatmaps/Drawables/Cards/Statistics/PlayCountStatistic.cs new file mode 100644 index 0000000000..d8f0c36bd9 --- /dev/null +++ b/osu.Game/Beatmaps/Drawables/Cards/Statistics/PlayCountStatistic.cs @@ -0,0 +1,23 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using Humanizer; +using osu.Framework.Extensions.LocalisationExtensions; +using osu.Framework.Graphics.Sprites; +using osu.Game.Resources.Localisation.Web; + +namespace osu.Game.Beatmaps.Drawables.Cards.Statistics +{ + /// + /// Shows the number of times the given beatmap set has been played. + /// + public class PlayCountStatistic : BeatmapCardStatistic + { + public PlayCountStatistic(IBeatmapSetOnlineInfo onlineInfo) + { + Icon = FontAwesome.Regular.PlayCircle; + Text = onlineInfo.PlayCount.ToMetric(decimals: 1); + TooltipText = BeatmapsStrings.PanelPlaycount(onlineInfo.PlayCount.ToLocalisableString(@"N0")); + } + } +} diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs index 3ed5055b7f..9117da5d32 100644 --- a/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs @@ -129,7 +129,7 @@ namespace osu.Game.Beatmaps.Formats if (!string.IsNullOrEmpty(beatmap.Metadata.TitleUnicode)) writer.WriteLine(FormattableString.Invariant($"TitleUnicode: {beatmap.Metadata.TitleUnicode}")); writer.WriteLine(FormattableString.Invariant($"Artist: {beatmap.Metadata.Artist}")); if (!string.IsNullOrEmpty(beatmap.Metadata.ArtistUnicode)) writer.WriteLine(FormattableString.Invariant($"ArtistUnicode: {beatmap.Metadata.ArtistUnicode}")); - writer.WriteLine(FormattableString.Invariant($"Creator: {beatmap.Metadata.AuthorString}")); + writer.WriteLine(FormattableString.Invariant($"Creator: {beatmap.Metadata.Author.Username}")); writer.WriteLine(FormattableString.Invariant($"Version: {beatmap.BeatmapInfo.Version}")); if (!string.IsNullOrEmpty(beatmap.Metadata.Source)) writer.WriteLine(FormattableString.Invariant($"Source: {beatmap.Metadata.Source}")); if (!string.IsNullOrEmpty(beatmap.Metadata.Tags)) writer.WriteLine(FormattableString.Invariant($"Tags: {beatmap.Metadata.Tags}")); diff --git a/osu.Game/Beatmaps/IBeatmapMetadataInfo.cs b/osu.Game/Beatmaps/IBeatmapMetadataInfo.cs index 55aee7d7bc..968ad14928 100644 --- a/osu.Game/Beatmaps/IBeatmapMetadataInfo.cs +++ b/osu.Game/Beatmaps/IBeatmapMetadataInfo.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using osu.Game.Users; #nullable enable @@ -35,7 +36,7 @@ namespace osu.Game.Beatmaps /// /// The author of this beatmap. /// - string Author { get; } // eventually should be linked to a persisted User. + IUser Author { get; } /// /// The source of this beatmap. diff --git a/osu.Game/Beatmaps/IBeatmapSetOnlineInfo.cs b/osu.Game/Beatmaps/IBeatmapSetOnlineInfo.cs index 6def6ec21d..2982cf9c3a 100644 --- a/osu.Game/Beatmaps/IBeatmapSetOnlineInfo.cs +++ b/osu.Game/Beatmaps/IBeatmapSetOnlineInfo.cs @@ -102,5 +102,19 @@ namespace osu.Game.Beatmaps /// Total vote counts of user ratings on a scale of 0..10 where 0 is unused (probably will be fixed at API?). /// int[]? Ratings { get; } + + /// + /// Contains the current hype status of the beatmap set. + /// Non-null only for , , and sets. + /// + /// + /// See: https://github.com/ppy/osu-web/blob/93930cd02cfbd49724929912597c727c9fbadcd1/app/Models/Beatmapset.php#L155 + /// + BeatmapSetHypeStatus? HypeStatus { get; } + + /// + /// Contains the current nomination status of the beatmap set. + /// + BeatmapSetNominationStatus? NominationStatus { get; } } } diff --git a/osu.Game/Beatmaps/WorkingBeatmapCache.cs b/osu.Game/Beatmaps/WorkingBeatmapCache.cs index 11257e3abc..0af28902a0 100644 --- a/osu.Game/Beatmaps/WorkingBeatmapCache.cs +++ b/osu.Game/Beatmaps/WorkingBeatmapCache.cs @@ -41,7 +41,7 @@ namespace osu.Game.Beatmaps [CanBeNull] private readonly GameHost host; - public WorkingBeatmapCache([NotNull] AudioManager audioManager, IResourceStore resources, IResourceStore files, WorkingBeatmap defaultBeatmap = null, GameHost host = null) + public WorkingBeatmapCache(ITrackStore trackStore, AudioManager audioManager, IResourceStore resources, IResourceStore files, WorkingBeatmap defaultBeatmap = null, GameHost host = null) { DefaultBeatmap = defaultBeatmap; @@ -50,7 +50,7 @@ namespace osu.Game.Beatmaps this.host = host; this.files = files; largeTextureStore = new LargeTextureStore(host?.CreateTextureLoaderStore(files)); - trackStore = audioManager.GetTrackStore(files); + this.trackStore = trackStore; } public void Invalidate(BeatmapSetInfo info) diff --git a/osu.Game/Database/ArchiveModelManager.cs b/osu.Game/Database/ArchiveModelManager.cs index d2f9ee1dc1..019749760f 100644 --- a/osu.Game/Database/ArchiveModelManager.cs +++ b/osu.Game/Database/ArchiveModelManager.cs @@ -10,7 +10,6 @@ using System.Threading.Tasks; using Humanizer; using JetBrains.Annotations; using Microsoft.EntityFrameworkCore; -using osu.Framework.Bindables; using osu.Framework.Extensions; using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Logging; @@ -63,17 +62,13 @@ namespace osu.Game.Database /// Fired when a new or updated becomes available in the database. /// This is not guaranteed to run on the update thread. /// - public IBindable> ItemUpdated => itemUpdated; - - private readonly Bindable> itemUpdated = new Bindable>(); + public event Action ItemUpdated; /// /// Fired when a is removed from the database. /// This is not guaranteed to run on the update thread. /// - public IBindable> ItemRemoved => itemRemoved; - - private readonly Bindable> itemRemoved = new Bindable>(); + public event Action ItemRemoved; public virtual IEnumerable HandledExtensions => new[] { @".zip" }; @@ -93,8 +88,8 @@ namespace osu.Game.Database ContextFactory = contextFactory; ModelStore = modelStore; - ModelStore.ItemUpdated += item => handleEvent(() => itemUpdated.Value = new WeakReference(item)); - ModelStore.ItemRemoved += item => handleEvent(() => itemRemoved.Value = new WeakReference(item)); + ModelStore.ItemUpdated += item => handleEvent(() => ItemUpdated?.Invoke(item)); + ModelStore.ItemRemoved += item => handleEvent(() => ItemRemoved?.Invoke(item)); exportStorage = storage.GetStorageForDirectory(@"exports"); diff --git a/osu.Game/Database/IModelDownloader.cs b/osu.Game/Database/IModelDownloader.cs index 3c57a277ba..81fba14244 100644 --- a/osu.Game/Database/IModelDownloader.cs +++ b/osu.Game/Database/IModelDownloader.cs @@ -3,7 +3,6 @@ using System; using osu.Game.Online.API; -using osu.Framework.Bindables; namespace osu.Game.Database { @@ -18,13 +17,13 @@ namespace osu.Game.Database /// Fired when a download begins. /// This is NOT run on the update thread and should be scheduled. /// - IBindable>> DownloadBegan { get; } + event Action> DownloadBegan; /// /// Fired when a download is interrupted, either due to user cancellation or failure. /// This is NOT run on the update thread and should be scheduled. /// - IBindable>> DownloadFailed { get; } + event Action> DownloadFailed; /// /// Begin a download for the requested . diff --git a/osu.Game/Database/IModelManager.cs b/osu.Game/Database/IModelManager.cs index 0be927322d..15ad455f21 100644 --- a/osu.Game/Database/IModelManager.cs +++ b/osu.Game/Database/IModelManager.cs @@ -5,7 +5,6 @@ using System; using System.Collections.Generic; using System.IO; using System.Threading.Tasks; -using osu.Framework.Bindables; using osu.Game.IO; namespace osu.Game.Database @@ -18,16 +17,14 @@ namespace osu.Game.Database where TModel : class { /// - /// A bindable which contains a weak reference to the last item that was updated. - /// This is not thread-safe and should be scheduled locally if consumed from a drawable component. + /// Fired when an item is updated. /// - IBindable> ItemUpdated { get; } + event Action ItemUpdated; /// - /// A bindable which contains a weak reference to the last item that was removed. - /// This is not thread-safe and should be scheduled locally if consumed from a drawable component. + /// Fired when an item is removed. /// - IBindable> ItemRemoved { get; } + event Action ItemRemoved; /// /// This is a temporary method and will likely be replaced by a full-fledged (and more correctly placed) migration process in the future. diff --git a/osu.Game/Database/ModelDownloader.cs b/osu.Game/Database/ModelDownloader.cs index e44ae21ed6..3c1f181f24 100644 --- a/osu.Game/Database/ModelDownloader.cs +++ b/osu.Game/Database/ModelDownloader.cs @@ -6,7 +6,6 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Humanizer; -using osu.Framework.Bindables; using osu.Framework.Logging; using osu.Framework.Platform; using osu.Game.Online.API; @@ -20,13 +19,9 @@ namespace osu.Game.Database { public Action PostNotification { protected get; set; } - public IBindable>> DownloadBegan => downloadBegan; + public event Action> DownloadBegan; - private readonly Bindable>> downloadBegan = new Bindable>>(); - - public IBindable>> DownloadFailed => downloadFailed; - - private readonly Bindable>> downloadFailed = new Bindable>>(); + public event Action> DownloadFailed; private readonly IModelImporter importer; private readonly IAPIProvider api; @@ -73,7 +68,7 @@ namespace osu.Game.Database // for now a failed import will be marked as a failed download for simplicity. if (!imported.Any()) - downloadFailed.Value = new WeakReference>(request); + DownloadFailed?.Invoke(request); CurrentDownloads.Remove(request); }, TaskCreationOptions.LongRunning); @@ -92,14 +87,14 @@ namespace osu.Game.Database api.PerformAsync(request); - downloadBegan.Value = new WeakReference>(request); + DownloadBegan?.Invoke(request); return true; void triggerFailure(Exception error) { CurrentDownloads.Remove(request); - downloadFailed.Value = new WeakReference>(request); + DownloadFailed?.Invoke(request); notification.State = ProgressNotificationState.Cancelled; diff --git a/osu.Game/Database/RealmContextFactory.cs b/osu.Game/Database/RealmContextFactory.cs index 85f7dd6b89..42ae986921 100644 --- a/osu.Game/Database/RealmContextFactory.cs +++ b/osu.Game/Database/RealmContextFactory.cs @@ -3,6 +3,7 @@ using System; using System.Linq; +using System.Reflection; using System.Threading; using osu.Framework.Allocation; using osu.Framework.Development; @@ -35,8 +36,9 @@ namespace osu.Game.Database /// 6 First tracked version (~20211018) /// 7 Changed OnlineID fields to non-nullable to add indexing support (20211018) /// 8 Rebind scroll adjust keys to not have control modifier (20211029) + /// 9 Converted BeatmapMetadata.Author from string to RealmUser (20211104) /// - private const int schema_version = 8; + private const int schema_version = 9; /// /// Lock object which is held during sections, blocking context creation during blocking periods. @@ -151,50 +153,86 @@ namespace osu.Game.Database private void onMigration(Migration migration, ulong lastSchemaVersion) { - if (lastSchemaVersion < 8) + for (ulong i = lastSchemaVersion; i <= schema_version; i++) + applyMigrationsForVersion(migration, i); + } + + private void applyMigrationsForVersion(Migration migration, ulong version) + { + switch (version) { - // Ctrl -/+ now adjusts UI scale so let's clear any bindings which overlap these combinations. - // New defaults will be populated by the key store afterwards. - var keyBindings = migration.NewRealm.All(); + case 7: + convertOnlineIDs(); + convertOnlineIDs(); + convertOnlineIDs(); - var increaseSpeedBinding = keyBindings.FirstOrDefault(k => k.ActionInt == (int)GlobalAction.IncreaseScrollSpeed); - if (increaseSpeedBinding != null && increaseSpeedBinding.KeyCombination.Keys.SequenceEqual(new[] { InputKey.Control, InputKey.Plus })) - migration.NewRealm.Remove(increaseSpeedBinding); + void convertOnlineIDs() where T : RealmObject + { + string className = getMappedOrOriginalName(typeof(T)); - var decreaseSpeedBinding = keyBindings.FirstOrDefault(k => k.ActionInt == (int)GlobalAction.DecreaseScrollSpeed); - if (decreaseSpeedBinding != null && decreaseSpeedBinding.KeyCombination.Keys.SequenceEqual(new[] { InputKey.Control, InputKey.Minus })) - migration.NewRealm.Remove(decreaseSpeedBinding); - } + // version was not bumped when the beatmap/ruleset models were added + // therefore we must manually check for their presence to avoid throwing on the `DynamicApi` calls. + if (!migration.OldRealm.Schema.TryFindObjectSchema(className, out _)) + return; - if (lastSchemaVersion < 7) - { - convertOnlineIDs(); - convertOnlineIDs(); - convertOnlineIDs(); + var oldItems = migration.OldRealm.DynamicApi.All(className); + var newItems = migration.NewRealm.DynamicApi.All(className); - void convertOnlineIDs() where T : RealmObject - { - string className = typeof(T).Name.Replace(@"Realm", string.Empty); + int itemCount = newItems.Count(); - // version was not bumped when the beatmap/ruleset models were added - // therefore we must manually check for their presence to avoid throwing on the `DynamicApi` calls. - if (!migration.OldRealm.Schema.TryFindObjectSchema(className, out _)) + for (int i = 0; i < itemCount; i++) + { + dynamic? oldItem = oldItems.ElementAt(i); + dynamic? newItem = newItems.ElementAt(i); + + long? nullableOnlineID = oldItem?.OnlineID; + newItem.OnlineID = (int)(nullableOnlineID ?? -1); + } + } + + break; + + case 8: + // Ctrl -/+ now adjusts UI scale so let's clear any bindings which overlap these combinations. + // New defaults will be populated by the key store afterwards. + var keyBindings = migration.NewRealm.All(); + + var increaseSpeedBinding = keyBindings.FirstOrDefault(k => k.ActionInt == (int)GlobalAction.IncreaseScrollSpeed); + if (increaseSpeedBinding != null && increaseSpeedBinding.KeyCombination.Keys.SequenceEqual(new[] { InputKey.Control, InputKey.Plus })) + migration.NewRealm.Remove(increaseSpeedBinding); + + var decreaseSpeedBinding = keyBindings.FirstOrDefault(k => k.ActionInt == (int)GlobalAction.DecreaseScrollSpeed); + if (decreaseSpeedBinding != null && decreaseSpeedBinding.KeyCombination.Keys.SequenceEqual(new[] { InputKey.Control, InputKey.Minus })) + migration.NewRealm.Remove(decreaseSpeedBinding); + + break; + + case 9: + // Pretty pointless to do this as beatmaps aren't really loaded via realm yet, but oh well. + string metadataClassName = getMappedOrOriginalName(typeof(RealmBeatmapMetadata)); + + // May be coming from a version before `RealmBeatmapMetadata` existed. + if (!migration.OldRealm.Schema.TryFindObjectSchema(metadataClassName, out _)) return; - var oldItems = migration.OldRealm.DynamicApi.All(className); - var newItems = migration.NewRealm.DynamicApi.All(className); + var oldMetadata = migration.OldRealm.DynamicApi.All(metadataClassName); + var newMetadata = migration.NewRealm.All(); - int itemCount = newItems.Count(); + int metadataCount = newMetadata.Count(); - for (int i = 0; i < itemCount; i++) + for (int i = 0; i < metadataCount; i++) { - dynamic? oldItem = oldItems.ElementAt(i); - dynamic? newItem = newItems.ElementAt(i); + dynamic? oldItem = oldMetadata.ElementAt(i); + var newItem = newMetadata.ElementAt(i); - long? nullableOnlineID = oldItem?.OnlineID; - newItem.OnlineID = (int)(nullableOnlineID ?? -1); + string username = oldItem.Author; + newItem.Author = new RealmUser + { + Username = username + }; } - } + + break; } } @@ -252,6 +290,9 @@ namespace osu.Game.Database }); } + // https://github.com/realm/realm-dotnet/blob/32f4ebcc88b3e80a3b254412665340cd9f3bd6b5/Realm/Realm/Extensions/ReflectionExtensions.cs#L46 + private static string getMappedOrOriginalName(MemberInfo member) => member.GetCustomAttribute()?.Mapping ?? member.Name; + private bool isDisposed; public void Dispose() diff --git a/osu.Game/Database/UserLookupCache.cs b/osu.Game/Database/UserLookupCache.cs index 3626f5e83a..dae2d2549c 100644 --- a/osu.Game/Database/UserLookupCache.cs +++ b/osu.Game/Database/UserLookupCache.cs @@ -9,33 +9,33 @@ using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Game.Online.API; using osu.Game.Online.API.Requests; -using osu.Game.Users; +using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Database { - public class UserLookupCache : MemoryCachingComponent + public class UserLookupCache : MemoryCachingComponent { [Resolved] private IAPIProvider api { get; set; } /// - /// Perform an API lookup on the specified user, populating a model. + /// Perform an API lookup on the specified user, populating a model. /// /// The user to lookup. /// An optional cancellation token. /// The populated user, or null if the user does not exist or the request could not be satisfied. [ItemCanBeNull] - public Task GetUserAsync(int userId, CancellationToken token = default) => GetAsync(userId, token); + public Task GetUserAsync(int userId, CancellationToken token = default) => GetAsync(userId, token); /// - /// Perform an API lookup on the specified users, populating a model. + /// Perform an API lookup on the specified users, populating a model. /// /// The users to lookup. /// An optional cancellation token. /// The populated users. May include null results for failed retrievals. - public Task GetUsersAsync(int[] userIds, CancellationToken token = default) + public Task GetUsersAsync(int[] userIds, CancellationToken token = default) { - var userLookupTasks = new List>(); + var userLookupTasks = new List>(); foreach (int u in userIds) { @@ -51,18 +51,18 @@ namespace osu.Game.Database return Task.WhenAll(userLookupTasks); } - protected override async Task ComputeValueAsync(int lookup, CancellationToken token = default) + protected override async Task ComputeValueAsync(int lookup, CancellationToken token = default) => await queryUser(lookup).ConfigureAwait(false); - private readonly Queue<(int id, TaskCompletionSource)> pendingUserTasks = new Queue<(int, TaskCompletionSource)>(); + private readonly Queue<(int id, TaskCompletionSource)> pendingUserTasks = new Queue<(int, TaskCompletionSource)>(); private Task pendingRequestTask; private readonly object taskAssignmentLock = new object(); - private Task queryUser(int userId) + private Task queryUser(int userId) { lock (taskAssignmentLock) { - var tcs = new TaskCompletionSource(); + var tcs = new TaskCompletionSource(); // Add to the queue. pendingUserTasks.Enqueue((userId, tcs)); @@ -78,14 +78,14 @@ namespace osu.Game.Database private void performLookup() { // contains at most 50 unique user IDs from userTasks, which is used to perform the lookup. - var userTasks = new Dictionary>>(); + var userTasks = new Dictionary>>(); // Grab at most 50 unique user IDs from the queue. lock (taskAssignmentLock) { while (pendingUserTasks.Count > 0 && userTasks.Count < 50) { - (int id, TaskCompletionSource task) next = pendingUserTasks.Dequeue(); + (int id, TaskCompletionSource task) next = pendingUserTasks.Dequeue(); // Perform a secondary check for existence, in case the user was queried in a previous batch. if (CheckExists(next.id, out var existing)) @@ -95,7 +95,7 @@ namespace osu.Game.Database if (userTasks.TryGetValue(next.id, out var tasks)) tasks.Add(next.task); else - userTasks[next.id] = new List> { next.task }; + userTasks[next.id] = new List> { next.task }; } } } @@ -115,7 +115,7 @@ namespace osu.Game.Database createNewTask(); } - List foundUsers = request.Response?.Users; + List foundUsers = request.Response?.Users; if (foundUsers != null) { diff --git a/osu.Game/Graphics/Containers/LinkFlowContainer.cs b/osu.Game/Graphics/Containers/LinkFlowContainer.cs index 7d1210d0e3..1d286d3487 100644 --- a/osu.Game/Graphics/Containers/LinkFlowContainer.cs +++ b/osu.Game/Graphics/Containers/LinkFlowContainer.cs @@ -46,7 +46,7 @@ namespace osu.Game.Graphics.Containers AddText(text[previousLinkEnd..link.Index]); string displayText = text.Substring(link.Index, link.Length); - string linkArgument = link.Argument; + object linkArgument = link.Argument; string tooltip = displayText == link.Url ? null : link.Url; AddLink(displayText, link.Action, linkArgument, tooltip); @@ -62,16 +62,16 @@ namespace osu.Game.Graphics.Containers public void AddLink(LocalisableString text, Action action, string tooltipText = null, Action creationParameters = null) => createLink(CreateChunkFor(text, true, CreateSpriteText, creationParameters), new LinkDetails(LinkAction.Custom, string.Empty), tooltipText, action); - public void AddLink(LocalisableString text, LinkAction action, string argument, string tooltipText = null, Action creationParameters = null) + public void AddLink(LocalisableString text, LinkAction action, object argument, string tooltipText = null, Action creationParameters = null) => createLink(CreateChunkFor(text, true, CreateSpriteText, creationParameters), new LinkDetails(action, argument), tooltipText); - public void AddLink(IEnumerable text, LinkAction action, string linkArgument, string tooltipText = null) + public void AddLink(IEnumerable text, LinkAction action, object linkArgument, string tooltipText = null) { createLink(new TextPartManual(text), new LinkDetails(action, linkArgument), tooltipText); } - public void AddUserLink(User user, Action creationParameters = null) - => createLink(CreateChunkFor(user.Username, true, CreateSpriteText, creationParameters), new LinkDetails(LinkAction.OpenUserProfile, user.Id.ToString()), "view profile"); + public void AddUserLink(IUser user, Action creationParameters = null) + => createLink(CreateChunkFor(user.Username, true, CreateSpriteText, creationParameters), new LinkDetails(LinkAction.OpenUserProfile, user), "view profile"); private void createLink(ITextPart textPart, LinkDetails link, LocalisableString tooltipText, Action action = null) { @@ -83,7 +83,7 @@ namespace osu.Game.Graphics.Containers game.HandleLink(link); // fallback to handle cases where OsuGame is not available, ie. tournament client. else if (link.Action == LinkAction.External) - host.OpenUrlExternally(link.Argument); + host.OpenUrlExternally(link.Argument.ToString()); }; AddPart(new TextLink(textPart, tooltipText, onClickAction)); diff --git a/osu.Game/Input/RealmKeyBindingStore.cs b/osu.Game/Input/RealmKeyBindingStore.cs index c65e36e478..046969579c 100644 --- a/osu.Game/Input/RealmKeyBindingStore.cs +++ b/osu.Game/Input/RealmKeyBindingStore.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; +using osu.Framework.Input; using osu.Framework.Input.Bindings; using osu.Game.Database; using osu.Game.Input.Bindings; @@ -16,10 +17,12 @@ namespace osu.Game.Input public class RealmKeyBindingStore { private readonly RealmContextFactory realmFactory; + private readonly ReadableKeyCombinationProvider keyCombinationProvider; - public RealmKeyBindingStore(RealmContextFactory realmFactory) + public RealmKeyBindingStore(RealmContextFactory realmFactory, ReadableKeyCombinationProvider keyCombinationProvider) { this.realmFactory = realmFactory; + this.keyCombinationProvider = keyCombinationProvider; } /// @@ -35,7 +38,7 @@ namespace osu.Game.Input { foreach (var action in context.All().Where(b => b.RulesetID == null && (GlobalAction)b.ActionInt == globalAction)) { - string str = action.KeyCombination.ReadableString(); + string str = keyCombinationProvider.GetReadableString(action.KeyCombination); // even if found, the readable string may be empty for an unbound action. if (str.Length > 0) diff --git a/osu.Game/Models/RealmBeatmapMetadata.cs b/osu.Game/Models/RealmBeatmapMetadata.cs index 6ea7170d0f..db1b09e6ad 100644 --- a/osu.Game/Models/RealmBeatmapMetadata.cs +++ b/osu.Game/Models/RealmBeatmapMetadata.cs @@ -5,6 +5,7 @@ using System; using Newtonsoft.Json; using osu.Framework.Testing; using osu.Game.Beatmaps; +using osu.Game.Users; using Realms; #nullable enable @@ -26,7 +27,7 @@ namespace osu.Game.Models [JsonProperty("artist_unicode")] public string ArtistUnicode { get; set; } = string.Empty; - public string Author { get; set; } = string.Empty; // eventually should be linked to a persisted User. + public RealmUser Author { get; set; } = new RealmUser(); public string Source { get; set; } = string.Empty; @@ -41,5 +42,7 @@ namespace osu.Game.Models public string AudioFile { get; set; } = string.Empty; public string BackgroundFile { get; set; } = string.Empty; + + IUser IBeatmapMetadataInfo.Author => Author; } } diff --git a/osu.Game/Models/RealmUser.cs b/osu.Game/Models/RealmUser.cs new file mode 100644 index 0000000000..154ece502f --- /dev/null +++ b/osu.Game/Models/RealmUser.cs @@ -0,0 +1,17 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Game.Users; +using Realms; + +namespace osu.Game.Models +{ + public class RealmUser : EmbeddedObject, IUser + { + public int OnlineID { get; set; } = 1; + + public string Username { get; set; } + + public bool IsBot => false; + } +} diff --git a/osu.Game/Online/API/APIAccess.cs b/osu.Game/Online/API/APIAccess.cs index 94508e3a81..8d91548149 100644 --- a/osu.Game/Online/API/APIAccess.cs +++ b/osu.Game/Online/API/APIAccess.cs @@ -17,6 +17,7 @@ using osu.Framework.Graphics; using osu.Framework.Logging; using osu.Game.Configuration; using osu.Game.Online.API.Requests; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Users; namespace osu.Game.Online.API @@ -41,13 +42,13 @@ namespace osu.Game.Online.API private string password; - public IBindable LocalUser => localUser; - public IBindableList Friends => friends; + public IBindable LocalUser => localUser; + public IBindableList Friends => friends; public IBindable Activity => activity; - private Bindable localUser { get; } = new Bindable(createGuestUser()); + private Bindable localUser { get; } = new Bindable(createGuestUser()); - private BindableList friends { get; } = new BindableList(); + private BindableList friends { get; } = new BindableList(); private Bindable activity { get; } = new Bindable(); @@ -436,7 +437,7 @@ namespace osu.Game.Online.API flushQueue(); } - private static User createGuestUser() => new GuestUser(); + private static APIUser createGuestUser() => new GuestUser(); protected override void Dispose(bool isDisposing) { @@ -447,7 +448,7 @@ namespace osu.Game.Online.API } } - internal class GuestUser : User + internal class GuestUser : APIUser { public GuestUser() { diff --git a/osu.Game/Online/API/APIRequest.cs b/osu.Game/Online/API/APIRequest.cs index 69d72226ba..43195811dc 100644 --- a/osu.Game/Online/API/APIRequest.cs +++ b/osu.Game/Online/API/APIRequest.cs @@ -6,7 +6,7 @@ using JetBrains.Annotations; using Newtonsoft.Json; using osu.Framework.IO.Network; using osu.Framework.Logging; -using osu.Game.Users; +using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Online.API { @@ -69,7 +69,7 @@ namespace osu.Game.Online.API /// /// The currently logged in user. Note that this will only be populated during . /// - protected User User { get; private set; } + protected APIUser User { get; private set; } /// /// Invoked on successful completion of an API request. diff --git a/osu.Game/Online/API/DummyAPIAccess.cs b/osu.Game/Online/API/DummyAPIAccess.cs index 8f91a4d198..7131c3a7d4 100644 --- a/osu.Game/Online/API/DummyAPIAccess.cs +++ b/osu.Game/Online/API/DummyAPIAccess.cs @@ -6,19 +6,20 @@ using System.Threading; using System.Threading.Tasks; using osu.Framework.Bindables; using osu.Framework.Graphics; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Users; namespace osu.Game.Online.API { public class DummyAPIAccess : Component, IAPIProvider { - public Bindable LocalUser { get; } = new Bindable(new User + public Bindable LocalUser { get; } = new Bindable(new APIUser { Username = @"Dummy", Id = 1001, }); - public BindableList Friends { get; } = new BindableList(); + public BindableList Friends { get; } = new BindableList(); public Bindable Activity { get; } = new Bindable(); @@ -90,7 +91,7 @@ namespace osu.Game.Online.API } LastLoginError = null; - LocalUser.Value = new User + LocalUser.Value = new APIUser { Username = username, Id = 1001, @@ -115,8 +116,8 @@ namespace osu.Game.Online.API public void SetState(APIState newState) => state.Value = newState; - IBindable IAPIProvider.LocalUser => LocalUser; - IBindableList IAPIProvider.Friends => Friends; + IBindable IAPIProvider.LocalUser => LocalUser; + IBindableList IAPIProvider.Friends => Friends; IBindable IAPIProvider.Activity => Activity; public void FailNextLogin() => shouldFailNextLogin = true; diff --git a/osu.Game/Online/API/IAPIProvider.cs b/osu.Game/Online/API/IAPIProvider.cs index 72ca37bcf4..a97eae77e3 100644 --- a/osu.Game/Online/API/IAPIProvider.cs +++ b/osu.Game/Online/API/IAPIProvider.cs @@ -6,6 +6,7 @@ using System; using System.Threading.Tasks; using osu.Framework.Bindables; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Users; namespace osu.Game.Online.API @@ -16,13 +17,13 @@ namespace osu.Game.Online.API /// The local user. /// This is not thread-safe and should be scheduled locally if consumed from a drawable component. /// - IBindable LocalUser { get; } + IBindable LocalUser { get; } /// /// The user's friends. /// This is not thread-safe and should be scheduled locally if consumed from a drawable component. /// - IBindableList Friends { get; } + IBindableList Friends { get; } /// /// The current user's activity. diff --git a/osu.Game/Online/API/Requests/CreateNewPrivateMessageRequest.cs b/osu.Game/Online/API/Requests/CreateNewPrivateMessageRequest.cs index 37ffc04e04..e5761149e7 100644 --- a/osu.Game/Online/API/Requests/CreateNewPrivateMessageRequest.cs +++ b/osu.Game/Online/API/Requests/CreateNewPrivateMessageRequest.cs @@ -3,17 +3,17 @@ using System.Net.Http; using osu.Framework.IO.Network; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Chat; -using osu.Game.Users; namespace osu.Game.Online.API.Requests { public class CreateNewPrivateMessageRequest : APIRequest { - private readonly User user; + private readonly APIUser user; private readonly Message message; - public CreateNewPrivateMessageRequest(User user, Message message) + public CreateNewPrivateMessageRequest(APIUser user, Message message) { this.user = user; this.message = message; diff --git a/osu.Game/Online/API/Requests/GetFriendsRequest.cs b/osu.Game/Online/API/Requests/GetFriendsRequest.cs index 46890aa889..63a221d91a 100644 --- a/osu.Game/Online/API/Requests/GetFriendsRequest.cs +++ b/osu.Game/Online/API/Requests/GetFriendsRequest.cs @@ -2,11 +2,11 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Generic; -using osu.Game.Users; +using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Online.API.Requests { - public class GetFriendsRequest : APIRequest> + public class GetFriendsRequest : APIRequest> { protected override string Target => @"friends"; } diff --git a/osu.Game/Online/API/Requests/GetUserRequest.cs b/osu.Game/Online/API/Requests/GetUserRequest.cs index 730e4e02ed..e32451fc2f 100644 --- a/osu.Game/Online/API/Requests/GetUserRequest.cs +++ b/osu.Game/Online/API/Requests/GetUserRequest.cs @@ -1,12 +1,12 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using osu.Game.Users; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Rulesets; namespace osu.Game.Online.API.Requests { - public class GetUserRequest : APIRequest + public class GetUserRequest : APIRequest { public readonly string Lookup; public readonly RulesetInfo Ruleset; diff --git a/osu.Game/Online/API/Requests/GetUsersResponse.cs b/osu.Game/Online/API/Requests/GetUsersResponse.cs index 6f49d5cd53..022050de5c 100644 --- a/osu.Game/Online/API/Requests/GetUsersResponse.cs +++ b/osu.Game/Online/API/Requests/GetUsersResponse.cs @@ -3,13 +3,13 @@ using System.Collections.Generic; using Newtonsoft.Json; -using osu.Game.Users; +using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Online.API.Requests { public class GetUsersResponse : ResponseWithCursor { [JsonProperty("users")] - public List Users; + public List Users; } } diff --git a/osu.Game/Online/API/Requests/PostBeatmapFavouriteRequest.cs b/osu.Game/Online/API/Requests/PostBeatmapFavouriteRequest.cs index f3724230cb..9fdc3382aa 100644 --- a/osu.Game/Online/API/Requests/PostBeatmapFavouriteRequest.cs +++ b/osu.Game/Online/API/Requests/PostBeatmapFavouriteRequest.cs @@ -8,20 +8,21 @@ namespace osu.Game.Online.API.Requests { public class PostBeatmapFavouriteRequest : APIRequest { + public readonly BeatmapFavouriteAction Action; + private readonly int id; - private readonly BeatmapFavouriteAction action; public PostBeatmapFavouriteRequest(int id, BeatmapFavouriteAction action) { this.id = id; - this.action = action; + Action = action; } protected override WebRequest CreateWebRequest() { var req = base.CreateWebRequest(); req.Method = HttpMethod.Post; - req.AddParameter(@"action", action.ToString().ToLowerInvariant()); + req.AddParameter(@"action", Action.ToString().ToLowerInvariant()); return req; } diff --git a/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs b/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs index 47536879b2..168e9d5d51 100644 --- a/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs +++ b/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs @@ -6,7 +6,6 @@ using System.Collections.Generic; using Newtonsoft.Json; using osu.Game.Beatmaps; using osu.Game.Database; -using osu.Game.Users; #nullable enable @@ -62,6 +61,12 @@ namespace osu.Game.Online.API.Requests.Responses [JsonProperty(@"track_id")] public int? TrackId { get; set; } + [JsonProperty(@"hype")] + public BeatmapSetHypeStatus? HypeStatus { get; set; } + + [JsonProperty(@"nominations_summary")] + public BeatmapSetNominationStatus? NominationStatus { get; set; } + public string Title { get; set; } = string.Empty; [JsonProperty("title_unicode")] @@ -72,34 +77,26 @@ namespace osu.Game.Online.API.Requests.Responses [JsonProperty("artist_unicode")] public string ArtistUnicode { get; set; } = string.Empty; - public User? Author = new User(); + public APIUser Author = new APIUser(); /// - /// Helper property to deserialize a username to . + /// Helper property to deserialize a username to . /// [JsonProperty(@"user_id")] public int AuthorID { - get => Author?.Id ?? 1; - set - { - Author ??= new User(); - Author.Id = value; - } + get => Author.Id; + set => Author.Id = value; } /// - /// Helper property to deserialize a username to . + /// Helper property to deserialize a username to . /// [JsonProperty(@"creator")] public string AuthorString { - get => Author?.Username ?? string.Empty; - set - { - Author ??= new User(); - Author.Username = value; - } + get => Author.Username; + set => Author.Username = value; } [JsonProperty(@"availability")] diff --git a/osu.Game/Online/API/Requests/Responses/APIPlayStyle.cs b/osu.Game/Online/API/Requests/Responses/APIPlayStyle.cs new file mode 100644 index 0000000000..9573ae1825 --- /dev/null +++ b/osu.Game/Online/API/Requests/Responses/APIPlayStyle.cs @@ -0,0 +1,22 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.ComponentModel; + +namespace osu.Game.Online.API.Requests.Responses +{ + public enum APIPlayStyle + { + [Description("Keyboard")] + Keyboard, + + [Description("Mouse")] + Mouse, + + [Description("Tablet")] + Tablet, + + [Description("Touch Screen")] + Touch, + } +} diff --git a/osu.Game/Online/API/Requests/Responses/APIRankHistory.cs b/osu.Game/Online/API/Requests/Responses/APIRankHistory.cs new file mode 100644 index 0000000000..064badcccb --- /dev/null +++ b/osu.Game/Online/API/Requests/Responses/APIRankHistory.cs @@ -0,0 +1,16 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using Newtonsoft.Json; + +namespace osu.Game.Online.API.Requests.Responses +{ + public class APIRankHistory + { + [JsonProperty(@"mode")] + public string Mode; + + [JsonProperty(@"data")] + public int[] Data; + } +} diff --git a/osu.Game/Online/API/Requests/Responses/APIScoreInfo.cs b/osu.Game/Online/API/Requests/Responses/APIScoreInfo.cs index 82f56d27fd..d0677eacab 100644 --- a/osu.Game/Online/API/Requests/Responses/APIScoreInfo.cs +++ b/osu.Game/Online/API/Requests/Responses/APIScoreInfo.cs @@ -12,7 +12,6 @@ using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Scoring; using osu.Game.Scoring.Legacy; -using osu.Game.Users; namespace osu.Game.Online.API.Requests.Responses { @@ -25,7 +24,7 @@ namespace osu.Game.Online.API.Requests.Responses public int MaxCombo { get; set; } [JsonProperty(@"user")] - public User User { get; set; } + public APIUser User { get; set; } [JsonProperty(@"id")] public long OnlineID { get; set; } diff --git a/osu.Game/Online/API/Requests/Responses/APIUser.cs b/osu.Game/Online/API/Requests/Responses/APIUser.cs index ff422b8292..49edfd036b 100644 --- a/osu.Game/Online/API/Requests/Responses/APIUser.cs +++ b/osu.Game/Online/API/Requests/Responses/APIUser.cs @@ -1,14 +1,245 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; +using System.Collections.Generic; +using System.Linq; +using JetBrains.Annotations; using Newtonsoft.Json; +using osu.Framework.Bindables; using osu.Game.Users; namespace osu.Game.Online.API.Requests.Responses { - public class APIUser + public class APIUser : IEquatable, IUser { + [JsonProperty(@"id")] + public int Id { get; set; } = 1; + + [JsonProperty(@"join_date")] + public DateTimeOffset JoinDate; + + [JsonProperty(@"username")] + public string Username { get; set; } + + [JsonProperty(@"previous_usernames")] + public string[] PreviousUsernames; + + [JsonProperty(@"country")] + public Country Country; + + public readonly Bindable Status = new Bindable(); + + public readonly Bindable Activity = new Bindable(); + + [JsonProperty(@"profile_colour")] + public string Colour; + + [JsonProperty(@"avatar_url")] + public string AvatarUrl; + + [JsonProperty(@"cover_url")] + public string CoverUrl + { + get => Cover?.Url; + set => Cover = new UserCover { Url = value }; + } + + [JsonProperty(@"cover")] + public UserCover Cover; + + public class UserCover + { + [JsonProperty(@"custom_url")] + public string CustomUrl; + + [JsonProperty(@"url")] + public string Url; + + [JsonProperty(@"id")] + public int? Id; + } + + [JsonProperty(@"is_admin")] + public bool IsAdmin; + + [JsonProperty(@"is_supporter")] + public bool IsSupporter; + + [JsonProperty(@"support_level")] + public int SupportLevel; + + [JsonProperty(@"is_gmt")] + public bool IsGMT; + + [JsonProperty(@"is_qat")] + public bool IsQAT; + + [JsonProperty(@"is_bng")] + public bool IsBNG; + + [JsonProperty(@"is_bot")] + public bool IsBot { get; set; } + + [JsonProperty(@"is_active")] + public bool Active; + + [JsonProperty(@"is_online")] + public bool IsOnline; + + [JsonProperty(@"pm_friends_only")] + public bool PMFriendsOnly; + + [JsonProperty(@"interests")] + public string Interests; + + [JsonProperty(@"occupation")] + public string Occupation; + + [JsonProperty(@"title")] + public string Title; + + [JsonProperty(@"location")] + public string Location; + + [JsonProperty(@"last_visit")] + public DateTimeOffset? LastVisit; + + [JsonProperty(@"twitter")] + public string Twitter; + + [JsonProperty(@"discord")] + public string Discord; + + [JsonProperty(@"website")] + public string Website; + + [JsonProperty(@"post_count")] + public int PostCount; + + [JsonProperty(@"comments_count")] + public int CommentsCount; + + [JsonProperty(@"follower_count")] + public int FollowerCount; + + [JsonProperty(@"mapping_follower_count")] + public int MappingFollowerCount; + + [JsonProperty(@"favourite_beatmapset_count")] + public int FavouriteBeatmapsetCount; + + [JsonProperty(@"graveyard_beatmapset_count")] + public int GraveyardBeatmapsetCount; + + [JsonProperty(@"loved_beatmapset_count")] + public int LovedBeatmapsetCount; + + [JsonProperty(@"ranked_beatmapset_count")] + public int RankedBeatmapsetCount; + + [JsonProperty(@"pending_beatmapset_count")] + public int PendingBeatmapsetCount; + + [JsonProperty(@"scores_best_count")] + public int ScoresBestCount; + + [JsonProperty(@"scores_first_count")] + public int ScoresFirstCount; + + [JsonProperty(@"scores_recent_count")] + public int ScoresRecentCount; + + [JsonProperty(@"beatmap_playcounts_count")] + public int BeatmapPlaycountsCount; + [JsonProperty] - public User User; + private string[] playstyle + { + set => PlayStyles = value?.Select(str => Enum.Parse(typeof(APIPlayStyle), str, true)).Cast().ToArray(); + } + + public APIPlayStyle[] PlayStyles; + + [JsonProperty(@"playmode")] + public string PlayMode; + + [JsonProperty(@"profile_order")] + public string[] ProfileOrder; + + [JsonProperty(@"kudosu")] + public KudosuCount Kudosu; + + public class KudosuCount + { + [JsonProperty(@"total")] + public int Total; + + [JsonProperty(@"available")] + public int Available; + } + + private UserStatistics statistics; + + /// + /// User statistics for the requested ruleset (in the case of a or response). + /// Otherwise empty. + /// + [JsonProperty(@"statistics")] + public UserStatistics Statistics + { + get => statistics ??= new UserStatistics(); + set + { + if (statistics != null) + // we may already have rank history populated + value.RankHistory = statistics.RankHistory; + + statistics = value; + } + } + + [JsonProperty(@"rank_history")] + private APIRankHistory rankHistory + { + set => statistics.RankHistory = value; + } + + [JsonProperty("badges")] + public Badge[] Badges; + + [JsonProperty("user_achievements")] + public APIUserAchievement[] Achievements; + + [JsonProperty("monthly_playcounts")] + public APIUserHistoryCount[] MonthlyPlaycounts; + + [JsonProperty("replays_watched_counts")] + public APIUserHistoryCount[] ReplaysWatchedCounts; + + /// + /// All user statistics per ruleset's short name (in the case of a response). + /// Otherwise empty. Can be altered for testing purposes. + /// + // todo: this should likely be moved to a separate UserCompact class at some point. + [JsonProperty("statistics_rulesets")] + [CanBeNull] + public Dictionary RulesetsStatistics { get; set; } + + public override string ToString() => Username; + + /// + /// A user instance for displaying locally created system messages. + /// + public static readonly APIUser SYSTEM_USER = new APIUser + { + Id = 0, + Username = "system", + Colour = @"9c0101", + }; + + public int OnlineID => Id; + + public bool Equals(APIUser other) => OnlineID == other?.OnlineID; } } diff --git a/osu.Game/Online/API/Requests/Responses/APIUserAchievement.cs b/osu.Game/Online/API/Requests/Responses/APIUserAchievement.cs new file mode 100644 index 0000000000..cfba9118c2 --- /dev/null +++ b/osu.Game/Online/API/Requests/Responses/APIUserAchievement.cs @@ -0,0 +1,17 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using Newtonsoft.Json; + +namespace osu.Game.Online.API.Requests.Responses +{ + public class APIUserAchievement + { + [JsonProperty("achievement_id")] + public int ID; + + [JsonProperty("achieved_at")] + public DateTimeOffset AchievedAt; + } +} diff --git a/osu.Game/Users/Team.cs b/osu.Game/Online/API/Requests/Responses/APIUserContainer.cs similarity index 51% rename from osu.Game/Users/Team.cs rename to osu.Game/Online/API/Requests/Responses/APIUserContainer.cs index b56a083fdf..9eb4a2a4e3 100644 --- a/osu.Game/Users/Team.cs +++ b/osu.Game/Online/API/Requests/Responses/APIUserContainer.cs @@ -1,10 +1,13 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -namespace osu.Game.Users +using Newtonsoft.Json; + +namespace osu.Game.Online.API.Requests.Responses { - public class Team + public class APIUserContainer { - public string Name; + [JsonProperty] + public APIUser User; } } diff --git a/osu.Game/Online/API/Requests/Responses/APIUserHistoryCount.cs b/osu.Game/Online/API/Requests/Responses/APIUserHistoryCount.cs new file mode 100644 index 0000000000..1226c88c08 --- /dev/null +++ b/osu.Game/Online/API/Requests/Responses/APIUserHistoryCount.cs @@ -0,0 +1,17 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using Newtonsoft.Json; + +namespace osu.Game.Online.API.Requests.Responses +{ + public class APIUserHistoryCount + { + [JsonProperty("start_date")] + public DateTime Date; + + [JsonProperty("count")] + public long Count; + } +} diff --git a/osu.Game/Online/API/Requests/Responses/APIUserScoreAggregate.cs b/osu.Game/Online/API/Requests/Responses/APIUserScoreAggregate.cs index 172fa3a583..9a7f0832a6 100644 --- a/osu.Game/Online/API/Requests/Responses/APIUserScoreAggregate.cs +++ b/osu.Game/Online/API/Requests/Responses/APIUserScoreAggregate.cs @@ -3,7 +3,6 @@ using Newtonsoft.Json; using osu.Game.Scoring; -using osu.Game.Users; namespace osu.Game.Online.API.Requests.Responses { @@ -31,7 +30,7 @@ namespace osu.Game.Online.API.Requests.Responses public long UserID { get; set; } [JsonProperty("user")] - public User User { get; set; } + public APIUser User { get; set; } [JsonProperty("position")] public int? Position { get; set; } diff --git a/osu.Game/Online/API/Requests/Responses/Comment.cs b/osu.Game/Online/API/Requests/Responses/Comment.cs index 32d489432d..13379a40a6 100644 --- a/osu.Game/Online/API/Requests/Responses/Comment.cs +++ b/osu.Game/Online/API/Requests/Responses/Comment.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using Newtonsoft.Json; -using osu.Game.Users; using System; namespace osu.Game.Online.API.Requests.Responses @@ -20,7 +19,7 @@ namespace osu.Game.Online.API.Requests.Responses [JsonProperty(@"user_id")] public long? UserId { get; set; } - public User User { get; set; } + public APIUser User { get; set; } [JsonProperty(@"message")] public string Message { get; set; } @@ -61,7 +60,7 @@ namespace osu.Game.Online.API.Requests.Responses [JsonProperty(@"pinned")] public bool Pinned { get; set; } - public User EditedUser { get; set; } + public APIUser EditedUser { get; set; } public bool IsTopLevel => !ParentId.HasValue; diff --git a/osu.Game/Online/API/Requests/Responses/CommentBundle.cs b/osu.Game/Online/API/Requests/Responses/CommentBundle.cs index 4070df493d..8436381090 100644 --- a/osu.Game/Online/API/Requests/Responses/CommentBundle.cs +++ b/osu.Game/Online/API/Requests/Responses/CommentBundle.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using Newtonsoft.Json; -using osu.Game.Users; using System.Collections.Generic; using System.Linq; @@ -43,10 +42,10 @@ namespace osu.Game.Online.API.Requests.Responses } } - private List users; + private List users; [JsonProperty(@"users")] - public List Users + public List Users { get => users; set diff --git a/osu.Game/Online/BeatmapDownloadTracker.cs b/osu.Game/Online/BeatmapDownloadTracker.cs index 12cbcdbec7..592dc60d20 100644 --- a/osu.Game/Online/BeatmapDownloadTracker.cs +++ b/osu.Game/Online/BeatmapDownloadTracker.cs @@ -3,7 +3,6 @@ using System; using osu.Framework.Allocation; -using osu.Framework.Bindables; using osu.Game.Beatmaps; using osu.Game.Online.API; @@ -23,11 +22,6 @@ namespace osu.Game.Online { } - private IBindable>? managerUpdated; - private IBindable>? managerRemoved; - private IBindable>>? managerDownloadBegan; - private IBindable>>? managerDownloadFailed; - [BackgroundDependencyLoader(true)] private void load() { @@ -42,39 +36,23 @@ namespace osu.Game.Online else attachDownload(Manager.GetExistingDownload(beatmapSetInfo)); - managerDownloadBegan = Manager.DownloadBegan.GetBoundCopy(); - managerDownloadBegan.BindValueChanged(downloadBegan); - managerDownloadFailed = Manager.DownloadFailed.GetBoundCopy(); - managerDownloadFailed.BindValueChanged(downloadFailed); - managerUpdated = Manager.ItemUpdated.GetBoundCopy(); - managerUpdated.BindValueChanged(itemUpdated); - managerRemoved = Manager.ItemRemoved.GetBoundCopy(); - managerRemoved.BindValueChanged(itemRemoved); + Manager.DownloadBegan += downloadBegan; + Manager.DownloadFailed += downloadFailed; + Manager.ItemUpdated += itemUpdated; + Manager.ItemRemoved += itemRemoved; } - private void downloadBegan(ValueChangedEvent>> weakRequest) + private void downloadBegan(ArchiveDownloadRequest request) => Schedule(() => { - if (weakRequest.NewValue.TryGetTarget(out var request)) - { - Schedule(() => - { - if (checkEquality(request.Model, TrackedItem)) - attachDownload(request); - }); - } - } + if (checkEquality(request.Model, TrackedItem)) + attachDownload(request); + }); - private void downloadFailed(ValueChangedEvent>> weakRequest) + private void downloadFailed(ArchiveDownloadRequest request) => Schedule(() => { - if (weakRequest.NewValue.TryGetTarget(out var request)) - { - Schedule(() => - { - if (checkEquality(request.Model, TrackedItem)) - attachDownload(null); - }); - } - } + if (checkEquality(request.Model, TrackedItem)) + attachDownload(null); + }); private void attachDownload(ArchiveDownloadRequest? request) { @@ -116,29 +94,17 @@ namespace osu.Game.Online private void onRequestFailure(Exception e) => Schedule(() => attachDownload(null)); - private void itemUpdated(ValueChangedEvent> weakItem) + private void itemUpdated(BeatmapSetInfo item) => Schedule(() => { - if (weakItem.NewValue.TryGetTarget(out var item)) - { - Schedule(() => - { - if (checkEquality(item, TrackedItem)) - UpdateState(DownloadState.LocallyAvailable); - }); - } - } + if (checkEquality(item, TrackedItem)) + UpdateState(DownloadState.LocallyAvailable); + }); - private void itemRemoved(ValueChangedEvent> weakItem) + private void itemRemoved(BeatmapSetInfo item) => Schedule(() => { - if (weakItem.NewValue.TryGetTarget(out var item)) - { - Schedule(() => - { - if (checkEquality(item, TrackedItem)) - UpdateState(DownloadState.NotDownloaded); - }); - } - } + if (checkEquality(item, TrackedItem)) + UpdateState(DownloadState.NotDownloaded); + }); private bool checkEquality(IBeatmapSetInfo x, IBeatmapSetInfo y) => x.OnlineID == y.OnlineID; @@ -148,6 +114,14 @@ namespace osu.Game.Online { base.Dispose(isDisposing); attachDownload(null); + + if (Manager != null) + { + Manager.DownloadBegan -= downloadBegan; + Manager.DownloadFailed -= downloadFailed; + Manager.ItemUpdated -= itemUpdated; + Manager.ItemRemoved -= itemRemoved; + } } #endregion diff --git a/osu.Game/Online/Chat/Channel.cs b/osu.Game/Online/Chat/Channel.cs index 9b463a6348..9cbb2f37e4 100644 --- a/osu.Game/Online/Chat/Channel.cs +++ b/osu.Game/Online/Chat/Channel.cs @@ -8,7 +8,7 @@ using System.Linq; using Newtonsoft.Json; using osu.Framework.Bindables; using osu.Framework.Lists; -using osu.Game.Users; +using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Online.Chat { @@ -19,7 +19,7 @@ namespace osu.Game.Online.Chat /// /// Contains every joined user except the current logged in user. Currently only returned for PM channels. /// - public readonly ObservableCollection Users = new ObservableCollection(); + public readonly ObservableCollection Users = new ObservableCollection(); [JsonProperty(@"users")] private int[] userIds @@ -27,7 +27,7 @@ namespace osu.Game.Online.Chat set { foreach (int id in value) - Users.Add(new User { Id = id }); + Users.Add(new APIUser { Id = id }); } } @@ -98,7 +98,7 @@ namespace osu.Game.Online.Chat /// Create a private messaging channel with the specified user. /// /// The user to create the private conversation with. - public Channel(User user) + public Channel(APIUser user) { Type = ChannelType.PM; Users.Add(user); diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index 52c9387185..edaf135e93 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -11,8 +11,8 @@ using osu.Framework.Logging; using osu.Game.Database; using osu.Game.Online.API; using osu.Game.Online.API.Requests; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays.Chat.Tabs; -using osu.Game.Users; namespace osu.Game.Online.Chat { @@ -91,7 +91,7 @@ namespace osu.Game.Online.Chat /// Opens a new private channel. /// /// The user the private channel is opened with. - public void OpenPrivateChannel(User user) + public void OpenPrivateChannel(APIUser user) { if (user == null) throw new ArgumentNullException(nameof(user)); diff --git a/osu.Game/Online/Chat/InfoMessage.cs b/osu.Game/Online/Chat/InfoMessage.cs index cea336aae2..e97245df45 100644 --- a/osu.Game/Online/Chat/InfoMessage.cs +++ b/osu.Game/Online/Chat/InfoMessage.cs @@ -2,7 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; -using osu.Game.Users; +using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Online.Chat { @@ -14,7 +14,7 @@ namespace osu.Game.Online.Chat Timestamp = DateTimeOffset.Now; Content = message; - Sender = User.SYSTEM_USER; + Sender = APIUser.SYSTEM_USER; } } } diff --git a/osu.Game/Online/Chat/Message.cs b/osu.Game/Online/Chat/Message.cs index 4f33153e56..dcd15f9028 100644 --- a/osu.Game/Online/Chat/Message.cs +++ b/osu.Game/Online/Chat/Message.cs @@ -4,7 +4,7 @@ using System; using System.Collections.Generic; using Newtonsoft.Json; -using osu.Game.Users; +using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Online.Chat { @@ -26,7 +26,7 @@ namespace osu.Game.Online.Chat public string Content; [JsonProperty(@"sender")] - public User Sender; + public APIUser Sender; [JsonConstructor] public Message() diff --git a/osu.Game/Online/Chat/MessageFormatter.cs b/osu.Game/Online/Chat/MessageFormatter.cs index 5e0f66443b..92911f0f51 100644 --- a/osu.Game/Online/Chat/MessageFormatter.cs +++ b/osu.Game/Online/Chat/MessageFormatter.cs @@ -320,9 +320,9 @@ namespace osu.Game.Online.Chat { public readonly LinkAction Action; - public readonly string Argument; + public readonly object Argument; - public LinkDetails(LinkAction action, string argument) + public LinkDetails(LinkAction action, object argument) { Action = action; Argument = argument; @@ -351,9 +351,9 @@ namespace osu.Game.Online.Chat public int Index; public int Length; public LinkAction Action; - public string Argument; + public object Argument; - public Link(string url, int startIndex, int length, LinkAction action, string argument) + public Link(string url, int startIndex, int length, LinkAction action, object argument) { Url = url; Index = startIndex; diff --git a/osu.Game/Online/Chat/MessageNotifier.cs b/osu.Game/Online/Chat/MessageNotifier.cs index 6840c036ff..ca6317566f 100644 --- a/osu.Game/Online/Chat/MessageNotifier.cs +++ b/osu.Game/Online/Chat/MessageNotifier.cs @@ -12,9 +12,9 @@ using osu.Framework.Graphics.Sprites; using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Online.API; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays; using osu.Game.Overlays.Notifications; -using osu.Game.Users; namespace osu.Game.Online.Chat { @@ -35,7 +35,7 @@ namespace osu.Game.Online.Chat private Bindable notifyOnUsername; private Bindable notifyOnPrivateMessage; - private readonly IBindable localUser = new Bindable(); + private readonly IBindable localUser = new Bindable(); private readonly IBindableList joinedChannels = new BindableList(); [BackgroundDependencyLoader] diff --git a/osu.Game/Online/Multiplayer/MultiplayerClient.cs b/osu.Game/Online/Multiplayer/MultiplayerClient.cs index 6c4747ea54..567e59e8a0 100644 --- a/osu.Game/Online/Multiplayer/MultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerClient.cs @@ -22,8 +22,8 @@ using osu.Game.Online.Rooms; using osu.Game.Online.Rooms.RoomStatuses; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; -using osu.Game.Users; using osu.Game.Utils; +using APIUser = osu.Game.Online.API.Requests.Responses.APIUser; namespace osu.Game.Online.Multiplayer { @@ -402,7 +402,7 @@ namespace osu.Game.Online.Multiplayer { Debug.Assert(APIRoom != null); - APIRoom.RecentParticipants.Add(user.User ?? new User + APIRoom.RecentParticipants.Add(user.User ?? new APIUser { Id = user.UserID, Username = "[Unresolved]" @@ -614,7 +614,7 @@ namespace osu.Game.Online.Multiplayer } /// - /// Populates the for a given . + /// Populates the for a given . /// /// The to populate. protected async Task PopulateUser(MultiplayerRoomUser multiplayerUser) => multiplayerUser.User ??= await userLookupCache.GetUserAsync(multiplayerUser.UserID).ConfigureAwait(false); diff --git a/osu.Game/Online/Multiplayer/MultiplayerRoomUser.cs b/osu.Game/Online/Multiplayer/MultiplayerRoomUser.cs index 5d11e2921a..519bfff116 100644 --- a/osu.Game/Online/Multiplayer/MultiplayerRoomUser.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerRoomUser.cs @@ -9,8 +9,8 @@ using System.Linq; using MessagePack; using Newtonsoft.Json; using osu.Game.Online.API; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Rooms; -using osu.Game.Users; namespace osu.Game.Online.Multiplayer { @@ -40,7 +40,7 @@ namespace osu.Game.Online.Multiplayer public IEnumerable Mods { get; set; } = Enumerable.Empty(); [IgnoreMember] - public User? User { get; set; } + public APIUser? User { get; set; } [JsonConstructor] public MultiplayerRoomUser(int userId) diff --git a/osu.Game/Online/Rooms/MultiplayerScore.cs b/osu.Game/Online/Rooms/MultiplayerScore.cs index 375e0b6b9f..cfb81f0bad 100644 --- a/osu.Game/Online/Rooms/MultiplayerScore.cs +++ b/osu.Game/Online/Rooms/MultiplayerScore.cs @@ -9,10 +9,10 @@ using Newtonsoft.Json; using Newtonsoft.Json.Converters; using osu.Game.Beatmaps; using osu.Game.Online.API; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Scoring; using osu.Game.Scoring; -using osu.Game.Users; namespace osu.Game.Online.Rooms { @@ -22,7 +22,7 @@ namespace osu.Game.Online.Rooms public long ID { get; set; } [JsonProperty("user")] - public User User { get; set; } + public APIUser User { get; set; } [JsonProperty("rank")] [JsonConverter(typeof(StringEnumConverter))] diff --git a/osu.Game/Online/Rooms/Room.cs b/osu.Game/Online/Rooms/Room.cs index 39fc7f1da8..48c5412aa3 100644 --- a/osu.Game/Online/Rooms/Room.cs +++ b/osu.Game/Online/Rooms/Room.cs @@ -7,8 +7,8 @@ using Newtonsoft.Json; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Game.IO.Serialization.Converters; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Rooms.RoomStatuses; -using osu.Game.Users; using osu.Game.Utils; namespace osu.Game.Online.Rooms @@ -25,7 +25,7 @@ namespace osu.Game.Online.Rooms [Cached] [JsonProperty("host")] - public readonly Bindable Host = new Bindable(); + public readonly Bindable Host = new Bindable(); [Cached] [JsonProperty("playlist")] @@ -86,7 +86,7 @@ namespace osu.Game.Online.Rooms [Cached] [JsonProperty("recent_participants")] - public readonly BindableList RecentParticipants = new BindableList(); + public readonly BindableList RecentParticipants = new BindableList(); [Cached] [JsonProperty("participant_count")] diff --git a/osu.Game/Online/ScoreDownloadTracker.cs b/osu.Game/Online/ScoreDownloadTracker.cs index 9ea6d5b79a..32307fc50e 100644 --- a/osu.Game/Online/ScoreDownloadTracker.cs +++ b/osu.Game/Online/ScoreDownloadTracker.cs @@ -3,7 +3,6 @@ using System; using osu.Framework.Allocation; -using osu.Framework.Bindables; using osu.Game.Online.API; using osu.Game.Scoring; @@ -23,11 +22,6 @@ namespace osu.Game.Online { } - private IBindable>? managerUpdated; - private IBindable>? managerRemoved; - private IBindable>>? managerDownloadBegan; - private IBindable>>? managerDownloadFailed; - [BackgroundDependencyLoader(true)] private void load() { @@ -46,39 +40,23 @@ namespace osu.Game.Online else attachDownload(Manager.GetExistingDownload(scoreInfo)); - managerDownloadBegan = Manager.DownloadBegan.GetBoundCopy(); - managerDownloadBegan.BindValueChanged(downloadBegan); - managerDownloadFailed = Manager.DownloadFailed.GetBoundCopy(); - managerDownloadFailed.BindValueChanged(downloadFailed); - managerUpdated = Manager.ItemUpdated.GetBoundCopy(); - managerUpdated.BindValueChanged(itemUpdated); - managerRemoved = Manager.ItemRemoved.GetBoundCopy(); - managerRemoved.BindValueChanged(itemRemoved); + Manager.DownloadBegan += downloadBegan; + Manager.DownloadFailed += downloadFailed; + Manager.ItemUpdated += itemUpdated; + Manager.ItemRemoved += itemRemoved; } - private void downloadBegan(ValueChangedEvent>> weakRequest) + private void downloadBegan(ArchiveDownloadRequest request) => Schedule(() => { - if (weakRequest.NewValue.TryGetTarget(out var request)) - { - Schedule(() => - { - if (checkEquality(request.Model, TrackedItem)) - attachDownload(request); - }); - } - } + if (checkEquality(request.Model, TrackedItem)) + attachDownload(request); + }); - private void downloadFailed(ValueChangedEvent>> weakRequest) + private void downloadFailed(ArchiveDownloadRequest request) => Schedule(() => { - if (weakRequest.NewValue.TryGetTarget(out var request)) - { - Schedule(() => - { - if (checkEquality(request.Model, TrackedItem)) - attachDownload(null); - }); - } - } + if (checkEquality(request.Model, TrackedItem)) + attachDownload(null); + }); private void attachDownload(ArchiveDownloadRequest? request) { @@ -120,29 +98,17 @@ namespace osu.Game.Online private void onRequestFailure(Exception e) => Schedule(() => attachDownload(null)); - private void itemUpdated(ValueChangedEvent> weakItem) + private void itemUpdated(ScoreInfo item) => Schedule(() => { - if (weakItem.NewValue.TryGetTarget(out var item)) - { - Schedule(() => - { - if (checkEquality(item, TrackedItem)) - UpdateState(DownloadState.LocallyAvailable); - }); - } - } + if (checkEquality(item, TrackedItem)) + UpdateState(DownloadState.LocallyAvailable); + }); - private void itemRemoved(ValueChangedEvent> weakItem) + private void itemRemoved(ScoreInfo item) => Schedule(() => { - if (weakItem.NewValue.TryGetTarget(out var item)) - { - Schedule(() => - { - if (checkEquality(item, TrackedItem)) - UpdateState(DownloadState.NotDownloaded); - }); - } - } + if (checkEquality(item, TrackedItem)) + UpdateState(DownloadState.NotDownloaded); + }); private bool checkEquality(IScoreInfo x, IScoreInfo y) => x.OnlineID == y.OnlineID; @@ -152,6 +118,14 @@ namespace osu.Game.Online { base.Dispose(isDisposing); attachDownload(null); + + if (Manager != null) + { + Manager.DownloadBegan -= downloadBegan; + Manager.DownloadFailed -= downloadFailed; + Manager.ItemUpdated -= itemUpdated; + Manager.ItemRemoved -= itemRemoved; + } } #endregion diff --git a/osu.Game/Online/Solo/SubmittableScore.cs b/osu.Game/Online/Solo/SubmittableScore.cs index bafb308a13..373c302844 100644 --- a/osu.Game/Online/Solo/SubmittableScore.cs +++ b/osu.Game/Online/Solo/SubmittableScore.cs @@ -10,7 +10,7 @@ using osu.Game.Online.API; using osu.Game.Online.API.Requests.Responses; using osu.Game.Rulesets.Scoring; using osu.Game.Scoring; -using osu.Game.Users; +using APIUser = osu.Game.Online.API.Requests.Responses.APIUser; namespace osu.Game.Online.Solo { @@ -48,7 +48,7 @@ namespace osu.Game.Online.Solo public APIMod[] Mods { get; set; } [JsonProperty("user")] - public User User { get; set; } + public APIUser User { get; set; } [JsonProperty("statistics")] public Dictionary Statistics { get; set; } diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index a7ed7fedf5..bf757a153f 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -53,8 +53,10 @@ using osu.Game.Database; using osu.Game.Extensions; using osu.Game.IO; using osu.Game.Localisation; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Performance; using osu.Game.Skinning.Editor; +using osu.Game.Users; namespace osu.Game { @@ -287,25 +289,27 @@ namespace osu.Game /// The link to load. public void HandleLink(LinkDetails link) => Schedule(() => { + string argString = link.Argument.ToString(); + switch (link.Action) { case LinkAction.OpenBeatmap: // TODO: proper query params handling - if (int.TryParse(link.Argument.Contains('?') ? link.Argument.Split('?')[0] : link.Argument, out int beatmapId)) + if (int.TryParse(argString.Contains('?') ? argString.Split('?')[0] : argString, out int beatmapId)) ShowBeatmap(beatmapId); break; case LinkAction.OpenBeatmapSet: - if (int.TryParse(link.Argument, out int setId)) + if (int.TryParse(argString, out int setId)) ShowBeatmapSet(setId); break; case LinkAction.OpenChannel: - ShowChannel(link.Argument); + ShowChannel(argString); break; case LinkAction.SearchBeatmapSet: - SearchBeatmapSet(link.Argument); + SearchBeatmapSet(argString); break; case LinkAction.OpenEditorTimestamp: @@ -319,27 +323,31 @@ namespace osu.Game break; case LinkAction.External: - OpenUrlExternally(link.Argument); + OpenUrlExternally(argString); break; case LinkAction.OpenUserProfile: - if (int.TryParse(link.Argument, out int userId)) - ShowUser(userId); - else - ShowUser(link.Argument); + if (!(link.Argument is IUser user)) + { + user = int.TryParse(argString, out int userId) + ? new APIUser { Id = userId } + : new APIUser { Username = argString }; + } + + ShowUser(user); break; case LinkAction.OpenWiki: - ShowWiki(link.Argument); + ShowWiki(argString); break; case LinkAction.OpenChangelog: - if (string.IsNullOrEmpty(link.Argument)) + if (string.IsNullOrEmpty(argString)) ShowChangelogListing(); else { - string[] changelogArgs = link.Argument.Split("/"); + string[] changelogArgs = argString.Split("/"); ShowChangelogBuild(changelogArgs[0], changelogArgs[1]); } @@ -383,14 +391,8 @@ namespace osu.Game /// /// Show a user's profile as an overlay. /// - /// The user to display. - public void ShowUser(int userId) => waitForReady(() => userProfile, _ => userProfile.ShowUser(userId)); - - /// - /// Show a user's profile as an overlay. - /// - /// The user to display. - public void ShowUser(string username) => waitForReady(() => userProfile, _ => userProfile.ShowUser(username)); + /// The user to display. + public void ShowUser(IUser user) => waitForReady(() => userProfile, _ => userProfile.ShowUser(user)); /// /// Show a beatmap's set as an overlay, displaying the given beatmap. diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index f6ec22a536..e207d9ce3b 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -40,6 +40,7 @@ using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Scoring; using osu.Game.Skinning; +using osu.Game.Stores; using osu.Game.Utils; using RuntimeInfo = osu.Framework.RuntimeInfo; @@ -64,7 +65,7 @@ namespace osu.Game /// /// The maximum volume at which audio tracks should playback. This can be set lower than 1 to create some head-room for sound effects. /// - internal const double GLOBAL_TRACK_VOLUME_ADJUST = 0.8; + private const double global_track_volume_adjust = 0.8; public bool UseDevelopmentServer { get; } @@ -158,7 +159,9 @@ namespace osu.Game private Bindable fpsDisplayVisible; - private readonly BindableNumber globalTrackVolumeAdjust = new BindableNumber(GLOBAL_TRACK_VOLUME_ADJUST); + private readonly BindableNumber globalTrackVolumeAdjust = new BindableNumber(global_track_volume_adjust); + + private RealmRulesetStore realmRulesetStore; public OsuGameBase() { @@ -167,7 +170,7 @@ namespace osu.Game } [BackgroundDependencyLoader] - private void load() + private void load(ReadableKeyCombinationProvider keyCombinationProvider) { try { @@ -206,17 +209,11 @@ namespace osu.Game dependencies.CacheAs(SkinManager); // needs to be done here rather than inside SkinManager to ensure thread safety of CurrentSkinInfo. - SkinManager.ItemRemoved.BindValueChanged(weakRemovedInfo => + SkinManager.ItemRemoved += item => Schedule(() => { - if (weakRemovedInfo.NewValue.TryGetTarget(out var removedInfo)) - { - Schedule(() => - { - // check the removed skin is not the current user choice. if it is, switch back to default. - if (removedInfo.ID == SkinManager.CurrentSkinInfo.Value.ID) - SkinManager.CurrentSkinInfo.Value = SkinInfo.Default; - }); - } + // check the removed skin is not the current user choice. if it is, switch back to default. + if (item.ID == SkinManager.CurrentSkinInfo.Value.ID) + SkinManager.CurrentSkinInfo.Value = SkinInfo.Default; }); EndpointConfiguration endpoints = UseDevelopmentServer ? (EndpointConfiguration)new DevelopmentEndpointConfiguration() : new ProductionEndpointConfiguration(); @@ -237,6 +234,11 @@ namespace osu.Game dependencies.Cache(ScoreManager = new ScoreManager(RulesetStore, () => BeatmapManager, Storage, API, contextFactory, Scheduler, Host, () => difficultyCache, LocalConfig)); dependencies.Cache(BeatmapManager = new BeatmapManager(Storage, contextFactory, RulesetStore, API, Audio, Resources, Host, defaultBeatmap, performOnlineLookups: true)); + // the following realm components are not actively used yet, but initialised and kept up to date for initial testing. + realmRulesetStore = new RealmRulesetStore(realmFactory, Storage); + + dependencies.Cache(realmRulesetStore); + // this should likely be moved to ArchiveModelManager when another case appears where it is necessary // to have inter-dependent model managers. this could be obtained with an IHasForeign interface to // allow lookups to be done on the child (ScoreManager in this case) to perform the cascading delete. @@ -246,17 +248,8 @@ namespace osu.Game return ScoreManager.QueryScores(s => beatmapIds.Contains(s.BeatmapInfo.ID)).ToList(); } - BeatmapManager.ItemRemoved.BindValueChanged(i => - { - if (i.NewValue.TryGetTarget(out var item)) - ScoreManager.Delete(getBeatmapScores(item), true); - }); - - BeatmapManager.ItemUpdated.BindValueChanged(i => - { - if (i.NewValue.TryGetTarget(out var item)) - ScoreManager.Undelete(getBeatmapScores(item), true); - }); + BeatmapManager.ItemRemoved += item => ScoreManager.Delete(getBeatmapScores(item), true); + BeatmapManager.ItemUpdated += item => ScoreManager.Undelete(getBeatmapScores(item), true); dependencies.Cache(difficultyCache = new BeatmapDifficultyCache()); AddInternal(difficultyCache); @@ -316,13 +309,13 @@ namespace osu.Game base.Content.Add(CreateScalingContainer().WithChildren(mainContent)); - KeyBindingStore = new RealmKeyBindingStore(realmFactory); + KeyBindingStore = new RealmKeyBindingStore(realmFactory, keyCombinationProvider); KeyBindingStore.Register(globalBindings, RulesetStore.AvailableRulesets); dependencies.Cache(globalBindings); PreviewTrackManager previewTrackManager; - dependencies.Cache(previewTrackManager = new PreviewTrackManager()); + dependencies.Cache(previewTrackManager = new PreviewTrackManager(BeatmapManager.BeatmapTrackStore)); Add(previewTrackManager); AddInternal(MusicController = new MusicController()); @@ -527,6 +520,8 @@ namespace osu.Game LocalConfig?.Dispose(); contextFactory?.FlushConnections(); + + realmRulesetStore?.Dispose(); realmFactory?.Dispose(); } } diff --git a/osu.Game/Overlays/BeatmapSet/AuthorInfo.cs b/osu.Game/Overlays/BeatmapSet/AuthorInfo.cs index c90e2e2085..9131f6f74c 100644 --- a/osu.Game/Overlays/BeatmapSet/AuthorInfo.cs +++ b/osu.Game/Overlays/BeatmapSet/AuthorInfo.cs @@ -13,9 +13,9 @@ using osuTK.Graphics; using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Sprites; using osu.Game.Graphics; -using osu.Game.Users; using osu.Game.Graphics.Containers; using osu.Game.Online.API.Requests.Responses; +using APIUser = osu.Game.Online.API.Requests.Responses.APIUser; namespace osu.Game.Overlays.BeatmapSet { @@ -144,7 +144,7 @@ namespace osu.Game.Overlays.BeatmapSet }; } - public Field(string first, User second, FontUsage secondFont) + public Field(string first, APIUser second, FontUsage secondFont) { AutoSizeAxes = Axes.Both; Direction = FillDirection.Horizontal; diff --git a/osu.Game/Overlays/BeatmapSet/Buttons/FavouriteButton.cs b/osu.Game/Overlays/BeatmapSet/Buttons/FavouriteButton.cs index d4873f241c..8fe7450873 100644 --- a/osu.Game/Overlays/BeatmapSet/Buttons/FavouriteButton.cs +++ b/osu.Game/Overlays/BeatmapSet/Buttons/FavouriteButton.cs @@ -14,8 +14,8 @@ using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays.Notifications; using osu.Game.Resources.Localisation.Web; -using osu.Game.Users; using osuTK; +using APIUser = osu.Game.Online.API.Requests.Responses.APIUser; namespace osu.Game.Overlays.BeatmapSet.Buttons { @@ -28,7 +28,7 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons private PostBeatmapFavouriteRequest request; private LoadingLayer loading; - private readonly IBindable localUser = new Bindable(); + private readonly IBindable localUser = new Bindable(); public LocalisableString TooltipText { diff --git a/osu.Game/Overlays/BeatmapSet/Buttons/HeaderDownloadButton.cs b/osu.Game/Overlays/BeatmapSet/Buttons/HeaderDownloadButton.cs index bd7723d3c0..ee40f114d2 100644 --- a/osu.Game/Overlays/BeatmapSet/Buttons/HeaderDownloadButton.cs +++ b/osu.Game/Overlays/BeatmapSet/Buttons/HeaderDownloadButton.cs @@ -17,9 +17,9 @@ using osu.Game.Online.API; using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays.BeatmapListing.Panels; using osu.Game.Resources.Localisation.Web; -using osu.Game.Users; using osuTK; using osuTK.Graphics; +using APIUser = osu.Game.Online.API.Requests.Responses.APIUser; using CommonStrings = osu.Game.Localisation.CommonStrings; namespace osu.Game.Overlays.BeatmapSet.Buttons @@ -32,7 +32,7 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons public LocalisableString TooltipText => BeatmapsetsStrings.ShowDetailsDownloadDefault; - private readonly IBindable localUser = new Bindable(); + private readonly IBindable localUser = new Bindable(); private ShakeContainer shakeContainer; private HeaderButton button; @@ -165,7 +165,7 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons }, true); } - private void userChanged(ValueChangedEvent e) => button.Enabled.Value = !(e.NewValue is GuestUser); + private void userChanged(ValueChangedEvent e) => button.Enabled.Value = !(e.NewValue is GuestUser); private void enabledChanged(ValueChangedEvent e) => this.FadeColour(e.NewValue ? Color4.White : Color4.Gray, 200, Easing.OutQuint); diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs index 69739b3352..15e700fc91 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs @@ -18,8 +18,8 @@ using osu.Game.Online.API.Requests.Responses; using osu.Game.Rulesets; using osu.Game.Scoring; using osu.Game.Screens.Select.Leaderboards; -using osu.Game.Users; using osuTK; +using APIUser = osu.Game.Online.API.Requests.Responses.APIUser; namespace osu.Game.Overlays.BeatmapSet.Scores { @@ -30,7 +30,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores public readonly Bindable Beatmap = new Bindable(); private readonly Bindable ruleset = new Bindable(); private readonly Bindable scope = new Bindable(BeatmapLeaderboardScope.Global); - private readonly IBindable user = new Bindable(); + private readonly IBindable user = new Bindable(); private readonly Box background; private readonly ScoreTable scoreTable; @@ -227,7 +227,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores scope.Value = BeatmapLeaderboardScope.Global; } - private void onUserChanged(ValueChangedEvent user) + private void onUserChanged(ValueChangedEvent user) { if (modSelector.SelectedMods.Any()) modSelector.DeselectAll(); diff --git a/osu.Game/Overlays/Changelog/ChangelogEntry.cs b/osu.Game/Overlays/Changelog/ChangelogEntry.cs index 55edb40283..da062ca617 100644 --- a/osu.Game/Overlays/Changelog/ChangelogEntry.cs +++ b/osu.Game/Overlays/Changelog/ChangelogEntry.cs @@ -12,9 +12,9 @@ using osu.Framework.Graphics.Sprites; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Online.API.Requests.Responses; -using osu.Game.Users; using osuTK; using osuTK.Graphics; +using APIUser = osu.Game.Online.API.Requests.Responses.APIUser; namespace osu.Game.Overlays.Changelog { @@ -131,7 +131,7 @@ namespace osu.Game.Overlays.Changelog if (entry.GithubUser.UserId != null) { - title.AddUserLink(new User + title.AddUserLink(new APIUser { Username = entry.GithubUser.OsuUsername, Id = entry.GithubUser.UserId.Value diff --git a/osu.Game/Overlays/Chat/ChatLine.cs b/osu.Game/Overlays/Chat/ChatLine.cs index 6f4f568eb2..87d1b1a3ad 100644 --- a/osu.Game/Overlays/Chat/ChatLine.cs +++ b/osu.Game/Overlays/Chat/ChatLine.cs @@ -17,8 +17,8 @@ using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using osu.Game.Online.API; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Chat; -using osu.Game.Users; using osuTK; using osuTK.Graphics; @@ -209,7 +209,7 @@ namespace osu.Game.Overlays.Chat username.Text = $@"{message.Sender.Username}" + (senderHasBackground || message.IsAction ? "" : ":"); // remove non-existent channels from the link list - message.Links.RemoveAll(link => link.Action == LinkAction.OpenChannel && chatManager?.AvailableChannels.Any(c => c.Name == link.Argument) != true); + message.Links.RemoveAll(link => link.Action == LinkAction.OpenChannel && chatManager?.AvailableChannels.Any(c => c.Name == link.Argument.ToString()) != true); ContentFlow.Clear(); ContentFlow.AddLinks(message.DisplayContent, message.Links); @@ -217,14 +217,14 @@ namespace osu.Game.Overlays.Chat private class MessageSender : OsuClickableContainer, IHasContextMenu { - private readonly User sender; + private readonly APIUser sender; private Action startChatAction; [Resolved] private IAPIProvider api { get; set; } - public MessageSender(User sender) + public MessageSender(APIUser sender) { this.sender = sender; } @@ -240,7 +240,7 @@ namespace osu.Game.Overlays.Chat { get { - if (sender.Equals(User.SYSTEM_USER)) + if (sender.Equals(APIUser.SYSTEM_USER)) return Array.Empty(); List items = new List diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index 6b3d816e84..970fc5ccef 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -13,10 +13,10 @@ using System.Threading; using System.Linq; using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Threading; -using osu.Game.Users; using System.Collections.Generic; using JetBrains.Annotations; using osu.Game.Graphics.Sprites; +using APIUser = osu.Game.Online.API.Requests.Responses.APIUser; namespace osu.Game.Overlays.Comments { @@ -28,7 +28,7 @@ namespace osu.Game.Overlays.Comments public readonly Bindable Sort = new Bindable(); public readonly BindableBool ShowDeleted = new BindableBool(); - protected readonly IBindable User = new Bindable(); + protected readonly IBindable User = new Bindable(); [Resolved] private IAPIProvider api { get; set; } diff --git a/osu.Game/Overlays/Dashboard/CurrentlyPlayingDisplay.cs b/osu.Game/Overlays/Dashboard/CurrentlyPlayingDisplay.cs index 454dd500fe..269ed81bb5 100644 --- a/osu.Game/Overlays/Dashboard/CurrentlyPlayingDisplay.cs +++ b/osu.Game/Overlays/Dashboard/CurrentlyPlayingDisplay.cs @@ -10,6 +10,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Screens; using osu.Game.Database; using osu.Game.Online.API; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Spectator; using osu.Game.Screens.OnlinePlay.Match.Components; using osu.Game.Screens.Play; @@ -91,7 +92,7 @@ namespace osu.Game.Overlays.Dashboard } }); - private PlayingUserPanel createUserPanel(User user) => + private PlayingUserPanel createUserPanel(APIUser user) => new PlayingUserPanel(user).With(panel => { panel.Anchor = Anchor.TopCentre; @@ -100,12 +101,12 @@ namespace osu.Game.Overlays.Dashboard private class PlayingUserPanel : CompositeDrawable { - public readonly User User; + public readonly APIUser User; [Resolved(canBeNull: true)] private OsuGame game { get; set; } - public PlayingUserPanel(User user) + public PlayingUserPanel(APIUser user) { User = user; diff --git a/osu.Game/Overlays/Dashboard/Friends/FriendDisplay.cs b/osu.Game/Overlays/Dashboard/Friends/FriendDisplay.cs index 0922ce5ecc..765f037d70 100644 --- a/osu.Game/Overlays/Dashboard/Friends/FriendDisplay.cs +++ b/osu.Game/Overlays/Dashboard/Friends/FriendDisplay.cs @@ -11,6 +11,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics.UserInterface; using osu.Game.Online.API; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Users; using osuTK; @@ -18,9 +19,9 @@ namespace osu.Game.Overlays.Dashboard.Friends { public class FriendDisplay : CompositeDrawable { - private List users = new List(); + private List users = new List(); - public List Users + public List Users { get => users; set @@ -41,7 +42,7 @@ namespace osu.Game.Overlays.Dashboard.Friends private Container itemsPlaceholder; private LoadingLayer loading; - private readonly IBindableList apiFriends = new BindableList(); + private readonly IBindableList apiFriends = new BindableList(); public FriendDisplay() { @@ -169,7 +170,7 @@ namespace osu.Game.Overlays.Dashboard.Friends LoadComponentAsync(createTable(sortedUsers), addContentToPlaceholder, (cancellationToken = new CancellationTokenSource()).Token); } - private List getUsersInCurrentGroup() + private List getUsersInCurrentGroup() { switch (onlineStreamControl.Current.Value?.Status) { @@ -201,7 +202,7 @@ namespace osu.Game.Overlays.Dashboard.Friends currentContent.FadeIn(200, Easing.OutQuint); } - private FillFlowContainer createTable(List users) + private FillFlowContainer createTable(List users) { var style = userListToolbar.DisplayStyle.Value; @@ -214,7 +215,7 @@ namespace osu.Game.Overlays.Dashboard.Friends }; } - private UserPanel createUserPanel(User user, OverlayPanelDisplayStyle style) + private UserPanel createUserPanel(APIUser user, OverlayPanelDisplayStyle style) { switch (style) { @@ -235,7 +236,7 @@ namespace osu.Game.Overlays.Dashboard.Friends } } - private List sortUsers(List unsorted) + private List sortUsers(List unsorted) { switch (userListToolbar.SortCriteria.Value) { diff --git a/osu.Game/Overlays/Dashboard/Friends/FriendOnlineStreamControl.cs b/osu.Game/Overlays/Dashboard/Friends/FriendOnlineStreamControl.cs index d7f66e35b5..7275cdff7c 100644 --- a/osu.Game/Overlays/Dashboard/Friends/FriendOnlineStreamControl.cs +++ b/osu.Game/Overlays/Dashboard/Friends/FriendOnlineStreamControl.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.Linq; -using osu.Game.Users; +using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Overlays.Dashboard.Friends { @@ -11,7 +11,7 @@ namespace osu.Game.Overlays.Dashboard.Friends { protected override OverlayStreamItem CreateStreamItem(FriendStream value) => new FriendsOnlineStatusItem(value); - public void Populate(List users) + public void Populate(List users) { Clear(); diff --git a/osu.Game/Overlays/MusicController.cs b/osu.Game/Overlays/MusicController.cs index 97c7aaeaeb..829ff5be25 100644 --- a/osu.Game/Overlays/MusicController.cs +++ b/osu.Game/Overlays/MusicController.cs @@ -65,16 +65,11 @@ namespace osu.Game.Overlays [NotNull] public DrawableTrack CurrentTrack { get; private set; } = new DrawableTrack(new TrackVirtual(1000)); - private IBindable> managerUpdated; - private IBindable> managerRemoved; - [BackgroundDependencyLoader] private void load() { - managerUpdated = beatmaps.ItemUpdated.GetBoundCopy(); - managerUpdated.BindValueChanged(beatmapUpdated); - managerRemoved = beatmaps.ItemRemoved.GetBoundCopy(); - managerRemoved.BindValueChanged(beatmapRemoved); + beatmaps.ItemUpdated += beatmapUpdated; + beatmaps.ItemRemoved += beatmapRemoved; beatmapSets.AddRange(beatmaps.GetAllUsableBeatmapSets(IncludedDetails.Minimal, true).OrderBy(_ => RNG.Next())); @@ -110,28 +105,13 @@ namespace osu.Game.Overlays /// public bool TrackLoaded => CurrentTrack.TrackLoaded; - private void beatmapUpdated(ValueChangedEvent> weakSet) + private void beatmapUpdated(BeatmapSetInfo set) => Schedule(() => { - if (weakSet.NewValue.TryGetTarget(out var set)) - { - Schedule(() => - { - beatmapSets.Remove(set); - beatmapSets.Add(set); - }); - } - } + beatmapSets.Remove(set); + beatmapSets.Add(set); + }); - private void beatmapRemoved(ValueChangedEvent> weakSet) - { - if (weakSet.NewValue.TryGetTarget(out var set)) - { - Schedule(() => - { - beatmapSets.RemoveAll(s => s.ID == set.ID); - }); - } - } + private void beatmapRemoved(BeatmapSetInfo set) => Schedule(() => beatmapSets.RemoveAll(s => s.ID == set.ID)); private ScheduledDelegate seekDelegate; @@ -437,6 +417,17 @@ namespace osu.Game.Overlays mod.ApplyToTrack(CurrentTrack); } } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + if (beatmaps != null) + { + beatmaps.ItemUpdated -= beatmapUpdated; + beatmaps.ItemRemoved -= beatmapRemoved; + } + } } public enum TrackChangeDirection diff --git a/osu.Game/Overlays/Profile/Header/BottomHeaderContainer.cs b/osu.Game/Overlays/Profile/Header/BottomHeaderContainer.cs index fe61e532e1..ea52cec2e1 100644 --- a/osu.Game/Overlays/Profile/Header/BottomHeaderContainer.cs +++ b/osu.Game/Overlays/Profile/Header/BottomHeaderContainer.cs @@ -14,7 +14,7 @@ using osu.Framework.Graphics.Sprites; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Online.API; -using osu.Game.Users; +using osu.Game.Online.API.Requests.Responses; using osuTK; using osuTK.Graphics; @@ -22,7 +22,7 @@ namespace osu.Game.Overlays.Profile.Header { public class BottomHeaderContainer : CompositeDrawable { - public readonly Bindable User = new Bindable(); + public readonly Bindable User = new Bindable(); private LinkFlowContainer topLinkContainer; private LinkFlowContainer bottomLinkContainer; @@ -75,7 +75,7 @@ namespace osu.Game.Overlays.Profile.Header User.BindValueChanged(user => updateDisplay(user.NewValue)); } - private void updateDisplay(User user) + private void updateDisplay(APIUser user) { topLinkContainer.Clear(); bottomLinkContainer.Clear(); diff --git a/osu.Game/Overlays/Profile/Header/CentreHeaderContainer.cs b/osu.Game/Overlays/Profile/Header/CentreHeaderContainer.cs index 180a288729..a13f5ed6ce 100644 --- a/osu.Game/Overlays/Profile/Header/CentreHeaderContainer.cs +++ b/osu.Game/Overlays/Profile/Header/CentreHeaderContainer.cs @@ -9,9 +9,9 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Textures; using osu.Framework.Localisation; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays.Profile.Header.Components; using osu.Game.Resources.Localisation.Web; -using osu.Game.Users; using osuTK; namespace osu.Game.Overlays.Profile.Header @@ -19,7 +19,7 @@ namespace osu.Game.Overlays.Profile.Header public class CentreHeaderContainer : CompositeDrawable { public readonly BindableBool DetailsVisible = new BindableBool(true); - public readonly Bindable User = new Bindable(); + public readonly Bindable User = new Bindable(); private OverlinedInfoContainer hiddenDetailGlobal; private OverlinedInfoContainer hiddenDetailCountry; @@ -145,7 +145,7 @@ namespace osu.Game.Overlays.Profile.Header User.BindValueChanged(user => updateDisplay(user.NewValue)); } - private void updateDisplay(User user) + private void updateDisplay(APIUser user) { hiddenDetailGlobal.Content = user?.Statistics?.GlobalRank?.ToLocalisableString("\\##,##0") ?? (LocalisableString)"-"; hiddenDetailCountry.Content = user?.Statistics?.CountryRank?.ToLocalisableString("\\##,##0") ?? (LocalisableString)"-"; diff --git a/osu.Game/Overlays/Profile/Header/Components/FollowersButton.cs b/osu.Game/Overlays/Profile/Header/Components/FollowersButton.cs index 8f66120055..1b21bfc982 100644 --- a/osu.Game/Overlays/Profile/Header/Components/FollowersButton.cs +++ b/osu.Game/Overlays/Profile/Header/Components/FollowersButton.cs @@ -5,14 +5,14 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics.Sprites; using osu.Framework.Localisation; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Resources.Localisation.Web; -using osu.Game.Users; namespace osu.Game.Overlays.Profile.Header.Components { public class FollowersButton : ProfileHeaderStatisticsButton { - public readonly Bindable User = new Bindable(); + public readonly Bindable User = new Bindable(); public override LocalisableString TooltipText => FriendsStrings.ButtonsDisabled; diff --git a/osu.Game/Overlays/Profile/Header/Components/LevelBadge.cs b/osu.Game/Overlays/Profile/Header/Components/LevelBadge.cs index 1deed1a748..e1302788da 100644 --- a/osu.Game/Overlays/Profile/Header/Components/LevelBadge.cs +++ b/osu.Game/Overlays/Profile/Header/Components/LevelBadge.cs @@ -11,14 +11,14 @@ using osu.Framework.Graphics.Textures; using osu.Framework.Localisation; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Resources.Localisation.Web; -using osu.Game.Users; namespace osu.Game.Overlays.Profile.Header.Components { public class LevelBadge : CompositeDrawable, IHasTooltip { - public readonly Bindable User = new Bindable(); + public readonly Bindable User = new Bindable(); public LocalisableString TooltipText { get; private set; } @@ -51,7 +51,7 @@ namespace osu.Game.Overlays.Profile.Header.Components User.BindValueChanged(user => updateLevel(user.NewValue)); } - private void updateLevel(User user) + private void updateLevel(APIUser user) { levelText.Text = user?.Statistics?.Level.Current.ToString() ?? "0"; TooltipText = UsersStrings.ShowStatsLevel(user?.Statistics?.Level.Current.ToString()); diff --git a/osu.Game/Overlays/Profile/Header/Components/LevelProgressBar.cs b/osu.Game/Overlays/Profile/Header/Components/LevelProgressBar.cs index 2c8c421eba..8f6b935128 100644 --- a/osu.Game/Overlays/Profile/Header/Components/LevelProgressBar.cs +++ b/osu.Game/Overlays/Profile/Header/Components/LevelProgressBar.cs @@ -11,15 +11,15 @@ using osu.Framework.Localisation; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Resources.Localisation.Web; -using osu.Game.Users; using osuTK.Graphics; namespace osu.Game.Overlays.Profile.Header.Components { public class LevelProgressBar : CompositeDrawable, IHasTooltip { - public readonly Bindable User = new Bindable(); + public readonly Bindable User = new Bindable(); public LocalisableString TooltipText { get; } @@ -59,7 +59,7 @@ namespace osu.Game.Overlays.Profile.Header.Components User.BindValueChanged(user => updateProgress(user.NewValue)); } - private void updateProgress(User user) + private void updateProgress(APIUser user) { levelProgressBar.Length = user?.Statistics?.Level.Progress / 100f ?? 0; levelProgressText.Text = user?.Statistics?.Level.Progress.ToLocalisableString("0'%'"); diff --git a/osu.Game/Overlays/Profile/Header/Components/MappingSubscribersButton.cs b/osu.Game/Overlays/Profile/Header/Components/MappingSubscribersButton.cs index 5cdf3a5ef9..6d1024ff18 100644 --- a/osu.Game/Overlays/Profile/Header/Components/MappingSubscribersButton.cs +++ b/osu.Game/Overlays/Profile/Header/Components/MappingSubscribersButton.cs @@ -5,14 +5,14 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics.Sprites; using osu.Framework.Localisation; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Resources.Localisation.Web; -using osu.Game.Users; namespace osu.Game.Overlays.Profile.Header.Components { public class MappingSubscribersButton : ProfileHeaderStatisticsButton { - public readonly Bindable User = new Bindable(); + public readonly Bindable User = new Bindable(); public override LocalisableString TooltipText => FollowsStrings.MappingFollowers; diff --git a/osu.Game/Overlays/Profile/Header/Components/MessageUserButton.cs b/osu.Game/Overlays/Profile/Header/Components/MessageUserButton.cs index 07f1f1c3ed..e3dc5f818a 100644 --- a/osu.Game/Overlays/Profile/Header/Components/MessageUserButton.cs +++ b/osu.Game/Overlays/Profile/Header/Components/MessageUserButton.cs @@ -7,16 +7,16 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; using osu.Framework.Localisation; using osu.Game.Online.API; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Chat; using osu.Game.Resources.Localisation.Web; -using osu.Game.Users; using osuTK; namespace osu.Game.Overlays.Profile.Header.Components { public class MessageUserButton : ProfileHeaderButton { - public readonly Bindable User = new Bindable(); + public readonly Bindable User = new Bindable(); public override LocalisableString TooltipText => UsersStrings.CardSendMessage; diff --git a/osu.Game/Overlays/Profile/Header/Components/OverlinedTotalPlayTime.cs b/osu.Game/Overlays/Profile/Header/Components/OverlinedTotalPlayTime.cs index 1a40944632..1ead2cd2f5 100644 --- a/osu.Game/Overlays/Profile/Header/Components/OverlinedTotalPlayTime.cs +++ b/osu.Game/Overlays/Profile/Header/Components/OverlinedTotalPlayTime.cs @@ -7,14 +7,14 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Cursor; using osu.Framework.Localisation; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Resources.Localisation.Web; -using osu.Game.Users; namespace osu.Game.Overlays.Profile.Header.Components { public class OverlinedTotalPlayTime : CompositeDrawable, IHasTooltip { - public readonly Bindable User = new Bindable(); + public readonly Bindable User = new Bindable(); public LocalisableString TooltipText { get; set; } @@ -39,7 +39,7 @@ namespace osu.Game.Overlays.Profile.Header.Components User.BindValueChanged(updateTime, true); } - private void updateTime(ValueChangedEvent user) + private void updateTime(ValueChangedEvent user) { TooltipText = (user.NewValue?.Statistics?.PlayTime ?? 0) / 3600 + " hours"; info.Content = formatTime(user.NewValue?.Statistics?.PlayTime); diff --git a/osu.Game/Overlays/Profile/Header/Components/PreviousUsernames.cs b/osu.Game/Overlays/Profile/Header/Components/PreviousUsernames.cs index b1076ba39b..229bbaef83 100644 --- a/osu.Game/Overlays/Profile/Header/Components/PreviousUsernames.cs +++ b/osu.Game/Overlays/Profile/Header/Components/PreviousUsernames.cs @@ -12,8 +12,8 @@ using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Events; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Resources.Localisation.Web; -using osu.Game.Users; using osuTK; namespace osu.Game.Overlays.Profile.Header.Components @@ -25,7 +25,7 @@ namespace osu.Game.Overlays.Profile.Header.Components private const int width = 310; private const int move_offset = 15; - public readonly Bindable User = new Bindable(); + public readonly Bindable User = new Bindable(); private readonly TextFlowContainer text; private readonly Box background; @@ -107,7 +107,7 @@ namespace osu.Game.Overlays.Profile.Header.Components User.BindValueChanged(onUserChanged, true); } - private void onUserChanged(ValueChangedEvent user) + private void onUserChanged(ValueChangedEvent user) { text.Text = string.Empty; diff --git a/osu.Game/Overlays/Profile/Header/Components/ProfileRulesetSelector.cs b/osu.Game/Overlays/Profile/Header/Components/ProfileRulesetSelector.cs index 41a3ee8ad6..eaa9703834 100644 --- a/osu.Game/Overlays/Profile/Header/Components/ProfileRulesetSelector.cs +++ b/osu.Game/Overlays/Profile/Header/Components/ProfileRulesetSelector.cs @@ -3,14 +3,14 @@ using osu.Framework.Bindables; using osu.Framework.Graphics.UserInterface; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Rulesets; -using osu.Game.Users; namespace osu.Game.Overlays.Profile.Header.Components { public class ProfileRulesetSelector : OverlayRulesetSelector { - public readonly Bindable User = new Bindable(); + public readonly Bindable User = new Bindable(); protected override void LoadComplete() { diff --git a/osu.Game/Overlays/Profile/Header/DetailHeaderContainer.cs b/osu.Game/Overlays/Profile/Header/DetailHeaderContainer.cs index 8ca6961950..79e553062d 100644 --- a/osu.Game/Overlays/Profile/Header/DetailHeaderContainer.cs +++ b/osu.Game/Overlays/Profile/Header/DetailHeaderContainer.cs @@ -11,11 +11,11 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Localisation; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Leaderboards; using osu.Game.Overlays.Profile.Header.Components; using osu.Game.Resources.Localisation.Web; using osu.Game.Scoring; -using osu.Game.Users; using osuTK; namespace osu.Game.Overlays.Profile.Header @@ -30,7 +30,7 @@ namespace osu.Game.Overlays.Profile.Header private FillFlowContainer fillFlow; private RankGraph rankGraph; - public readonly Bindable User = new Bindable(); + public readonly Bindable User = new Bindable(); private bool expanded = true; @@ -171,7 +171,7 @@ namespace osu.Game.Overlays.Profile.Header }; } - private void updateDisplay(User user) + private void updateDisplay(APIUser user) { medalInfo.Content = user?.Achievements?.Length.ToString() ?? "0"; ppInfo.Content = user?.Statistics?.PP?.ToLocalisableString("#,##0") ?? (LocalisableString)"0"; diff --git a/osu.Game/Overlays/Profile/Header/MedalHeaderContainer.cs b/osu.Game/Overlays/Profile/Header/MedalHeaderContainer.cs index f6419db540..5f513582e5 100644 --- a/osu.Game/Overlays/Profile/Header/MedalHeaderContainer.cs +++ b/osu.Game/Overlays/Profile/Header/MedalHeaderContainer.cs @@ -8,8 +8,8 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays.Profile.Header.Components; -using osu.Game.Users; using osuTK; using osuTK.Graphics; @@ -19,7 +19,7 @@ namespace osu.Game.Overlays.Profile.Header { private FillFlowContainer badgeFlowContainer; - public readonly Bindable User = new Bindable(); + public readonly Bindable User = new Bindable(); [BackgroundDependencyLoader] private void load(OverlayColourProvider colourProvider) @@ -63,7 +63,7 @@ namespace osu.Game.Overlays.Profile.Header }; } - private void updateDisplay(User user) + private void updateDisplay(APIUser user) { var badges = user.Badges; badgeFlowContainer.Clear(); diff --git a/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs b/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs index f5720cffb0..6ba5cb2f7f 100644 --- a/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs +++ b/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs @@ -13,9 +13,9 @@ using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using osu.Game.Online.API; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays.Profile.Header.Components; using osu.Game.Resources.Localisation.Web; -using osu.Game.Users; using osu.Game.Users.Drawables; using osuTK; @@ -25,7 +25,7 @@ namespace osu.Game.Overlays.Profile.Header { private const float avatar_size = 110; - public readonly Bindable User = new Bindable(); + public readonly Bindable User = new Bindable(); [Resolved] private IAPIProvider api { get; set; } @@ -167,7 +167,7 @@ namespace osu.Game.Overlays.Profile.Header User.BindValueChanged(user => updateUser(user.NewValue)); } - private void updateUser(User user) + private void updateUser(APIUser user) { avatar.User = user; usernameText.Text = user?.Username ?? string.Empty; diff --git a/osu.Game/Overlays/Profile/ProfileHeader.cs b/osu.Game/Overlays/Profile/ProfileHeader.cs index 815f9fdafc..fab2487c0d 100644 --- a/osu.Game/Overlays/Profile/ProfileHeader.cs +++ b/osu.Game/Overlays/Profile/ProfileHeader.cs @@ -8,6 +8,7 @@ using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Localisation; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays.Profile.Header; using osu.Game.Resources.Localisation.Web; using osu.Game.Users; @@ -18,7 +19,7 @@ namespace osu.Game.Overlays.Profile { private UserCoverBackground coverContainer; - public Bindable User = new Bindable(); + public Bindable User = new Bindable(); private CentreHeaderContainer centreHeaderContainer; private DetailHeaderContainer detailHeaderContainer; @@ -92,7 +93,7 @@ namespace osu.Game.Overlays.Profile protected override OverlayTitle CreateTitle() => new ProfileHeaderTitle(); - private void updateDisplay(User user) => coverContainer.User = user; + private void updateDisplay(APIUser user) => coverContainer.User = user; private class ProfileHeaderTitle : OverlayTitle { diff --git a/osu.Game/Overlays/Profile/ProfileSection.cs b/osu.Game/Overlays/Profile/ProfileSection.cs index 1a5f562fff..6223b32814 100644 --- a/osu.Game/Overlays/Profile/ProfileSection.cs +++ b/osu.Game/Overlays/Profile/ProfileSection.cs @@ -12,7 +12,7 @@ using osu.Framework.Localisation; using osu.Game.Graphics; using osu.Game.Graphics.Backgrounds; using osu.Game.Graphics.Sprites; -using osu.Game.Users; +using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Overlays.Profile { @@ -28,7 +28,7 @@ namespace osu.Game.Overlays.Profile protected override Container Content => content; - public readonly Bindable User = new Bindable(); + public readonly Bindable User = new Bindable(); protected ProfileSection() { diff --git a/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs b/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs index fffa20dc11..36b94283e5 100644 --- a/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs @@ -10,8 +10,8 @@ using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays.BeatmapListing.Panels; -using osu.Game.Users; using osuTK; +using APIUser = osu.Game.Online.API.Requests.Responses.APIUser; namespace osu.Game.Overlays.Profile.Sections.Beatmaps { @@ -20,7 +20,7 @@ namespace osu.Game.Overlays.Profile.Sections.Beatmaps private const float panel_padding = 10f; private readonly BeatmapSetType type; - public PaginatedBeatmapContainer(BeatmapSetType type, Bindable user, LocalisableString headerText) + public PaginatedBeatmapContainer(BeatmapSetType type, Bindable user, LocalisableString headerText) : base(user, headerText) { this.type = type; @@ -33,7 +33,7 @@ namespace osu.Game.Overlays.Profile.Sections.Beatmaps ItemsContainer.Spacing = new Vector2(panel_padding); } - protected override int GetCount(User user) + protected override int GetCount(APIUser user) { switch (type) { diff --git a/osu.Game/Overlays/Profile/Sections/Historical/ChartProfileSubsection.cs b/osu.Game/Overlays/Profile/Sections/Historical/ChartProfileSubsection.cs index 986b3d9874..4edbdc31bd 100644 --- a/osu.Game/Overlays/Profile/Sections/Historical/ChartProfileSubsection.cs +++ b/osu.Game/Overlays/Profile/Sections/Historical/ChartProfileSubsection.cs @@ -7,8 +7,7 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Localisation; -using osu.Game.Users; -using static osu.Game.Users.User; +using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Overlays.Profile.Sections.Historical { @@ -21,7 +20,7 @@ namespace osu.Game.Overlays.Profile.Sections.Historical /// protected abstract LocalisableString GraphCounterName { get; } - protected ChartProfileSubsection(Bindable user, LocalisableString headerText) + protected ChartProfileSubsection(Bindable user, LocalisableString headerText) : base(user, headerText) { } @@ -45,7 +44,7 @@ namespace osu.Game.Overlays.Profile.Sections.Historical User.BindValueChanged(onUserChanged, true); } - private void onUserChanged(ValueChangedEvent e) + private void onUserChanged(ValueChangedEvent e) { var values = GetValues(e.NewValue); @@ -62,9 +61,9 @@ namespace osu.Game.Overlays.Profile.Sections.Historical /// /// Add entries for any missing months (filled with zero values). /// - private UserHistoryCount[] fillZeroValues(UserHistoryCount[] historyEntries) + private APIUserHistoryCount[] fillZeroValues(APIUserHistoryCount[] historyEntries) { - var filledHistoryEntries = new List(); + var filledHistoryEntries = new List(); foreach (var entry in historyEntries) { @@ -72,7 +71,7 @@ namespace osu.Game.Overlays.Profile.Sections.Historical while (lastFilled?.Date.AddMonths(1) < entry.Date) { - filledHistoryEntries.Add(lastFilled = new UserHistoryCount + filledHistoryEntries.Add(lastFilled = new APIUserHistoryCount { Count = 0, Date = lastFilled.Date.AddMonths(1) @@ -85,6 +84,6 @@ namespace osu.Game.Overlays.Profile.Sections.Historical return filledHistoryEntries.ToArray(); } - protected abstract UserHistoryCount[] GetValues(User user); + protected abstract APIUserHistoryCount[] GetValues(APIUser user); } } diff --git a/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs b/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs index 428d04f985..c943d129cc 100644 --- a/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs @@ -10,13 +10,13 @@ using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests.Responses; using osu.Game.Resources.Localisation.Web; -using osu.Game.Users; +using APIUser = osu.Game.Online.API.Requests.Responses.APIUser; namespace osu.Game.Overlays.Profile.Sections.Historical { public class PaginatedMostPlayedBeatmapContainer : PaginatedProfileSubsection { - public PaginatedMostPlayedBeatmapContainer(Bindable user) + public PaginatedMostPlayedBeatmapContainer(Bindable user) : base(user, UsersStrings.ShowExtraHistoricalMostPlayedTitle) { ItemsPerPage = 5; @@ -28,7 +28,7 @@ namespace osu.Game.Overlays.Profile.Sections.Historical ItemsContainer.Direction = FillDirection.Vertical; } - protected override int GetCount(User user) => user.BeatmapPlaycountsCount; + protected override int GetCount(APIUser user) => user.BeatmapPlaycountsCount; protected override APIRequest> CreateRequest() => new GetUserMostPlayedBeatmapsRequest(User.Value.Id, VisiblePages++, ItemsPerPage); diff --git a/osu.Game/Overlays/Profile/Sections/Historical/PlayHistorySubsection.cs b/osu.Game/Overlays/Profile/Sections/Historical/PlayHistorySubsection.cs index 83c005970e..bca88318d5 100644 --- a/osu.Game/Overlays/Profile/Sections/Historical/PlayHistorySubsection.cs +++ b/osu.Game/Overlays/Profile/Sections/Historical/PlayHistorySubsection.cs @@ -3,9 +3,8 @@ using osu.Framework.Bindables; using osu.Framework.Localisation; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Resources.Localisation.Web; -using osu.Game.Users; -using static osu.Game.Users.User; namespace osu.Game.Overlays.Profile.Sections.Historical { @@ -13,11 +12,11 @@ namespace osu.Game.Overlays.Profile.Sections.Historical { protected override LocalisableString GraphCounterName => UsersStrings.ShowExtraHistoricalMonthlyPlaycountsCountLabel; - public PlayHistorySubsection(Bindable user) + public PlayHistorySubsection(Bindable user) : base(user, UsersStrings.ShowExtraHistoricalMonthlyPlaycountsTitle) { } - protected override UserHistoryCount[] GetValues(User user) => user?.MonthlyPlaycounts; + protected override APIUserHistoryCount[] GetValues(APIUser user) => user?.MonthlyPlaycounts; } } diff --git a/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs b/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs index d402438376..c049bff7b2 100644 --- a/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs +++ b/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs @@ -14,16 +14,16 @@ using osu.Game.Graphics; using osu.Framework.Graphics.Shapes; using osuTK; using osu.Framework.Localisation; -using static osu.Game.Users.User; +using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Overlays.Profile.Sections.Historical { public class ProfileLineChart : CompositeDrawable { - private UserHistoryCount[] values; + private APIUserHistoryCount[] values; [NotNull] - public UserHistoryCount[] Values + public APIUserHistoryCount[] Values { get => values; set diff --git a/osu.Game/Overlays/Profile/Sections/Historical/ReplaysSubsection.cs b/osu.Game/Overlays/Profile/Sections/Historical/ReplaysSubsection.cs index 76d5f73bd7..22312afdc9 100644 --- a/osu.Game/Overlays/Profile/Sections/Historical/ReplaysSubsection.cs +++ b/osu.Game/Overlays/Profile/Sections/Historical/ReplaysSubsection.cs @@ -3,9 +3,8 @@ using osu.Framework.Bindables; using osu.Framework.Localisation; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Resources.Localisation.Web; -using osu.Game.Users; -using static osu.Game.Users.User; namespace osu.Game.Overlays.Profile.Sections.Historical { @@ -13,11 +12,11 @@ namespace osu.Game.Overlays.Profile.Sections.Historical { protected override LocalisableString GraphCounterName => UsersStrings.ShowExtraHistoricalReplaysWatchedCountsCountLabel; - public ReplaysSubsection(Bindable user) + public ReplaysSubsection(Bindable user) : base(user, UsersStrings.ShowExtraHistoricalReplaysWatchedCountsTitle) { } - protected override UserHistoryCount[] GetValues(User user) => user?.ReplaysWatchedCounts; + protected override APIUserHistoryCount[] GetValues(APIUser user) => user?.ReplaysWatchedCounts; } } diff --git a/osu.Game/Overlays/Profile/Sections/Historical/UserHistoryGraph.cs b/osu.Game/Overlays/Profile/Sections/Historical/UserHistoryGraph.cs index 61f77cd6ff..f80167f9d3 100644 --- a/osu.Game/Overlays/Profile/Sections/Historical/UserHistoryGraph.cs +++ b/osu.Game/Overlays/Profile/Sections/Historical/UserHistoryGraph.cs @@ -7,7 +7,7 @@ using System.Linq; using JetBrains.Annotations; using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Localisation; -using static osu.Game.Users.User; +using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Overlays.Profile.Sections.Historical { @@ -16,7 +16,7 @@ namespace osu.Game.Overlays.Profile.Sections.Historical private readonly LocalisableString tooltipCounterName; [CanBeNull] - public UserHistoryCount[] Values + public APIUserHistoryCount[] Values { set => Data = value?.Select(v => new KeyValuePair(v.Date, v.Count)).ToArray(); } diff --git a/osu.Game/Overlays/Profile/Sections/Kudosu/KudosuInfo.cs b/osu.Game/Overlays/Profile/Sections/Kudosu/KudosuInfo.cs index 762716efab..79a06ecdd4 100644 --- a/osu.Game/Overlays/Profile/Sections/Kudosu/KudosuInfo.cs +++ b/osu.Game/Overlays/Profile/Sections/Kudosu/KudosuInfo.cs @@ -10,19 +10,19 @@ using osu.Framework.Input.Events; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; -using osu.Game.Users; using osu.Framework.Allocation; using osu.Framework.Extensions.LocalisationExtensions; using osu.Game.Resources.Localisation.Web; using osu.Framework.Localisation; +using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Overlays.Profile.Sections.Kudosu { public class KudosuInfo : Container { - private readonly Bindable user = new Bindable(); + private readonly Bindable user = new Bindable(); - public KudosuInfo(Bindable user) + public KudosuInfo(Bindable user) { this.user.BindTo(user); CountSection total; diff --git a/osu.Game/Overlays/Profile/Sections/Kudosu/PaginatedKudosuHistoryContainer.cs b/osu.Game/Overlays/Profile/Sections/Kudosu/PaginatedKudosuHistoryContainer.cs index 76cd7ed722..c4837cc0e2 100644 --- a/osu.Game/Overlays/Profile/Sections/Kudosu/PaginatedKudosuHistoryContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Kudosu/PaginatedKudosuHistoryContainer.cs @@ -3,18 +3,18 @@ using osu.Framework.Graphics; using osu.Game.Online.API.Requests; -using osu.Game.Users; using osu.Framework.Bindables; using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.API; using System.Collections.Generic; using osu.Game.Resources.Localisation.Web; +using APIUser = osu.Game.Online.API.Requests.Responses.APIUser; namespace osu.Game.Overlays.Profile.Sections.Kudosu { public class PaginatedKudosuHistoryContainer : PaginatedProfileSubsection { - public PaginatedKudosuHistoryContainer(Bindable user) + public PaginatedKudosuHistoryContainer(Bindable user) : base(user, missingText: UsersStrings.ShowExtraKudosuEntryEmpty) { ItemsPerPage = 5; diff --git a/osu.Game/Overlays/Profile/Sections/PaginatedProfileSubsection.cs b/osu.Game/Overlays/Profile/Sections/PaginatedProfileSubsection.cs index d60243cd0a..affe9ecb0c 100644 --- a/osu.Game/Overlays/Profile/Sections/PaginatedProfileSubsection.cs +++ b/osu.Game/Overlays/Profile/Sections/PaginatedProfileSubsection.cs @@ -7,7 +7,6 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Online.API; -using osu.Game.Users; using System.Collections.Generic; using System.Linq; using System.Threading; @@ -16,6 +15,7 @@ using osu.Game.Rulesets; using osu.Game.Graphics.Sprites; using osu.Game.Graphics; using osu.Framework.Localisation; +using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Overlays.Profile.Sections { @@ -39,7 +39,7 @@ namespace osu.Game.Overlays.Profile.Sections private OsuSpriteText missing; private readonly LocalisableString? missingText; - protected PaginatedProfileSubsection(Bindable user, LocalisableString? headerText = null, LocalisableString? missingText = null) + protected PaginatedProfileSubsection(Bindable user, LocalisableString? headerText = null, LocalisableString? missingText = null) : base(user, headerText, CounterVisibilityState.AlwaysVisible) { this.missingText = missingText; @@ -81,7 +81,7 @@ namespace osu.Game.Overlays.Profile.Sections User.BindValueChanged(onUserChanged, true); } - private void onUserChanged(ValueChangedEvent e) + private void onUserChanged(ValueChangedEvent e) { loadCancellation?.Cancel(); retrievalRequest?.Cancel(); @@ -131,7 +131,7 @@ namespace osu.Game.Overlays.Profile.Sections }, loadCancellation.Token); }); - protected virtual int GetCount(User user) => 0; + protected virtual int GetCount(APIUser user) => 0; protected virtual void OnItemsReceived(List items) { diff --git a/osu.Game/Overlays/Profile/Sections/ProfileSubsection.cs b/osu.Game/Overlays/Profile/Sections/ProfileSubsection.cs index 5a17f0d8bb..fdf8cb19ff 100644 --- a/osu.Game/Overlays/Profile/Sections/ProfileSubsection.cs +++ b/osu.Game/Overlays/Profile/Sections/ProfileSubsection.cs @@ -5,22 +5,22 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Game.Users; using JetBrains.Annotations; using osu.Framework.Localisation; +using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Overlays.Profile.Sections { public abstract class ProfileSubsection : FillFlowContainer { - protected readonly Bindable User = new Bindable(); + protected readonly Bindable User = new Bindable(); private readonly LocalisableString headerText; private readonly CounterVisibilityState counterVisibilityState; private ProfileSubsectionHeader header; - protected ProfileSubsection(Bindable user, LocalisableString? headerText = null, CounterVisibilityState counterVisibilityState = CounterVisibilityState.AlwaysHidden) + protected ProfileSubsection(Bindable user, LocalisableString? headerText = null, CounterVisibilityState counterVisibilityState = CounterVisibilityState.AlwaysHidden) { this.headerText = headerText ?? string.Empty; this.counterVisibilityState = counterVisibilityState; diff --git a/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs b/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs index cde386bc7b..c3f10587a9 100644 --- a/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs @@ -3,7 +3,6 @@ using osu.Framework.Graphics.Containers; using osu.Game.Online.API.Requests; -using osu.Game.Users; using System; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -12,6 +11,7 @@ using System.Collections.Generic; using osu.Game.Online.API; using osu.Framework.Allocation; using osu.Framework.Localisation; +using APIUser = osu.Game.Online.API.Requests.Responses.APIUser; namespace osu.Game.Overlays.Profile.Sections.Ranks { @@ -19,7 +19,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks { private readonly ScoreType type; - public PaginatedScoreContainer(ScoreType type, Bindable user, LocalisableString headerText) + public PaginatedScoreContainer(ScoreType type, Bindable user, LocalisableString headerText) : base(user, headerText) { this.type = type; @@ -33,7 +33,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks ItemsContainer.Direction = FillDirection.Vertical; } - protected override int GetCount(User user) + protected override int GetCount(APIUser user) { switch (type) { diff --git a/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs b/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs index 49b46f7e7a..cb8dae0bbc 100644 --- a/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs +++ b/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs @@ -216,7 +216,7 @@ namespace osu.Game.Overlays.Profile.Sections.Recent private void addBeatmapsetLink() => content.AddLink(activity.Beatmapset?.Title, LinkAction.OpenBeatmapSet, getLinkArgument(activity.Beatmapset?.Url), creationParameters: t => t.Font = getLinkFont()); - private string getLinkArgument(string url) => MessageFormatter.GetLinkDetails($"{api.APIEndpointUrl}{url}").Argument; + private string getLinkArgument(string url) => MessageFormatter.GetLinkDetails($"{api.APIEndpointUrl}{url}").Argument.ToString(); private FontUsage getLinkFont(FontWeight fontWeight = FontWeight.Regular) => OsuFont.GetFont(size: font_size, weight: fontWeight, italics: true); diff --git a/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs b/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs index db2e6bc1e0..c5ff896654 100644 --- a/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs @@ -3,7 +3,6 @@ using osu.Framework.Graphics; using osu.Game.Online.API.Requests; -using osu.Game.Users; using osu.Framework.Bindables; using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.API; @@ -11,12 +10,13 @@ using System.Collections.Generic; using osuTK; using osu.Framework.Allocation; using osu.Game.Resources.Localisation.Web; +using APIUser = osu.Game.Online.API.Requests.Responses.APIUser; namespace osu.Game.Overlays.Profile.Sections.Recent { public class PaginatedRecentActivityContainer : PaginatedProfileSubsection { - public PaginatedRecentActivityContainer(Bindable user) + public PaginatedRecentActivityContainer(Bindable user) : base(user, missingText: EventsStrings.Empty) { ItemsPerPage = 10; diff --git a/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.cs b/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.cs index f44f02d0ed..96a685a9c5 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.cs @@ -12,6 +12,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Shapes; +using osu.Framework.Input; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; using osu.Game.Database; @@ -57,13 +58,16 @@ namespace osu.Game.Overlays.Settings.Sections.Input public bool FilteringActive { get; set; } + [Resolved] + private ReadableKeyCombinationProvider keyCombinationProvider { get; set; } + private OsuSpriteText text; private FillFlowContainer cancelAndClearButtons; private FillFlowContainer buttons; private Bindable isDefault { get; } = new BindableBool(true); - public IEnumerable FilterTerms => bindings.Select(b => b.KeyCombination.ReadableString()).Prepend(text.Text.ToString()); + public IEnumerable FilterTerms => bindings.Select(b => keyCombinationProvider.GetReadableString(b.KeyCombination)).Prepend(text.Text.ToString()); public KeyBindingRow(object action, List bindings) { @@ -149,12 +153,12 @@ namespace osu.Game.Overlays.Settings.Sections.Input new CancelButton { Action = finalise }, new ClearButton { Action = clear }, }, - } + }, + new HoverClickSounds() } } } - }, - new HoverClickSounds() + } }; foreach (var b in bindings) @@ -422,6 +426,9 @@ namespace osu.Game.Overlays.Settings.Sections.Input [Resolved] private OverlayColourProvider colourProvider { get; set; } + [Resolved] + private ReadableKeyCombinationProvider keyCombinationProvider { get; set; } + private bool isBinding; public bool IsBinding @@ -470,12 +477,19 @@ namespace osu.Game.Overlays.Settings.Sections.Input Margin = new MarginPadding(5), Anchor = Anchor.Centre, Origin = Anchor.Centre, - Text = keyBinding.KeyCombination.ReadableString(), }, new HoverSounds() }; } + protected override void LoadComplete() + { + base.LoadComplete(); + + keyCombinationProvider.KeymapChanged += updateKeyCombinationText; + updateKeyCombinationText(); + } + [BackgroundDependencyLoader] private void load() { @@ -514,7 +528,22 @@ namespace osu.Game.Overlays.Settings.Sections.Input return; KeyBinding.KeyCombination = newCombination; - Text.Text = KeyBinding.KeyCombination.ReadableString(); + updateKeyCombinationText(); + } + + private void updateKeyCombinationText() + { + Scheduler.AddOnce(updateText); + + void updateText() => Text.Text = keyCombinationProvider.GetReadableString(KeyBinding.KeyCombination); + } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + if (keyCombinationProvider != null) + keyCombinationProvider.KeymapChanged -= updateKeyCombinationText; } } } diff --git a/osu.Game/Overlays/Settings/Sections/SkinSection.cs b/osu.Game/Overlays/Settings/Sections/SkinSection.cs index cf5d70ba91..0714b28b47 100644 --- a/osu.Game/Overlays/Settings/Sections/SkinSection.cs +++ b/osu.Game/Overlays/Settings/Sections/SkinSection.cs @@ -56,9 +56,6 @@ namespace osu.Game.Overlays.Settings.Sections [Resolved] private SkinManager skins { get; set; } - private IBindable> managerUpdated; - private IBindable> managerRemoved; - [BackgroundDependencyLoader(permitNulls: true)] private void load(OsuConfigManager config, [CanBeNull] SkinEditorOverlay skinEditor) { @@ -76,11 +73,8 @@ namespace osu.Game.Overlays.Settings.Sections new ExportSkinButton(), }; - managerUpdated = skins.ItemUpdated.GetBoundCopy(); - managerUpdated.BindValueChanged(itemUpdated); - - managerRemoved = skins.ItemRemoved.GetBoundCopy(); - managerRemoved.BindValueChanged(itemRemoved); + skins.ItemUpdated += itemUpdated; + skins.ItemRemoved += itemRemoved; config.BindWith(OsuSetting.Skin, configBindable); @@ -129,11 +123,7 @@ namespace osu.Game.Overlays.Settings.Sections skinDropdown.Items = skinItems; } - private void itemUpdated(ValueChangedEvent> weakItem) - { - if (weakItem.NewValue.TryGetTarget(out var item)) - Schedule(() => addItem(item)); - } + private void itemUpdated(SkinInfo item) => Schedule(() => addItem(item)); private void addItem(SkinInfo item) { @@ -142,11 +132,7 @@ namespace osu.Game.Overlays.Settings.Sections skinDropdown.Items = newDropdownItems; } - private void itemRemoved(ValueChangedEvent> weakItem) - { - if (weakItem.NewValue.TryGetTarget(out var item)) - Schedule(() => skinDropdown.Items = skinDropdown.Items.Where(i => i.ID != item.ID).ToArray()); - } + private void itemRemoved(SkinInfo item) => Schedule(() => skinDropdown.Items = skinDropdown.Items.Where(i => i.ID != item.ID).ToArray()); private void sortUserSkins(List skinsList) { @@ -155,6 +141,17 @@ namespace osu.Game.Overlays.Settings.Sections Comparer.Create((a, b) => string.Compare(a.Name, b.Name, StringComparison.OrdinalIgnoreCase))); } + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + if (skins != null) + { + skins.ItemUpdated -= itemUpdated; + skins.ItemRemoved -= itemRemoved; + } + } + private class SkinSettingsDropdown : SettingsDropdown { protected override OsuDropdown CreateDropdown() => new SkinDropdownControl(); diff --git a/osu.Game/Overlays/Settings/Sections/UserInterface/MainMenuSettings.cs b/osu.Game/Overlays/Settings/Sections/UserInterface/MainMenuSettings.cs index 40485a070c..284e9cb2de 100644 --- a/osu.Game/Overlays/Settings/Sections/UserInterface/MainMenuSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/UserInterface/MainMenuSettings.cs @@ -8,7 +8,7 @@ using osu.Framework.Localisation; using osu.Game.Configuration; using osu.Game.Localisation; using osu.Game.Online.API; -using osu.Game.Users; +using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Overlays.Settings.Sections.UserInterface { @@ -16,7 +16,7 @@ namespace osu.Game.Overlays.Settings.Sections.UserInterface { protected override LocalisableString Header => UserInterfaceStrings.MainMenuHeader; - private IBindable user; + private IBindable user; private SettingsEnumDropdown backgroundSourceDropdown; diff --git a/osu.Game/Overlays/Toolbar/ToolbarButton.cs b/osu.Game/Overlays/Toolbar/ToolbarButton.cs index ab37b3b355..b2252a5575 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarButton.cs @@ -11,6 +11,7 @@ using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; +using osu.Framework.Input; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; using osu.Game.Database; @@ -39,6 +40,9 @@ namespace osu.Game.Overlays.Toolbar [Resolved] private TextureStore textures { get; set; } + [Resolved] + private ReadableKeyCombinationProvider keyCombinationProvider { get; set; } + public void SetIcon(string texture) => SetIcon(new Sprite { @@ -207,7 +211,7 @@ namespace osu.Game.Overlays.Toolbar if (realmKeyBinding != null) { - string keyBindingString = realmKeyBinding.KeyCombination.ReadableString(); + string keyBindingString = keyCombinationProvider.GetReadableString(realmKeyBinding.KeyCombination); if (!string.IsNullOrEmpty(keyBindingString)) keyBindingTooltip.Text = $" ({keyBindingString})"; diff --git a/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs b/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs index 5d4430caa2..b0c9a04285 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs @@ -8,7 +8,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Effects; using osu.Game.Graphics; using osu.Game.Online.API; -using osu.Game.Users; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Users.Drawables; using osuTK; using osuTK.Graphics; @@ -63,7 +63,7 @@ namespace osu.Game.Overlays.Toolbar { default: Text = @"Guest"; - avatar.User = new User(); + avatar.User = new APIUser(); break; case APIState.Online: diff --git a/osu.Game/Overlays/UserProfileOverlay.cs b/osu.Game/Overlays/UserProfileOverlay.cs index b0327987f2..9fac1463f2 100644 --- a/osu.Game/Overlays/UserProfileOverlay.cs +++ b/osu.Game/Overlays/UserProfileOverlay.cs @@ -11,6 +11,7 @@ using osu.Framework.Graphics.UserInterface; using osu.Framework.Input.Events; using osu.Game.Graphics.Containers; using osu.Game.Online.API.Requests; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays.Profile; using osu.Game.Overlays.Profile.Sections; using osu.Game.Users; @@ -38,18 +39,14 @@ namespace osu.Game.Overlays protected override Color4 BackgroundColour => ColourProvider.Background6; - public void ShowUser(int userId) => ShowUser(new User { Id = userId }); - - public void ShowUser(string username) => ShowUser(new User { Username = username }); - - public void ShowUser(User user, bool fetchOnline = true) + public void ShowUser(IUser user) { - if (user == User.SYSTEM_USER) + if (user == APIUser.SYSTEM_USER) return; Show(); - if (user.Id == Header?.User.Value?.Id) + if (user.OnlineID == Header?.User.Value?.Id) return; if (sectionsContainer != null) @@ -116,22 +113,23 @@ namespace osu.Game.Overlays } }; - if (fetchOnline) - { - userReq = user.Id > 1 ? new GetUserRequest(user.Id) : new GetUserRequest(user.Username); - userReq.Success += userLoadComplete; - API.Queue(userReq); - } - else + sectionsContainer.ScrollToTop(); + + // Check arbitrarily whether this user has already been populated. + // This is only generally used by tests, but should be quite safe unless we want to force a refresh on loading a previous user in the future. + if (user is APIUser apiUser && apiUser.JoinDate != default) { userReq = null; - userLoadComplete(user); + userLoadComplete(apiUser); + return; } - sectionsContainer.ScrollToTop(); + userReq = user.OnlineID > 1 ? new GetUserRequest(user.OnlineID) : new GetUserRequest(user.Username); + userReq.Success += userLoadComplete; + API.Queue(userReq); } - private void userLoadComplete(User user) + private void userLoadComplete(APIUser user) { Header.User.Value = user; diff --git a/osu.Game/Rulesets/Edit/Checks/CheckBackgroundQuality.cs b/osu.Game/Rulesets/Edit/Checks/CheckBackgroundQuality.cs index 8fa79e2ee8..7ce2ee802e 100644 --- a/osu.Game/Rulesets/Edit/Checks/CheckBackgroundQuality.cs +++ b/osu.Game/Rulesets/Edit/Checks/CheckBackgroundQuality.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Generic; +using System.IO; using osu.Game.Rulesets.Edit.Checks.Components; namespace osu.Game.Rulesets.Edit.Checks @@ -48,10 +49,14 @@ namespace osu.Game.Rulesets.Edit.Checks yield return new IssueTemplateLowResolution(this).Create(texture.Width, texture.Height); string storagePath = context.Beatmap.BeatmapInfo.BeatmapSet.GetPathForFile(backgroundFile); - double filesizeMb = context.WorkingBeatmap.GetStream(storagePath).Length / (1024d * 1024d); - if (filesizeMb > max_filesize_mb) - yield return new IssueTemplateTooUncompressed(this).Create(filesizeMb); + using (Stream stream = context.WorkingBeatmap.GetStream(storagePath)) + { + double filesizeMb = stream.Length / (1024d * 1024d); + + if (filesizeMb > max_filesize_mb) + yield return new IssueTemplateTooUncompressed(this).Create(filesizeMb); + } } public class IssueTemplateTooHighResolution : IssueTemplate diff --git a/osu.Game/Rulesets/Mods/ModAutoplay.cs b/osu.Game/Rulesets/Mods/ModAutoplay.cs index 4849d6ea36..60b9c29fe0 100644 --- a/osu.Game/Rulesets/Mods/ModAutoplay.cs +++ b/osu.Game/Rulesets/Mods/ModAutoplay.cs @@ -30,11 +30,6 @@ namespace osu.Game.Rulesets.Mods public override bool HasImplementation => GetType().GenericTypeArguments.Length == 0; - [Obsolete("Use the mod-supporting override")] // can be removed 20210731 - public virtual Score CreateReplayScore(IBeatmap beatmap) => new Score { Replay = new Replay() }; - -#pragma warning disable 618 - public virtual Score CreateReplayScore(IBeatmap beatmap, IReadOnlyList mods) => CreateReplayScore(beatmap); -#pragma warning restore 618 + public virtual Score CreateReplayScore(IBeatmap beatmap, IReadOnlyList mods) => new Score { Replay = new Replay() }; } } diff --git a/osu.Game/Scoring/IScoreInfo.cs b/osu.Game/Scoring/IScoreInfo.cs index 77579f23d9..21a402f8c3 100644 --- a/osu.Game/Scoring/IScoreInfo.cs +++ b/osu.Game/Scoring/IScoreInfo.cs @@ -4,14 +4,14 @@ using System; using osu.Game.Beatmaps; using osu.Game.Database; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Rulesets; -using osu.Game.Users; namespace osu.Game.Scoring { public interface IScoreInfo : IHasOnlineID { - User User { get; } + APIUser User { get; } long TotalScore { get; } diff --git a/osu.Game/Scoring/Legacy/LegacyScoreDecoder.cs b/osu.Game/Scoring/Legacy/LegacyScoreDecoder.cs index 379718195c..7bfe0308f7 100644 --- a/osu.Game/Scoring/Legacy/LegacyScoreDecoder.cs +++ b/osu.Game/Scoring/Legacy/LegacyScoreDecoder.cs @@ -8,12 +8,12 @@ using osu.Game.Beatmaps; using osu.Game.Beatmaps.Formats; using osu.Game.Beatmaps.Legacy; using osu.Game.IO.Legacy; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Replays; using osu.Game.Replays.Legacy; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Replays; -using osu.Game.Users; using SharpCompress.Compressors.LZMA; namespace osu.Game.Scoring.Legacy @@ -45,7 +45,7 @@ namespace osu.Game.Scoring.Legacy if (workingBeatmap is DummyWorkingBeatmap) throw new BeatmapNotFoundException(); - scoreInfo.User = new User { Username = sr.ReadString() }; + scoreInfo.User = new APIUser { Username = sr.ReadString() }; // MD5Hash sr.ReadString(); diff --git a/osu.Game/Scoring/ScoreInfo.cs b/osu.Game/Scoring/ScoreInfo.cs index 36608e2a74..e5b050fc01 100644 --- a/osu.Game/Scoring/ScoreInfo.cs +++ b/osu.Game/Scoring/ScoreInfo.cs @@ -10,10 +10,10 @@ using osu.Framework.Localisation; using osu.Game.Beatmaps; using osu.Game.Database; using osu.Game.Online.API; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Scoring; -using osu.Game.Users; using osu.Game.Utils; namespace osu.Game.Scoring @@ -105,7 +105,7 @@ namespace osu.Game.Scoring } [NotMapped] - public User User { get; set; } + public APIUser User { get; set; } [Column("User")] public string UserString @@ -113,7 +113,7 @@ namespace osu.Game.Scoring get => User?.Username; set { - User ??= new User(); + User ??= new APIUser(); User.Username = value; } } @@ -124,7 +124,7 @@ namespace osu.Game.Scoring get => User?.Id ?? 1; set { - User ??= new User(); + User ??= new APIUser(); User.Id = value ?? 1; } } diff --git a/osu.Game/Scoring/ScoreManager.cs b/osu.Game/Scoring/ScoreManager.cs index 676baf511a..9b4216084e 100644 --- a/osu.Game/Scoring/ScoreManager.cs +++ b/osu.Game/Scoring/ScoreManager.cs @@ -246,9 +246,17 @@ namespace osu.Game.Scoring #region Implementation of IModelManager - public IBindable> ItemUpdated => scoreModelManager.ItemUpdated; + public event Action ItemUpdated + { + add => scoreModelManager.ItemUpdated += value; + remove => scoreModelManager.ItemUpdated -= value; + } - public IBindable> ItemRemoved => scoreModelManager.ItemRemoved; + public event Action ItemRemoved + { + add => scoreModelManager.ItemRemoved += value; + remove => scoreModelManager.ItemRemoved -= value; + } public Task ImportFromStableAsync(StableStorage stableStorage) { @@ -348,11 +356,19 @@ namespace osu.Game.Scoring #endregion - #region Implementation of IModelDownloader + #region Implementation of IModelDownloader - public IBindable>> DownloadBegan => scoreModelDownloader.DownloadBegan; + public event Action> DownloadBegan + { + add => scoreModelDownloader.DownloadBegan += value; + remove => scoreModelDownloader.DownloadBegan -= value; + } - public IBindable>> DownloadFailed => scoreModelDownloader.DownloadFailed; + public event Action> DownloadFailed + { + add => scoreModelDownloader.DownloadFailed += value; + remove => scoreModelDownloader.DownloadFailed -= value; + } public bool Download(IScoreInfo model, bool minimiseDownloadSize) => scoreModelDownloader.Download(model, minimiseDownloadSize); diff --git a/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs b/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs index f0c90cc409..4a922c45b9 100644 --- a/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs +++ b/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs @@ -11,8 +11,8 @@ using osu.Game.Beatmaps; using osu.Game.Configuration; using osu.Game.Graphics.Backgrounds; using osu.Game.Online.API; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Skinning; -using osu.Game.Users; namespace osu.Game.Screens.Backgrounds { @@ -22,7 +22,7 @@ namespace osu.Game.Screens.Backgrounds private int currentDisplay; private const int background_count = 7; - private IBindable user; + private IBindable user; private Bindable skin; private Bindable mode; private Bindable introSequence; diff --git a/osu.Game/Screens/Edit/Setup/MetadataSection.cs b/osu.Game/Screens/Edit/Setup/MetadataSection.cs index 5bb40c09a5..34c2fa8480 100644 --- a/osu.Game/Screens/Edit/Setup/MetadataSection.cs +++ b/osu.Game/Screens/Edit/Setup/MetadataSection.cs @@ -46,7 +46,7 @@ namespace osu.Game.Screens.Edit.Setup Empty(), - creatorTextBox = createTextBox("Creator", metadata.AuthorString), + creatorTextBox = createTextBox("Creator", metadata.Author.Username), difficultyTextBox = createTextBox("Difficulty Name", Beatmap.BeatmapInfo.Version), sourceTextBox = createTextBox("Source", metadata.Source), tagsTextBox = createTextBox("Tags", metadata.Tags) diff --git a/osu.Game/Screens/Menu/Disclaimer.cs b/osu.Game/Screens/Menu/Disclaimer.cs index b8abc131fd..22151db0dd 100644 --- a/osu.Game/Screens/Menu/Disclaimer.cs +++ b/osu.Game/Screens/Menu/Disclaimer.cs @@ -14,9 +14,9 @@ using osu.Framework.Utils; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Online.API; +using osu.Game.Online.API.Requests.Responses; using osuTK; using osuTK.Graphics; -using osu.Game.Users; namespace osu.Game.Screens.Menu { @@ -34,7 +34,7 @@ namespace osu.Game.Screens.Menu private readonly OsuScreen nextScreen; - private readonly Bindable currentUser = new Bindable(); + private readonly Bindable currentUser = new Bindable(); private FillFlowContainer fill; private readonly List expendableText = new List(); @@ -168,7 +168,7 @@ namespace osu.Game.Screens.Menu if (nextScreen != null) LoadComponentAsync(nextScreen); - ((IBindable)currentUser).BindTo(api.LocalUser); + ((IBindable)currentUser).BindTo(api.LocalUser); } public override void OnEntering(IScreen last) diff --git a/osu.Game/Screens/Menu/MenuLogoVisualisation.cs b/osu.Game/Screens/Menu/MenuLogoVisualisation.cs index c44beeffa5..f461136022 100644 --- a/osu.Game/Screens/Menu/MenuLogoVisualisation.cs +++ b/osu.Game/Screens/Menu/MenuLogoVisualisation.cs @@ -4,15 +4,15 @@ using osuTK.Graphics; using osu.Game.Skinning; using osu.Game.Online.API; -using osu.Game.Users; using osu.Framework.Allocation; using osu.Framework.Bindables; +using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Screens.Menu { internal class MenuLogoVisualisation : LogoVisualisation { - private IBindable user; + private IBindable user; private Bindable skin; [BackgroundDependencyLoader] diff --git a/osu.Game/Screens/Menu/MenuSideFlashes.cs b/osu.Game/Screens/Menu/MenuSideFlashes.cs index a1ae4555ed..bdcd3020f8 100644 --- a/osu.Game/Screens/Menu/MenuSideFlashes.cs +++ b/osu.Game/Screens/Menu/MenuSideFlashes.cs @@ -13,10 +13,10 @@ using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Skinning; using osu.Game.Online.API; -using osu.Game.Users; using System; using osu.Framework.Audio.Track; using osu.Framework.Bindables; +using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Screens.Menu { @@ -35,7 +35,7 @@ namespace osu.Game.Screens.Menu private const double box_fade_in_time = 65; private const int box_width = 200; - private IBindable user; + private IBindable user; private Bindable skin; [Resolved] diff --git a/osu.Game/Screens/OnlinePlay/Components/ParticipantsList.cs b/osu.Game/Screens/OnlinePlay/Components/ParticipantsList.cs index e531ddb0ec..1d5552fa7d 100644 --- a/osu.Game/Screens/OnlinePlay/Components/ParticipantsList.cs +++ b/osu.Game/Screens/OnlinePlay/Components/ParticipantsList.cs @@ -7,7 +7,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Threading; -using osu.Game.Users; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Users.Drawables; using osuTK; @@ -92,7 +92,7 @@ namespace osu.Game.Screens.OnlinePlay.Components private class UserTile : CompositeDrawable { - public User User + public APIUser User { get => avatar.User; set => avatar.User = value; diff --git a/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs b/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs index 0681ac23ad..85cee46a29 100644 --- a/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs +++ b/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs @@ -27,7 +27,6 @@ using osu.Game.Overlays.BeatmapSet; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Screens.Play.HUD; -using osu.Game.Users; using osuTK; using osuTK.Graphics; @@ -119,10 +118,10 @@ namespace osu.Game.Screens.OnlinePlay authorText.Clear(); - if (!string.IsNullOrEmpty(Item.Beatmap.Value?.Metadata.Author)) + if (!string.IsNullOrEmpty(Item.Beatmap.Value?.Metadata.Author.Username)) { authorText.AddText("mapped by "); - authorText.AddUserLink(new User { Username = Item.Beatmap.Value.Metadata.Author }); + authorText.AddUserLink(Item.Beatmap.Value.Metadata.Author); } bool hasExplicitContent = (Item.Beatmap.Value.BeatmapSet as IBeatmapSetOnlineInfo)?.HasExplicitContent == true; diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoomParticipantsList.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoomParticipantsList.cs index 31eb5db9bc..10bd534b89 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoomParticipantsList.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoomParticipantsList.cs @@ -12,8 +12,8 @@ using osu.Framework.Graphics.Sprites; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays; -using osu.Game.Users; using osu.Game.Users.Drawables; using osuTK; @@ -195,12 +195,12 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components switch (e.Action) { case NotifyCollectionChangedAction.Add: - foreach (var added in e.NewItems.OfType()) + foreach (var added in e.NewItems.OfType()) addUser(added); break; case NotifyCollectionChangedAction.Remove: - foreach (var removed in e.OldItems.OfType()) + foreach (var removed in e.OldItems.OfType()) removeUser(removed); break; @@ -222,13 +222,13 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components private int displayedCircles => avatarFlow.Count + (hiddenUsers.Count > 0 ? 1 : 0); - private void addUser(User user) + private void addUser(APIUser user) { if (displayedCircles < NumberOfCircles) avatarFlow.Add(new CircularAvatar { User = user }); } - private void removeUser(User user) + private void removeUser(APIUser user) { avatarFlow.RemoveAll(a => a.User == user); } @@ -256,7 +256,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components } } - private void onHostChanged(ValueChangedEvent host) + private void onHostChanged(ValueChangedEvent host) { hostAvatar.User = host.NewValue; hostText.Clear(); @@ -270,7 +270,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components private class CircularAvatar : CompositeDrawable { - public User User + public APIUser User { get => avatar.User; set => avatar.User = value; diff --git a/osu.Game/Screens/OnlinePlay/Match/DrawableMatchRoom.cs b/osu.Game/Screens/OnlinePlay/Match/DrawableMatchRoom.cs index e83403850f..a7b907c7d2 100644 --- a/osu.Game/Screens/OnlinePlay/Match/DrawableMatchRoom.cs +++ b/osu.Game/Screens/OnlinePlay/Match/DrawableMatchRoom.cs @@ -8,10 +8,10 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Game.Beatmaps.Drawables; using osu.Game.Online.API; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Rooms; using osu.Game.Screens.OnlinePlay.Lounge.Components; using osu.Game.Screens.OnlinePlay.Match.Components; -using osu.Game.Users; using osuTK; namespace osu.Game.Screens.OnlinePlay.Match @@ -24,7 +24,7 @@ namespace osu.Game.Screens.OnlinePlay.Match [Resolved] private IAPIProvider api { get; set; } - private readonly IBindable host = new Bindable(); + private readonly IBindable host = new Bindable(); private readonly bool allowEdit; [CanBeNull] diff --git a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs index 2cb29262e2..d6016ec4b9 100644 --- a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs @@ -62,8 +62,6 @@ namespace osu.Game.Screens.OnlinePlay.Match [Resolved(canBeNull: true)] protected OnlinePlayScreen ParentScreen { get; private set; } - private IBindable> managerUpdated; - [Cached] private OnlinePlayBeatmapAvailabilityTracker beatmapAvailabilityTracker { get; set; } @@ -246,8 +244,7 @@ namespace osu.Game.Screens.OnlinePlay.Match SelectedItem.BindValueChanged(_ => Scheduler.AddOnce(selectedItemChanged)); - managerUpdated = beatmapManager.ItemUpdated.GetBoundCopy(); - managerUpdated.BindValueChanged(beatmapUpdated); + beatmapManager.ItemUpdated += beatmapUpdated; UserMods.BindValueChanged(_ => Scheduler.AddOnce(UpdateMods)); } @@ -362,7 +359,7 @@ namespace osu.Game.Screens.OnlinePlay.Match } } - private void beatmapUpdated(ValueChangedEvent> weakSet) => Schedule(updateWorkingBeatmap); + private void beatmapUpdated(BeatmapSetInfo set) => Schedule(updateWorkingBeatmap); private void updateWorkingBeatmap() { @@ -431,6 +428,14 @@ namespace osu.Game.Screens.OnlinePlay.Match /// The room to change the settings of. protected abstract RoomSettingsOverlay CreateRoomSettingsOverlay(Room room); + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + if (beatmapManager != null) + beatmapManager.ItemUpdated -= beatmapUpdated; + } + public class UserModSelectButton : PurpleTriangleButton { } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/TeamDisplay.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/TeamDisplay.cs index 833fbd6605..1bf62241f2 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/TeamDisplay.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/TeamDisplay.cs @@ -29,52 +29,51 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants [Resolved] private OsuColour colours { get; set; } + private OsuClickableContainer clickableContent; + public TeamDisplay(MultiplayerRoomUser user) { this.user = user; RelativeSizeAxes = Axes.Y; - Width = 15; + + AutoSizeAxes = Axes.X; Margin = new MarginPadding { Horizontal = 3 }; - - Alpha = 0; - Scale = new Vector2(0, 1); } [BackgroundDependencyLoader] private void load(AudioManager audio) { - box = new Container + InternalChild = clickableContent = new OsuClickableContainer { - RelativeSizeAxes = Axes.Both, - CornerRadius = 5, - Masking = true, + Width = 15, + Alpha = 0, Scale = new Vector2(0, 1), - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Child = new Box + RelativeSizeAxes = Axes.Y, + Action = changeTeam, + Child = box = new Container { - Colour = Color4.White, RelativeSizeAxes = Axes.Both, + CornerRadius = 5, + Masking = true, + Scale = new Vector2(0, 1), Anchor = Anchor.Centre, Origin = Anchor.Centre, + Child = new Box + { + Colour = Color4.White, + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + } } }; if (Client.LocalUser?.Equals(user) == true) { - InternalChild = new OsuClickableContainer - { - RelativeSizeAxes = Axes.Both, - TooltipText = "Change team", - Action = changeTeam, - Child = box - }; - } - else - { - InternalChild = box; + clickableContent.Action = changeTeam; + clickableContent.TooltipText = "Change team"; } sampleTeamSwap = audio.Samples.Get(@"Multiplayer/team-swap"); @@ -88,7 +87,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants }); } - private int? displayedTeam; + public int? DisplayedTeam { get; private set; } protected override void OnRoomUpdated() { @@ -102,28 +101,28 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants int? newTeam = (userRoomState as TeamVersusUserState)?.TeamID; - if (newTeam == displayedTeam) + if (newTeam == DisplayedTeam) return; // only play the sample if an already valid team changes to another valid team. // this avoids playing a sound for each user if the match type is changed to/from a team mode. - if (newTeam != null && displayedTeam != null) + if (newTeam != null && DisplayedTeam != null) sampleTeamSwap?.Play(); - displayedTeam = newTeam; + DisplayedTeam = newTeam; - if (displayedTeam != null) + if (DisplayedTeam != null) { - box.FadeColour(getColourForTeam(displayedTeam.Value), duration, Easing.OutQuint); + box.FadeColour(getColourForTeam(DisplayedTeam.Value), duration, Easing.OutQuint); box.ScaleTo(new Vector2(box.Scale.X < 0 ? 1 : -1, 1), duration, Easing.OutQuint); - this.ScaleTo(Vector2.One, duration, Easing.OutQuint); - this.FadeIn(duration); + clickableContent.ScaleTo(Vector2.One, duration, Easing.OutQuint); + clickableContent.FadeIn(duration); } else { - this.ScaleTo(new Vector2(0, 1), duration, Easing.OutQuint); - this.FadeOut(duration); + clickableContent.ScaleTo(new Vector2(0, 1), duration, Easing.OutQuint); + clickableContent.FadeOut(duration); } } diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlayComposite.cs b/osu.Game/Screens/OnlinePlay/OnlinePlayComposite.cs index aa971864ef..cf274a3a21 100644 --- a/osu.Game/Screens/OnlinePlay/OnlinePlayComposite.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlayComposite.cs @@ -6,9 +6,9 @@ using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics.Containers; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Rooms; using osu.Game.Screens.OnlinePlay.Match; -using osu.Game.Users; namespace osu.Game.Screens.OnlinePlay { @@ -24,7 +24,7 @@ namespace osu.Game.Screens.OnlinePlay protected Bindable RoomName { get; private set; } [Resolved(typeof(Room))] - protected Bindable Host { get; private set; } + protected Bindable Host { get; private set; } [Resolved(typeof(Room))] protected Bindable Status { get; private set; } @@ -39,7 +39,7 @@ namespace osu.Game.Screens.OnlinePlay protected Bindable Category { get; private set; } [Resolved(typeof(Room))] - protected BindableList RecentParticipants { get; private set; } + protected BindableList RecentParticipants { get; private set; } [Resolved(typeof(Room))] protected Bindable ParticipantCount { get; private set; } diff --git a/osu.Game/Screens/Play/BeatmapMetadataDisplay.cs b/osu.Game/Screens/Play/BeatmapMetadataDisplay.cs index d77673580a..909f0a2b65 100644 --- a/osu.Game/Screens/Play/BeatmapMetadataDisplay.cs +++ b/osu.Game/Screens/Play/BeatmapMetadataDisplay.cs @@ -164,7 +164,7 @@ namespace osu.Game.Screens.Play new Drawable[] { new MetadataLineLabel("Mapper"), - new MetadataLineInfo(metadata.AuthorString) + new MetadataLineInfo(metadata.Author.Username) } } }, diff --git a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs index 871555e5a3..638b2c395f 100644 --- a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs @@ -11,7 +11,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; using osu.Game.Graphics.Containers; -using osu.Game.Users; +using osu.Game.Online.API.Requests.Responses; using osuTK; using osuTK.Graphics; @@ -75,7 +75,7 @@ namespace osu.Game.Screens.Play.HUD /// Whether the player should be tracked on the leaderboard. /// Set to true for the local player or a player whose replay is currently being played. /// - public ILeaderboardScore Add([CanBeNull] User user, bool isTracked) + public ILeaderboardScore Add([CanBeNull] APIUser user, bool isTracked) { var drawable = CreateLeaderboardScoreDrawable(user, isTracked); @@ -106,7 +106,7 @@ namespace osu.Game.Screens.Play.HUD scroll.ScrollToStart(false); } - protected virtual GameplayLeaderboardScore CreateLeaderboardScoreDrawable(User user, bool isTracked) => + protected virtual GameplayLeaderboardScore CreateLeaderboardScoreDrawable(APIUser user, bool isTracked) => new GameplayLeaderboardScore(user, isTracked); protected override void Update() diff --git a/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs b/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs index 85cf9d1966..773ee4a036 100644 --- a/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs +++ b/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs @@ -10,7 +10,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; -using osu.Game.Users; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Users.Drawables; using osu.Game.Utils; using osuTK; @@ -79,7 +79,7 @@ namespace osu.Game.Screens.Play.HUD } [CanBeNull] - public User User { get; } + public APIUser User { get; } /// /// Whether this score is the local user or a replay player (and should be focused / always visible). @@ -101,7 +101,7 @@ namespace osu.Game.Screens.Play.HUD /// /// The score's player. /// Whether the player is the local user or a replay player. - public GameplayLeaderboardScore([CanBeNull] User user, bool tracked) + public GameplayLeaderboardScore([CanBeNull] APIUser user, bool tracked) { User = user; Tracked = tracked; diff --git a/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs index 7caf90f610..e019ee9a3d 100644 --- a/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs @@ -12,11 +12,11 @@ using osu.Game.Configuration; using osu.Game.Database; using osu.Game.Graphics; using osu.Game.Online.API; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Multiplayer; using osu.Game.Online.Multiplayer.MatchTypes.TeamVersus; using osu.Game.Online.Spectator; using osu.Game.Rulesets.Scoring; -using osu.Game.Users; using osuTK.Graphics; namespace osu.Game.Screens.Play.HUD @@ -118,7 +118,7 @@ namespace osu.Game.Screens.Play.HUD protected virtual TrackedUserData CreateUserData(MultiplayerRoomUser user, ScoreProcessor scoreProcessor) => new TrackedUserData(user, scoreProcessor); - protected override GameplayLeaderboardScore CreateLeaderboardScoreDrawable(User user, bool isTracked) + protected override GameplayLeaderboardScore CreateLeaderboardScoreDrawable(APIUser user, bool isTracked) { var leaderboardScore = base.CreateLeaderboardScoreDrawable(user, isTracked); diff --git a/osu.Game/Screens/Play/HUD/UnstableRateCounter.cs b/osu.Game/Screens/Play/HUD/UnstableRateCounter.cs new file mode 100644 index 0000000000..89ae4f8a21 --- /dev/null +++ b/osu.Game/Screens/Play/HUD/UnstableRateCounter.cs @@ -0,0 +1,147 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using System.Collections.Generic; +using System.Linq; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Localisation; +using osu.Game.Beatmaps; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; +using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Scoring; +using osu.Game.Skinning; + +namespace osu.Game.Screens.Play.HUD +{ + public class UnstableRateCounter : RollingCounter, ISkinnableDrawable + { + public bool UsesFixedAnchor { get; set; } + + protected override double RollingDuration => 750; + + private const float alpha_when_invalid = 0.3f; + private readonly Bindable valid = new Bindable(); + + private readonly List hitOffsets = new List(); + + [Resolved] + private ScoreProcessor scoreProcessor { get; set; } + + public UnstableRateCounter() + { + Current.Value = 0; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours, BeatmapDifficultyCache difficultyCache) + { + Colour = colours.BlueLighter; + valid.BindValueChanged(e => + DrawableCount.FadeTo(e.NewValue ? 1 : alpha_when_invalid, 1000, Easing.OutQuint)); + } + + private bool changesUnstableRate(JudgementResult judgement) + => !(judgement.HitObject.HitWindows is HitWindows.EmptyHitWindows) && judgement.IsHit; + + protected override void LoadComplete() + { + base.LoadComplete(); + + scoreProcessor.NewJudgement += onJudgementAdded; + scoreProcessor.JudgementReverted += onJudgementReverted; + } + + private void onJudgementAdded(JudgementResult judgement) + { + if (!changesUnstableRate(judgement)) return; + + hitOffsets.Add(judgement.TimeOffset); + updateDisplay(); + } + + private void onJudgementReverted(JudgementResult judgement) + { + if (judgement.FailedAtJudgement || !changesUnstableRate(judgement)) return; + + hitOffsets.RemoveAt(hitOffsets.Count - 1); + updateDisplay(); + } + + private void updateDisplay() + { + // At Count = 0, we get NaN, While we are allowing count = 1, it will be 0 since average = offset. + if (hitOffsets.Count > 0) + { + double mean = hitOffsets.Average(); + double squares = hitOffsets.Select(offset => Math.Pow(offset - mean, 2)).Sum(); + Current.Value = (int)(Math.Sqrt(squares / hitOffsets.Count) * 10); + valid.Value = true; + } + else + { + Current.Value = 0; + valid.Value = false; + } + } + + protected override IHasText CreateText() => new TextComponent + { + Alpha = alpha_when_invalid, + }; + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + if (scoreProcessor == null) return; + + scoreProcessor.NewJudgement -= onJudgementAdded; + scoreProcessor.JudgementReverted -= onJudgementReverted; + } + + private class TextComponent : CompositeDrawable, IHasText + { + public LocalisableString Text + { + get => text.Text; + set => text.Text = value; + } + + private readonly OsuSpriteText text; + + public TextComponent() + { + AutoSizeAxes = Axes.Both; + + InternalChild = new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Children = new Drawable[] + { + text = new OsuSpriteText + { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + Font = OsuFont.Numeric.With(size: 16, fixedWidth: true) + }, + new OsuSpriteText + { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + Font = OsuFont.Numeric.With(size: 8, fixedWidth: true), + Text = "UR", + Padding = new MarginPadding { Bottom = 1.5f }, + } + } + }; + } + } + } +} diff --git a/osu.Game/Screens/Play/SoloSpectator.cs b/osu.Game/Screens/Play/SoloSpectator.cs index 250738df39..1dcc191c0f 100644 --- a/osu.Game/Screens/Play/SoloSpectator.cs +++ b/osu.Game/Screens/Play/SoloSpectator.cs @@ -27,6 +27,7 @@ using osu.Game.Screens.OnlinePlay.Match.Components; using osu.Game.Screens.Spectate; using osu.Game.Users; using osuTK; +using APIUser = osu.Game.Online.API.Requests.Responses.APIUser; namespace osu.Game.Screens.Play { @@ -34,7 +35,7 @@ namespace osu.Game.Screens.Play public class SoloSpectator : SpectatorScreen, IPreviewTrackOwner { [NotNull] - private readonly User targetUser; + private readonly APIUser targetUser; [Resolved] private IAPIProvider api { get; set; } @@ -62,7 +63,7 @@ namespace osu.Game.Screens.Play private APIBeatmapSet beatmapSet; - public SoloSpectator([NotNull] User targetUser) + public SoloSpectator([NotNull] APIUser targetUser) : base(targetUser.Id) { this.targetUser = targetUser; diff --git a/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs b/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs index c27d5227b5..29b9d6164e 100644 --- a/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs +++ b/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs @@ -62,7 +62,7 @@ namespace osu.Game.Screens.Ranking.Expanded { var beatmap = score.BeatmapInfo; var metadata = beatmap.BeatmapSet?.Metadata ?? beatmap.Metadata; - string creator = metadata.Author?.Username; + string creator = metadata.Author.Username; var topStatistics = new List { diff --git a/osu.Game/Screens/Ranking/Expanded/ExpandedPanelTopContent.cs b/osu.Game/Screens/Ranking/Expanded/ExpandedPanelTopContent.cs index 5dfc43cc29..bf06bc2227 100644 --- a/osu.Game/Screens/Ranking/Expanded/ExpandedPanelTopContent.cs +++ b/osu.Game/Screens/Ranking/Expanded/ExpandedPanelTopContent.cs @@ -6,7 +6,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; -using osu.Game.Users; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Users.Drawables; using osuTK; @@ -17,13 +17,13 @@ namespace osu.Game.Screens.Ranking.Expanded /// public class ExpandedPanelTopContent : CompositeDrawable { - private readonly User user; + private readonly APIUser user; /// /// Creates a new . /// - /// The to display. - public ExpandedPanelTopContent(User user) + /// The to display. + public ExpandedPanelTopContent(APIUser user) { this.user = user; Anchor = Anchor.TopCentre; diff --git a/osu.Game/Screens/Ranking/Statistics/StatisticsPanel.cs b/osu.Game/Screens/Ranking/Statistics/StatisticsPanel.cs index bc62bcf2b2..26dc3165f8 100644 --- a/osu.Game/Screens/Ranking/Statistics/StatisticsPanel.cs +++ b/osu.Game/Screens/Ranking/Statistics/StatisticsPanel.cs @@ -69,6 +69,8 @@ namespace osu.Game.Screens.Ranking.Statistics foreach (var child in content) child.FadeOut(150).Expire(); + spinner.Hide(); + var newScore = score.NewValue; if (newScore == null) diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index e5e28d2fde..0c593ebea1 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -143,11 +143,6 @@ namespace osu.Game.Screens.Select private CarouselRoot root; - private IBindable> itemUpdated; - private IBindable> itemRemoved; - private IBindable> itemHidden; - private IBindable> itemRestored; - private readonly DrawablePool setPool = new DrawablePool(100); public BeatmapCarousel() @@ -179,14 +174,10 @@ namespace osu.Game.Screens.Select RightClickScrollingEnabled.ValueChanged += enabled => Scroll.RightMouseScrollbar = enabled.NewValue; RightClickScrollingEnabled.TriggerChange(); - itemUpdated = beatmaps.ItemUpdated.GetBoundCopy(); - itemUpdated.BindValueChanged(beatmapUpdated); - itemRemoved = beatmaps.ItemRemoved.GetBoundCopy(); - itemRemoved.BindValueChanged(beatmapRemoved); - itemHidden = beatmaps.BeatmapHidden.GetBoundCopy(); - itemHidden.BindValueChanged(beatmapHidden); - itemRestored = beatmaps.BeatmapRestored.GetBoundCopy(); - itemRestored.BindValueChanged(beatmapRestored); + beatmaps.ItemUpdated += beatmapUpdated; + beatmaps.ItemRemoved += beatmapRemoved; + beatmaps.BeatmapHidden += beatmapHidden; + beatmaps.BeatmapRestored += beatmapRestored; if (!beatmapSets.Any()) loadBeatmapSets(GetLoadableBeatmaps()); @@ -675,29 +666,10 @@ namespace osu.Game.Screens.Select return (firstIndex, lastIndex); } - private void beatmapRemoved(ValueChangedEvent> weakItem) - { - if (weakItem.NewValue.TryGetTarget(out var item)) - RemoveBeatmapSet(item); - } - - private void beatmapUpdated(ValueChangedEvent> weakItem) - { - if (weakItem.NewValue.TryGetTarget(out var item)) - UpdateBeatmapSet(item); - } - - private void beatmapRestored(ValueChangedEvent> weakItem) - { - if (weakItem.NewValue.TryGetTarget(out var b)) - UpdateBeatmapSet(beatmaps.QueryBeatmapSet(s => s.ID == b.BeatmapSetInfoID)); - } - - private void beatmapHidden(ValueChangedEvent> weakItem) - { - if (weakItem.NewValue.TryGetTarget(out var b)) - UpdateBeatmapSet(beatmaps.QueryBeatmapSet(s => s.ID == b.BeatmapSetInfoID)); - } + private void beatmapRemoved(BeatmapSetInfo item) => RemoveBeatmapSet(item); + private void beatmapUpdated(BeatmapSetInfo item) => UpdateBeatmapSet(item); + private void beatmapRestored(BeatmapInfo b) => UpdateBeatmapSet(beatmaps.QueryBeatmapSet(s => s.ID == b.BeatmapSetInfoID)); + private void beatmapHidden(BeatmapInfo b) => UpdateBeatmapSet(beatmaps.QueryBeatmapSet(s => s.ID == b.BeatmapSetInfoID)); private CarouselBeatmapSet createCarouselSet(BeatmapSetInfo beatmapSet) { @@ -956,5 +928,18 @@ namespace osu.Game.Screens.Select return base.OnDragStart(e); } } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + if (beatmaps != null) + { + beatmaps.ItemUpdated -= beatmapUpdated; + beatmaps.ItemRemoved -= beatmapRemoved; + beatmaps.BeatmapHidden -= beatmapHidden; + beatmaps.BeatmapRestored -= beatmapRestored; + } + } } } diff --git a/osu.Game/Screens/Select/BeatmapInfoWedge.cs b/osu.Game/Screens/Select/BeatmapInfoWedge.cs index 89eed14e6d..e344da4027 100644 --- a/osu.Game/Screens/Select/BeatmapInfoWedge.cs +++ b/osu.Game/Screens/Select/BeatmapInfoWedge.cs @@ -428,7 +428,7 @@ namespace osu.Game.Screens.Select private Drawable getMapper(BeatmapMetadata metadata) { - if (metadata.Author == null) + if (string.IsNullOrEmpty(metadata.Author.Username)) return Empty(); return new LinkFlowContainer(s => diff --git a/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs b/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs index 9e057808a7..fa96e6dde7 100644 --- a/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs +++ b/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs @@ -49,7 +49,7 @@ namespace osu.Game.Screens.Select.Carousel match &= !criteria.BeatDivisor.HasFilter || criteria.BeatDivisor.IsInRange(BeatmapInfo.BeatDivisor); match &= !criteria.OnlineStatus.HasFilter || criteria.OnlineStatus.IsInRange(BeatmapInfo.Status); - match &= !criteria.Creator.HasFilter || criteria.Creator.Matches(BeatmapInfo.Metadata.AuthorString); + match &= !criteria.Creator.HasFilter || criteria.Creator.Matches(BeatmapInfo.Metadata.Author.Username); match &= !criteria.Artist.HasFilter || criteria.Artist.Matches(BeatmapInfo.Metadata.Artist) || criteria.Artist.Matches(BeatmapInfo.Metadata.ArtistUnicode); diff --git a/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs b/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs index d41cb73a29..e465f423bc 100644 --- a/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs +++ b/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs @@ -69,7 +69,7 @@ namespace osu.Game.Screens.Select.Carousel return string.Compare(BeatmapSet.Metadata.Title, otherSet.BeatmapSet.Metadata.Title, StringComparison.OrdinalIgnoreCase); case SortMode.Author: - return string.Compare(BeatmapSet.Metadata.Author?.Username, otherSet.BeatmapSet.Metadata.Author?.Username, StringComparison.OrdinalIgnoreCase); + return string.Compare(BeatmapSet.Metadata.Author.Username, otherSet.BeatmapSet.Metadata.Author.Username, StringComparison.OrdinalIgnoreCase); case SortMode.Source: return string.Compare(BeatmapSet.Metadata.Source, otherSet.BeatmapSet.Metadata.Source, StringComparison.OrdinalIgnoreCase); diff --git a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs index 8a5dde961f..5940911d4a 100644 --- a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs +++ b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs @@ -142,7 +142,7 @@ namespace osu.Game.Screens.Select.Carousel }, new OsuSpriteText { - Text = $"{(beatmapInfo.Metadata ?? beatmapInfo.BeatmapSet.Metadata).Author?.Username ?? string.Empty}", + Text = $"{(beatmapInfo.Metadata ?? beatmapInfo.BeatmapSet.Metadata).Author.Username}", Font = OsuFont.GetFont(italics: true), Anchor = Anchor.BottomLeft, Origin = Anchor.BottomLeft diff --git a/osu.Game/Screens/Select/Carousel/TopLocalRank.cs b/osu.Game/Screens/Select/Carousel/TopLocalRank.cs index f2485587d8..34129f232c 100644 --- a/osu.Game/Screens/Select/Carousel/TopLocalRank.cs +++ b/osu.Game/Screens/Select/Carousel/TopLocalRank.cs @@ -1,7 +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; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; @@ -28,9 +27,6 @@ namespace osu.Game.Screens.Select.Carousel [Resolved] private IAPIProvider api { get; set; } - private IBindable> itemUpdated; - private IBindable> itemRemoved; - public TopLocalRank(BeatmapInfo beatmapInfo) : base(null) { @@ -40,24 +36,18 @@ namespace osu.Game.Screens.Select.Carousel [BackgroundDependencyLoader] private void load() { - itemUpdated = scores.ItemUpdated.GetBoundCopy(); - itemUpdated.BindValueChanged(scoreChanged); - - itemRemoved = scores.ItemRemoved.GetBoundCopy(); - itemRemoved.BindValueChanged(scoreChanged); + scores.ItemUpdated += scoreChanged; + scores.ItemRemoved += scoreChanged; ruleset.ValueChanged += _ => fetchAndLoadTopScore(); fetchAndLoadTopScore(); } - private void scoreChanged(ValueChangedEvent> weakScore) + private void scoreChanged(ScoreInfo score) { - if (weakScore.NewValue.TryGetTarget(out var score)) - { - if (score.BeatmapInfoID == beatmapInfo.ID) - fetchAndLoadTopScore(); - } + if (score.BeatmapInfoID == beatmapInfo.ID) + fetchAndLoadTopScore(); } private ScheduledDelegate scheduledRankUpdate; @@ -86,5 +76,16 @@ namespace osu.Game.Screens.Select.Carousel .OrderByDescending(s => s.TotalScore) .FirstOrDefault(); } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + if (scores != null) + { + scores.ItemUpdated -= scoreChanged; + scores.ItemRemoved -= scoreChanged; + } + } } } diff --git a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs index de1ba5cf2e..9205c6c0d2 100644 --- a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs +++ b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs @@ -44,10 +44,6 @@ namespace osu.Game.Screens.Select.Leaderboards private bool filterMods; - private IBindable> itemRemoved; - - private IBindable> itemAdded; - /// /// Whether to apply the game's currently selected mods as a filter when retrieving scores. /// @@ -90,11 +86,8 @@ namespace osu.Game.Screens.Select.Leaderboards UpdateScores(); }; - itemRemoved = scoreManager.ItemRemoved.GetBoundCopy(); - itemRemoved.BindValueChanged(onScoreRemoved); - - itemAdded = scoreManager.ItemUpdated.GetBoundCopy(); - itemAdded.BindValueChanged(onScoreAdded); + scoreManager.ItemRemoved += scoreStoreChanged; + scoreManager.ItemUpdated += scoreStoreChanged; } protected override void Reset() @@ -103,22 +96,13 @@ namespace osu.Game.Screens.Select.Leaderboards TopScore = null; } - private void onScoreRemoved(ValueChangedEvent> score) => - scoreStoreChanged(score); - - private void onScoreAdded(ValueChangedEvent> score) => - scoreStoreChanged(score); - - private void scoreStoreChanged(ValueChangedEvent> score) + private void scoreStoreChanged(ScoreInfo score) { if (Scope != BeatmapLeaderboardScope.Local) return; - if (score.NewValue.TryGetTarget(out var scoreInfo)) - { - if (BeatmapInfo?.ID != scoreInfo.BeatmapInfoID) - return; - } + if (BeatmapInfo?.ID != score.BeatmapInfoID) + return; RefreshScores(); } @@ -215,5 +199,16 @@ namespace osu.Game.Screens.Select.Leaderboards { Action = () => ScoreSelected?.Invoke(model) }; + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + if (scoreManager != null) + { + scoreManager.ItemRemoved -= scoreStoreChanged; + scoreManager.ItemUpdated -= scoreStoreChanged; + } + } } } diff --git a/osu.Game/Screens/Spectate/SpectatorScreen.cs b/osu.Game/Screens/Spectate/SpectatorScreen.cs index c8df01dae6..3bcfcb2a0b 100644 --- a/osu.Game/Screens/Spectate/SpectatorScreen.cs +++ b/osu.Game/Screens/Spectate/SpectatorScreen.cs @@ -1,7 +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; using System.Collections.Generic; using System.Diagnostics; using System.Linq; @@ -11,11 +10,11 @@ using osu.Framework.Bindables; using osu.Framework.Extensions.ObjectExtensions; using osu.Game.Beatmaps; using osu.Game.Database; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Spectator; using osu.Game.Replays; using osu.Game.Rulesets; using osu.Game.Scoring; -using osu.Game.Users; namespace osu.Game.Screens.Spectate { @@ -42,11 +41,9 @@ namespace osu.Game.Screens.Spectate private readonly IBindableDictionary playingUserStates = new BindableDictionary(); - private readonly Dictionary userMap = new Dictionary(); + private readonly Dictionary userMap = new Dictionary(); private readonly Dictionary gameplayStates = new Dictionary(); - private IBindable> managerUpdated; - /// /// Creates a new . /// @@ -73,20 +70,16 @@ namespace osu.Game.Screens.Spectate playingUserStates.BindTo(spectatorClient.PlayingUserStates); playingUserStates.BindCollectionChanged(onPlayingUserStatesChanged, true); - managerUpdated = beatmaps.ItemUpdated.GetBoundCopy(); - managerUpdated.BindValueChanged(beatmapUpdated); + beatmaps.ItemUpdated += beatmapUpdated; foreach ((int id, var _) in userMap) spectatorClient.WatchUser(id); })); } - private void beatmapUpdated(ValueChangedEvent> e) + private void beatmapUpdated(BeatmapSetInfo beatmapSet) { - if (!e.NewValue.TryGetTarget(out var beatmapSet)) - return; - - foreach ((int userId, var _) in userMap) + foreach ((int userId, _) in userMap) { if (!playingUserStates.TryGetValue(userId, out var userState)) continue; @@ -223,7 +216,8 @@ namespace osu.Game.Screens.Spectate spectatorClient.StopWatchingUser(userId); } - managerUpdated?.UnbindAll(); + if (beatmaps != null) + beatmaps.ItemUpdated -= beatmapUpdated; } } } diff --git a/osu.Game/Skinning/LegacyBeatmapSkin.cs b/osu.Game/Skinning/LegacyBeatmapSkin.cs index 8720a55076..8abef6800d 100644 --- a/osu.Game/Skinning/LegacyBeatmapSkin.cs +++ b/osu.Game/Skinning/LegacyBeatmapSkin.cs @@ -77,6 +77,6 @@ namespace osu.Game.Skinning } private static SkinInfo createSkinInfo(BeatmapInfo beatmapInfo) => - new SkinInfo { Name = beatmapInfo.ToString(), Creator = beatmapInfo.Metadata?.AuthorString }; + new SkinInfo { Name = beatmapInfo.ToString(), Creator = beatmapInfo.Metadata?.Author.Username }; } } diff --git a/osu.Game/Stores/BeatmapImporter.cs b/osu.Game/Stores/BeatmapImporter.cs index 787b1ddd60..1ac73cf781 100644 --- a/osu.Game/Stores/BeatmapImporter.cs +++ b/osu.Game/Stores/BeatmapImporter.cs @@ -238,7 +238,11 @@ namespace osu.Game.Stores TitleUnicode = decoded.Metadata.TitleUnicode, Artist = decoded.Metadata.Artist, ArtistUnicode = decoded.Metadata.ArtistUnicode, - Author = decoded.Metadata.AuthorString, + Author = + { + OnlineID = decoded.Metadata.Author.Id, + Username = decoded.Metadata.Author.Username + }, Source = decoded.Metadata.Source, Tags = decoded.Metadata.Tags, PreviewTime = decoded.Metadata.PreviewTime, diff --git a/osu.Game/Stores/RealmRulesetStore.cs b/osu.Game/Stores/RealmRulesetStore.cs index e9c04f652d..0d2cddf874 100644 --- a/osu.Game/Stores/RealmRulesetStore.cs +++ b/osu.Game/Stores/RealmRulesetStore.cs @@ -102,75 +102,78 @@ namespace osu.Game.Stores private void addMissingRulesets() { - realmFactory.Context.Write(realm => + using (var context = realmFactory.CreateContext()) { - var rulesets = realm.All(); - - List instances = loadedAssemblies.Values - .Select(r => Activator.CreateInstance(r) as Ruleset) - .Where(r => r != null) - .Select(r => r.AsNonNull()) - .ToList(); - - // add all legacy rulesets first to ensure they have exclusive choice of primary key. - foreach (var r in instances.Where(r => r is ILegacyRuleset)) + context.Write(realm => { - if (realm.All().FirstOrDefault(rr => rr.OnlineID == r.RulesetInfo.ID) == null) - realm.Add(new RealmRuleset(r.RulesetInfo.ShortName, r.RulesetInfo.Name, r.RulesetInfo.InstantiationInfo, r.RulesetInfo.ID)); - } + var rulesets = realm.All(); - // add any other rulesets which have assemblies present but are not yet in the database. - foreach (var r in instances.Where(r => !(r is ILegacyRuleset))) - { - if (rulesets.FirstOrDefault(ri => ri.InstantiationInfo.Equals(r.RulesetInfo.InstantiationInfo, StringComparison.Ordinal)) == null) + List instances = loadedAssemblies.Values + .Select(r => Activator.CreateInstance(r) as Ruleset) + .Where(r => r != null) + .Select(r => r.AsNonNull()) + .ToList(); + + // add all legacy rulesets first to ensure they have exclusive choice of primary key. + foreach (var r in instances.Where(r => r is ILegacyRuleset)) { - var existingSameShortName = rulesets.FirstOrDefault(ri => ri.ShortName == r.RulesetInfo.ShortName); - - if (existingSameShortName != null) - { - // even if a matching InstantiationInfo was not found, there may be an existing ruleset with the same ShortName. - // this generally means the user or ruleset provider has renamed their dll but the underlying ruleset is *likely* the same one. - // in such cases, update the instantiation info of the existing entry to point to the new one. - existingSameShortName.InstantiationInfo = r.RulesetInfo.InstantiationInfo; - } - else + if (realm.All().FirstOrDefault(rr => rr.OnlineID == r.RulesetInfo.ID) == null) realm.Add(new RealmRuleset(r.RulesetInfo.ShortName, r.RulesetInfo.Name, r.RulesetInfo.InstantiationInfo, r.RulesetInfo.ID)); } - } - List detachedRulesets = new List(); - - // perform a consistency check and detach final rulesets from realm for cross-thread runtime usage. - foreach (var r in rulesets) - { - try + // add any other rulesets which have assemblies present but are not yet in the database. + foreach (var r in instances.Where(r => !(r is ILegacyRuleset))) { - var type = Type.GetType(r.InstantiationInfo); + if (rulesets.FirstOrDefault(ri => ri.InstantiationInfo.Equals(r.RulesetInfo.InstantiationInfo, StringComparison.Ordinal)) == null) + { + var existingSameShortName = rulesets.FirstOrDefault(ri => ri.ShortName == r.RulesetInfo.ShortName); - if (type == null) - throw new InvalidOperationException(@"Type resolution failure."); - - var rInstance = (Activator.CreateInstance(type) as Ruleset)?.RulesetInfo; - - if (rInstance == null) - throw new InvalidOperationException(@"Instantiation failure."); - - r.Name = rInstance.Name; - r.ShortName = rInstance.ShortName; - r.InstantiationInfo = rInstance.InstantiationInfo; - r.Available = true; - - detachedRulesets.Add(r.Clone()); + if (existingSameShortName != null) + { + // even if a matching InstantiationInfo was not found, there may be an existing ruleset with the same ShortName. + // this generally means the user or ruleset provider has renamed their dll but the underlying ruleset is *likely* the same one. + // in such cases, update the instantiation info of the existing entry to point to the new one. + existingSameShortName.InstantiationInfo = r.RulesetInfo.InstantiationInfo; + } + else + realm.Add(new RealmRuleset(r.RulesetInfo.ShortName, r.RulesetInfo.Name, r.RulesetInfo.InstantiationInfo, r.RulesetInfo.ID)); + } } - catch (Exception ex) + + List detachedRulesets = new List(); + + // perform a consistency check and detach final rulesets from realm for cross-thread runtime usage. + foreach (var r in rulesets) { - r.Available = false; - Logger.Log($"Could not load ruleset {r}: {ex.Message}"); - } - } + try + { + var type = Type.GetType(r.InstantiationInfo); - availableRulesets.AddRange(detachedRulesets); - }); + if (type == null) + throw new InvalidOperationException(@"Type resolution failure."); + + var rInstance = (Activator.CreateInstance(type) as Ruleset)?.RulesetInfo; + + if (rInstance == null) + throw new InvalidOperationException(@"Instantiation failure."); + + r.Name = rInstance.Name; + r.ShortName = rInstance.ShortName; + r.InstantiationInfo = rInstance.InstantiationInfo; + r.Available = true; + + detachedRulesets.Add(r.Clone()); + } + catch (Exception ex) + { + r.Available = false; + Logger.Log($"Could not load ruleset {r}: {ex.Message}"); + } + } + + availableRulesets.AddRange(detachedRulesets); + }); + } } private void loadFromAppDomain() diff --git a/osu.Game/Tests/Beatmaps/HitObjectSampleTest.cs b/osu.Game/Tests/Beatmaps/HitObjectSampleTest.cs index bb5dd09e16..b87c3d57c2 100644 --- a/osu.Game/Tests/Beatmaps/HitObjectSampleTest.cs +++ b/osu.Game/Tests/Beatmaps/HitObjectSampleTest.cs @@ -15,13 +15,13 @@ using osu.Framework.Timing; using osu.Game.Beatmaps; using osu.Game.Beatmaps.Formats; using osu.Game.IO; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Rulesets; using osu.Game.Rulesets.Objects; using osu.Game.Screens.Ranking; using osu.Game.Skinning; using osu.Game.Storyboards; using osu.Game.Tests.Visual; -using osu.Game.Users; namespace osu.Game.Tests.Beatmaps { @@ -41,7 +41,7 @@ namespace osu.Game.Tests.Beatmaps BeatmapSet = new BeatmapSetInfo(), Metadata = new BeatmapMetadata { - Author = User.SYSTEM_USER + Author = APIUser.SYSTEM_USER } }; diff --git a/osu.Game/Tests/TestScoreInfo.cs b/osu.Game/Tests/TestScoreInfo.cs index 719d31b092..a53cb0ae78 100644 --- a/osu.Game/Tests/TestScoreInfo.cs +++ b/osu.Game/Tests/TestScoreInfo.cs @@ -3,12 +3,12 @@ using System; using System.Linq; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Scoring; using osu.Game.Scoring; using osu.Game.Tests.Beatmaps; -using osu.Game.Users; namespace osu.Game.Tests { @@ -16,7 +16,7 @@ namespace osu.Game.Tests { public TestScoreInfo(RulesetInfo ruleset, bool excessMods = false) { - User = new User + User = new APIUser { Id = 2, Username = "peppy", diff --git a/osu.Game/Tests/Visual/EditorTestScene.cs b/osu.Game/Tests/Visual/EditorTestScene.cs index 4b02306d33..07152b5a3e 100644 --- a/osu.Game/Tests/Visual/EditorTestScene.cs +++ b/osu.Game/Tests/Visual/EditorTestScene.cs @@ -137,7 +137,7 @@ namespace osu.Game.Tests.Visual private readonly TestBeatmapManager testBeatmapManager; public TestWorkingBeatmapCache(TestBeatmapManager testBeatmapManager, AudioManager audioManager, IResourceStore resourceStore, IResourceStore storage, WorkingBeatmap defaultBeatmap, GameHost gameHost) - : base(audioManager, resourceStore, storage, defaultBeatmap, gameHost) + : base(testBeatmapManager.BeatmapTrackStore, audioManager, resourceStore, storage, defaultBeatmap, gameHost) { this.testBeatmapManager = testBeatmapManager; } diff --git a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs index 70d907ba15..0860e45346 100644 --- a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs +++ b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs @@ -18,7 +18,7 @@ using osu.Game.Online.Multiplayer; using osu.Game.Online.Multiplayer.MatchTypes.TeamVersus; using osu.Game.Online.Rooms; using osu.Game.Rulesets.Mods; -using osu.Game.Users; +using APIUser = osu.Game.Online.API.Requests.Responses.APIUser; namespace osu.Game.Tests.Visual.Multiplayer { @@ -51,7 +51,7 @@ namespace osu.Game.Tests.Visual.Multiplayer public void Disconnect() => isConnected.Value = false; - public MultiplayerRoomUser AddUser(User user, bool markAsPlaying = false) + public MultiplayerRoomUser AddUser(APIUser user, bool markAsPlaying = false) { var roomUser = new MultiplayerRoomUser(user.Id) { User = user }; @@ -73,7 +73,7 @@ namespace osu.Game.Tests.Visual.Multiplayer Scheduler.Update(); } - public void RemoveUser(User user) + public void RemoveUser(APIUser user) { Debug.Assert(Room != null); ((IMultiplayerClient)this).UserLeft(new MultiplayerRoomUser(user.Id)); diff --git a/osu.Game/Tests/Visual/OnlinePlay/TestRoomManager.cs b/osu.Game/Tests/Visual/OnlinePlay/TestRoomManager.cs index 5fe3dc8406..4cbc6174c9 100644 --- a/osu.Game/Tests/Visual/OnlinePlay/TestRoomManager.cs +++ b/osu.Game/Tests/Visual/OnlinePlay/TestRoomManager.cs @@ -3,10 +3,10 @@ using System; using osu.Game.Beatmaps; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Rooms; using osu.Game.Rulesets; using osu.Game.Screens.OnlinePlay.Components; -using osu.Game.Users; namespace osu.Game.Tests.Visual.OnlinePlay { @@ -33,7 +33,7 @@ namespace osu.Game.Tests.Visual.OnlinePlay { RoomID = { Value = -currentRoomId }, Name = { Value = $@"Room {currentRoomId}" }, - Host = { Value = new User { Username = @"Host" } }, + Host = { Value = new APIUser { Username = @"Host" } }, EndDate = { Value = DateTimeOffset.Now + TimeSpan.FromSeconds(10) }, Category = { Value = i % 2 == 0 ? RoomCategory.Spotlight : RoomCategory.Normal }, }; diff --git a/osu.Game/Tests/Visual/OnlinePlay/TestRoomRequestsHandler.cs b/osu.Game/Tests/Visual/OnlinePlay/TestRoomRequestsHandler.cs index 7f975c9985..dc12e48297 100644 --- a/osu.Game/Tests/Visual/OnlinePlay/TestRoomRequestsHandler.cs +++ b/osu.Game/Tests/Visual/OnlinePlay/TestRoomRequestsHandler.cs @@ -7,11 +7,11 @@ using System.Linq; using osu.Framework.Allocation; using osu.Game.Online.API; using osu.Game.Online.API.Requests; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Rooms; using osu.Game.Rulesets.Scoring; using osu.Game.Scoring; using osu.Game.Screens.OnlinePlay.Components; -using osu.Game.Users; namespace osu.Game.Tests.Visual.OnlinePlay { @@ -37,7 +37,7 @@ namespace osu.Game.Tests.Visual.OnlinePlay /// The local user to store in responses where required. /// The game base for cases where actual online requests need to be sent. /// Whether the request was successfully handled. - public bool HandleRequest(APIRequest request, User localUser, OsuGameBase game) + public bool HandleRequest(APIRequest request, APIUser localUser, OsuGameBase game) { switch (request) { diff --git a/osu.Game/Tests/Visual/OsuTestScene.cs b/osu.Game/Tests/Visual/OsuTestScene.cs index 153e2c487c..83e1423504 100644 --- a/osu.Game/Tests/Visual/OsuTestScene.cs +++ b/osu.Game/Tests/Visual/OsuTestScene.cs @@ -216,8 +216,6 @@ namespace osu.Game.Tests.Visual Artist = beatmap.BeatmapSet.Metadata.Artist, ArtistUnicode = beatmap.BeatmapSet.Metadata.ArtistUnicode, Author = beatmap.BeatmapSet.Metadata.Author, - AuthorID = beatmap.BeatmapSet.Metadata.AuthorID, - AuthorString = beatmap.BeatmapSet.Metadata.AuthorString, Source = beatmap.BeatmapSet.Metadata.Source, Tags = beatmap.BeatmapSet.Metadata.Tags, Beatmaps = new[] @@ -228,7 +226,7 @@ namespace osu.Game.Tests.Visual OnlineBeatmapSetID = beatmap.BeatmapSet.OnlineID, Status = beatmap.Status, Checksum = beatmap.MD5Hash, - AuthorID = beatmap.Metadata.AuthorID, + AuthorID = beatmap.Metadata.Author.OnlineID, RulesetID = beatmap.RulesetID, StarRating = beatmap.StarDifficulty, DifficultyName = beatmap.Version, diff --git a/osu.Game/Tests/Visual/TestUserLookupCache.cs b/osu.Game/Tests/Visual/TestUserLookupCache.cs index fcb9c070ff..ce1bbd5f15 100644 --- a/osu.Game/Tests/Visual/TestUserLookupCache.cs +++ b/osu.Game/Tests/Visual/TestUserLookupCache.cs @@ -4,24 +4,24 @@ using System.Threading; using System.Threading.Tasks; using osu.Game.Database; -using osu.Game.Users; +using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Tests.Visual { public class TestUserLookupCache : UserLookupCache { /// - /// A special user ID which would return a for. + /// A special user ID which would return a for. /// As a simulation to what a regular would return in the case of failing to fetch the user. /// public const int UNRESOLVED_USER_ID = -1; - protected override Task ComputeValueAsync(int lookup, CancellationToken token = default) + protected override Task ComputeValueAsync(int lookup, CancellationToken token = default) { if (lookup == UNRESOLVED_USER_ID) - return Task.FromResult((User)null); + return Task.FromResult((APIUser)null); - return Task.FromResult(new User + return Task.FromResult(new APIUser { Id = lookup, Username = $"User {lookup}" diff --git a/osu.Game/Users/Drawables/ClickableAvatar.cs b/osu.Game/Users/Drawables/ClickableAvatar.cs index c8af8d80e4..2825c41ef6 100644 --- a/osu.Game/Users/Drawables/ClickableAvatar.cs +++ b/osu.Game/Users/Drawables/ClickableAvatar.cs @@ -9,6 +9,7 @@ using osu.Framework.Input.Events; using osu.Framework.Localisation; using osu.Game.Graphics.Containers; using osu.Game.Graphics.UserInterface; +using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Users.Drawables { @@ -33,7 +34,7 @@ namespace osu.Game.Users.Drawables set => clickableArea.TooltipText = value ? (user?.Username ?? string.Empty) : default_tooltip_text; } - private readonly User user; + private readonly APIUser user; [Resolved(CanBeNull = true)] private OsuGame game { get; set; } @@ -45,7 +46,7 @@ namespace osu.Game.Users.Drawables /// If is true, clicking will open the user's profile. /// /// The user. A null value will get a placeholder avatar. - public ClickableAvatar(User user = null) + public ClickableAvatar(APIUser user = null) { this.user = user; @@ -65,7 +66,7 @@ namespace osu.Game.Users.Drawables private void openProfile() { if (user?.Id > 1) - game?.ShowUser(user.Id); + game?.ShowUser(user); } private class ClickableArea : OsuClickableContainer diff --git a/osu.Game/Users/Drawables/DrawableAvatar.cs b/osu.Game/Users/Drawables/DrawableAvatar.cs index 87860bd149..e6d7bb692d 100644 --- a/osu.Game/Users/Drawables/DrawableAvatar.cs +++ b/osu.Game/Users/Drawables/DrawableAvatar.cs @@ -5,19 +5,20 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; +using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Users.Drawables { [LongRunningLoad] public class DrawableAvatar : Sprite { - private readonly User user; + private readonly APIUser user; /// /// A simple, non-interactable avatar sprite for the specified user. /// /// The user. A null value will get a placeholder avatar. - public DrawableAvatar(User user = null) + public DrawableAvatar(APIUser user = null) { this.user = user; diff --git a/osu.Game/Users/Drawables/UpdateableAvatar.cs b/osu.Game/Users/Drawables/UpdateableAvatar.cs index 6d48104131..8ce6ce3460 100644 --- a/osu.Game/Users/Drawables/UpdateableAvatar.cs +++ b/osu.Game/Users/Drawables/UpdateableAvatar.cs @@ -4,15 +4,16 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Effects; +using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Users.Drawables { /// /// An avatar which can update to a new user when needed. /// - public class UpdateableAvatar : ModelBackedDrawable + public class UpdateableAvatar : ModelBackedDrawable { - public User User + public APIUser User { get => Model; set => Model = value; @@ -55,7 +56,7 @@ namespace osu.Game.Users.Drawables /// If set to true, hover/click sounds will play and clicking the avatar will open the user's profile. /// Whether to show the username rather than "view profile" on the tooltip. (note: this only applies if is also true) /// Whether to show a default guest representation on null user (as opposed to nothing). - public UpdateableAvatar(User user = null, bool isInteractive = true, bool showUsernameTooltip = false, bool showGuestOnNull = true) + public UpdateableAvatar(APIUser user = null, bool isInteractive = true, bool showUsernameTooltip = false, bool showGuestOnNull = true) { this.isInteractive = isInteractive; this.showUsernameTooltip = showUsernameTooltip; @@ -64,7 +65,7 @@ namespace osu.Game.Users.Drawables User = user; } - protected override Drawable CreateDrawable(User user) + protected override Drawable CreateDrawable(APIUser user) { if (user == null && !showGuestOnNull) return null; diff --git a/osu.Game/Users/ExtendedUserPanel.cs b/osu.Game/Users/ExtendedUserPanel.cs index 24317e6069..fc5e1eca5f 100644 --- a/osu.Game/Users/ExtendedUserPanel.cs +++ b/osu.Game/Users/ExtendedUserPanel.cs @@ -11,6 +11,7 @@ using osu.Game.Graphics.Sprites; using osu.Framework.Graphics.Sprites; using osu.Game.Users.Drawables; using osu.Framework.Input.Events; +using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Users { @@ -25,7 +26,7 @@ namespace osu.Game.Users private SpriteIcon statusIcon; private OsuSpriteText statusMessage; - protected ExtendedUserPanel(User user) + protected ExtendedUserPanel(APIUser user) : base(user) { } diff --git a/osu.Game/Users/IUser.cs b/osu.Game/Users/IUser.cs new file mode 100644 index 0000000000..3995531fd9 --- /dev/null +++ b/osu.Game/Users/IUser.cs @@ -0,0 +1,14 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Game.Database; + +namespace osu.Game.Users +{ + public interface IUser : IHasOnlineID + { + string Username { get; } + + bool IsBot { get; } + } +} diff --git a/osu.Game/Users/User.cs b/osu.Game/Users/User.cs deleted file mode 100644 index 20c23153f0..0000000000 --- a/osu.Game/Users/User.cs +++ /dev/null @@ -1,294 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Linq; -using JetBrains.Annotations; -using Newtonsoft.Json; -using osu.Framework.Bindables; -using osu.Game.Online.API.Requests; - -namespace osu.Game.Users -{ - public class User : IEquatable - { - [JsonProperty(@"id")] - public int Id = 1; - - [JsonProperty(@"join_date")] - public DateTimeOffset JoinDate; - - [JsonProperty(@"username")] - public string Username; - - [JsonProperty(@"previous_usernames")] - public string[] PreviousUsernames; - - [JsonProperty(@"country")] - public Country Country; - - public readonly Bindable Status = new Bindable(); - - public readonly Bindable Activity = new Bindable(); - - //public Team Team; - - [JsonProperty(@"profile_colour")] - public string Colour; - - [JsonProperty(@"avatar_url")] - public string AvatarUrl; - - [JsonProperty(@"cover_url")] - public string CoverUrl - { - get => Cover?.Url; - set => Cover = new UserCover { Url = value }; - } - - [JsonProperty(@"cover")] - public UserCover Cover; - - public class UserCover - { - [JsonProperty(@"custom_url")] - public string CustomUrl; - - [JsonProperty(@"url")] - public string Url; - - [JsonProperty(@"id")] - public int? Id; - } - - [JsonProperty(@"is_admin")] - public bool IsAdmin; - - [JsonProperty(@"is_supporter")] - public bool IsSupporter; - - [JsonProperty(@"support_level")] - public int SupportLevel; - - [JsonProperty(@"is_gmt")] - public bool IsGMT; - - [JsonProperty(@"is_qat")] - public bool IsQAT; - - [JsonProperty(@"is_bng")] - public bool IsBNG; - - [JsonProperty(@"is_bot")] - public bool IsBot; - - [JsonProperty(@"is_active")] - public bool Active; - - [JsonProperty(@"is_online")] - public bool IsOnline; - - [JsonProperty(@"pm_friends_only")] - public bool PMFriendsOnly; - - [JsonProperty(@"interests")] - public string Interests; - - [JsonProperty(@"occupation")] - public string Occupation; - - [JsonProperty(@"title")] - public string Title; - - [JsonProperty(@"location")] - public string Location; - - [JsonProperty(@"last_visit")] - public DateTimeOffset? LastVisit; - - [JsonProperty(@"twitter")] - public string Twitter; - - [JsonProperty(@"discord")] - public string Discord; - - [JsonProperty(@"website")] - public string Website; - - [JsonProperty(@"post_count")] - public int PostCount; - - [JsonProperty(@"comments_count")] - public int CommentsCount; - - [JsonProperty(@"follower_count")] - public int FollowerCount; - - [JsonProperty(@"mapping_follower_count")] - public int MappingFollowerCount; - - [JsonProperty(@"favourite_beatmapset_count")] - public int FavouriteBeatmapsetCount; - - [JsonProperty(@"graveyard_beatmapset_count")] - public int GraveyardBeatmapsetCount; - - [JsonProperty(@"loved_beatmapset_count")] - public int LovedBeatmapsetCount; - - [JsonProperty(@"ranked_beatmapset_count")] - public int RankedBeatmapsetCount; - - [JsonProperty(@"pending_beatmapset_count")] - public int PendingBeatmapsetCount; - - [JsonProperty(@"scores_best_count")] - public int ScoresBestCount; - - [JsonProperty(@"scores_first_count")] - public int ScoresFirstCount; - - [JsonProperty(@"scores_recent_count")] - public int ScoresRecentCount; - - [JsonProperty(@"beatmap_playcounts_count")] - public int BeatmapPlaycountsCount; - - [JsonProperty] - private string[] playstyle - { - set => PlayStyles = value?.Select(str => Enum.Parse(typeof(PlayStyle), str, true)).Cast().ToArray(); - } - - public PlayStyle[] PlayStyles; - - [JsonProperty(@"playmode")] - public string PlayMode; - - [JsonProperty(@"profile_order")] - public string[] ProfileOrder; - - [JsonProperty(@"kudosu")] - public KudosuCount Kudosu; - - public class KudosuCount - { - [JsonProperty(@"total")] - public int Total; - - [JsonProperty(@"available")] - public int Available; - } - - private UserStatistics statistics; - - /// - /// User statistics for the requested ruleset (in the case of a or response). - /// Otherwise empty. - /// - [JsonProperty(@"statistics")] - public UserStatistics Statistics - { - get => statistics ??= new UserStatistics(); - set - { - if (statistics != null) - // we may already have rank history populated - value.RankHistory = statistics.RankHistory; - - statistics = value; - } - } - - [JsonProperty(@"rank_history")] - private RankHistoryData rankHistory - { - set => statistics.RankHistory = value; - } - - public class RankHistoryData - { - [JsonProperty(@"mode")] - public string Mode; - - [JsonProperty(@"data")] - public int[] Data; - } - - [JsonProperty("badges")] - public Badge[] Badges; - - [JsonProperty("user_achievements")] - public UserAchievement[] Achievements; - - public class UserAchievement - { - [JsonProperty("achieved_at")] - public DateTimeOffset AchievedAt; - - [JsonProperty("achievement_id")] - public int ID; - } - - [JsonProperty("monthly_playcounts")] - public UserHistoryCount[] MonthlyPlaycounts; - - [JsonProperty("replays_watched_counts")] - public UserHistoryCount[] ReplaysWatchedCounts; - - /// - /// All user statistics per ruleset's short name (in the case of a response). - /// Otherwise empty. Can be altered for testing purposes. - /// - // todo: this should likely be moved to a separate UserCompact class at some point. - [JsonProperty("statistics_rulesets")] - [CanBeNull] - public Dictionary RulesetsStatistics { get; set; } - - public override string ToString() => Username; - - /// - /// A user instance for displaying locally created system messages. - /// - public static readonly User SYSTEM_USER = new User - { - Username = "system", - Colour = @"9c0101", - Id = 0 - }; - - public bool Equals(User other) - { - if (ReferenceEquals(null, other)) return false; - if (ReferenceEquals(this, other)) return true; - - return Id == other.Id; - } - - public enum PlayStyle - { - [Description("Keyboard")] - Keyboard, - - [Description("Mouse")] - Mouse, - - [Description("Tablet")] - Tablet, - - [Description("Touch Screen")] - Touch, - } - - public class UserHistoryCount - { - [JsonProperty("start_date")] - public DateTime Date; - - [JsonProperty("count")] - public long Count; - } - } -} diff --git a/osu.Game/Users/UserBrickPanel.cs b/osu.Game/Users/UserBrickPanel.cs index 9ca7768187..3debdb6e72 100644 --- a/osu.Game/Users/UserBrickPanel.cs +++ b/osu.Game/Users/UserBrickPanel.cs @@ -7,13 +7,14 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; +using osu.Game.Online.API.Requests.Responses; using osuTK; namespace osu.Game.Users { public class UserBrickPanel : UserPanel { - public UserBrickPanel(User user) + public UserBrickPanel(APIUser user) : base(user) { AutoSizeAxes = Axes.Both; diff --git a/osu.Game/Users/UserCoverBackground.cs b/osu.Game/Users/UserCoverBackground.cs index 34bbf6892e..3f1f838b27 100644 --- a/osu.Game/Users/UserCoverBackground.cs +++ b/osu.Game/Users/UserCoverBackground.cs @@ -10,19 +10,20 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; +using osu.Game.Online.API.Requests.Responses; using osuTK.Graphics; namespace osu.Game.Users { - public class UserCoverBackground : ModelBackedDrawable + public class UserCoverBackground : ModelBackedDrawable { - public User User + public APIUser User { get => Model; set => Model = value; } - protected override Drawable CreateDrawable(User user) => new Cover(user); + protected override Drawable CreateDrawable(APIUser user) => new Cover(user); protected override double LoadDelay => 300; @@ -37,9 +38,9 @@ namespace osu.Game.Users [LongRunningLoad] private class Cover : CompositeDrawable { - private readonly User user; + private readonly APIUser user; - public Cover(User user) + public Cover(APIUser user) { this.user = user; diff --git a/osu.Game/Users/UserGridPanel.cs b/osu.Game/Users/UserGridPanel.cs index 44dcbc305d..c37eeb1cbf 100644 --- a/osu.Game/Users/UserGridPanel.cs +++ b/osu.Game/Users/UserGridPanel.cs @@ -4,6 +4,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays.Profile.Header.Components; using osuTK; @@ -13,7 +14,7 @@ namespace osu.Game.Users { private const int margin = 10; - public UserGridPanel(User user) + public UserGridPanel(APIUser user) : base(user) { Height = 120; diff --git a/osu.Game/Users/UserListPanel.cs b/osu.Game/Users/UserListPanel.cs index cc4fca9b94..f06e412315 100644 --- a/osu.Game/Users/UserListPanel.cs +++ b/osu.Game/Users/UserListPanel.cs @@ -7,6 +7,7 @@ using osu.Framework.Graphics.Colour; using osu.Framework.Extensions.Color4Extensions; using osuTK.Graphics; using osu.Framework.Graphics.Containers; +using osu.Game.Online.API.Requests.Responses; using osuTK; using osu.Game.Overlays.Profile.Header.Components; @@ -14,7 +15,7 @@ namespace osu.Game.Users { public class UserListPanel : ExtendedUserPanel { - public UserListPanel(User user) + public UserListPanel(APIUser user) : base(user) { RelativeSizeAxes = Axes.X; diff --git a/osu.Game/Users/UserPanel.cs b/osu.Game/Users/UserPanel.cs index ff0d03a036..248debf1d3 100644 --- a/osu.Game/Users/UserPanel.cs +++ b/osu.Game/Users/UserPanel.cs @@ -13,12 +13,13 @@ using osu.Game.Graphics.UserInterface; using osu.Framework.Graphics.Cursor; using osu.Game.Graphics.Containers; using JetBrains.Annotations; +using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Users { public abstract class UserPanel : OsuClickableContainer, IHasContextMenu { - public readonly User User; + public readonly APIUser User; /// /// Perform an action in addition to showing the user's profile. @@ -30,7 +31,7 @@ namespace osu.Game.Users protected Drawable Background { get; private set; } - protected UserPanel(User user) + protected UserPanel(APIUser user) : base(HoverSampleSet.Submit) { if (user == null) diff --git a/osu.Game/Users/UserStatistics.cs b/osu.Game/Users/UserStatistics.cs index 449b0aa212..c690447256 100644 --- a/osu.Game/Users/UserStatistics.cs +++ b/osu.Game/Users/UserStatistics.cs @@ -4,16 +4,16 @@ using System; using Newtonsoft.Json; using osu.Framework.Localisation; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Scoring; using osu.Game.Utils; -using static osu.Game.Users.User; namespace osu.Game.Users { public class UserStatistics { [JsonProperty] - public User User; + public APIUser User; [JsonProperty(@"level")] public LevelInfo Level; @@ -34,7 +34,7 @@ namespace osu.Game.Users public int? CountryRank; // populated via User model, as that's where the data currently lives. - public RankHistoryData RankHistory; + public APIRankHistory RankHistory; [JsonProperty(@"pp")] public decimal? PP; diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 7811de5764..df3c9b355a 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -36,7 +36,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/osu.iOS.props b/osu.iOS.props index 9d95b7c765..1852957e87 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -70,7 +70,7 @@ - + @@ -93,7 +93,7 @@ - +