1
0
mirror of https://github.com/ppy/osu.git synced 2026-05-20 16:00:46 +08:00

Compare commits

..

5 Commits

71 changed files with 338 additions and 376 deletions
-3
View File
@@ -4,9 +4,6 @@ concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read # to fetch code (actions/checkout)
jobs:
inspect-code:
name: Code Quality
-4
View File
@@ -8,12 +8,8 @@ on:
workflows: ["Continuous Integration"]
types:
- completed
permissions: {}
jobs:
annotate:
permissions:
checks: write # to create checks (dorny/test-reporter)
name: Annotate CI run with test results
runs-on: ubuntu-latest
if: ${{ github.event.workflow_run.conclusion != 'cancelled' }}
-3
View File
@@ -5,9 +5,6 @@ on:
tags:
- '*'
permissions:
contents: read # to fetch code (actions/checkout)
jobs:
sentry_release:
runs-on: ubuntu-latest
+1 -1
View File
@@ -52,7 +52,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="ppy.osu.Game.Resources" Version="2022.831.0" />
<PackageReference Include="ppy.osu.Framework.Android" Version="2022.922.0" />
<PackageReference Include="ppy.osu.Framework.Android" Version="2022.916.1" />
</ItemGroup>
<ItemGroup Label="Transitive Dependencies">
<!-- Realm needs to be directly referenced in all Xamarin projects, as it will not pull in its transitive dependencies otherwise. -->
@@ -17,15 +17,21 @@ namespace osu.Game.Rulesets.Catch.Mods
public override double ScoreMultiplier => UsesDefaultConfiguration ? 1.12 : 1;
[SettingSource("Flashlight size", "Multiplier applied to the default flashlight size.")]
public override BindableFloat SizeMultiplier { get; } = new BindableFloat(1)
public override BindableFloat SizeMultiplier { get; } = new BindableFloat
{
MinValue = 0.5f,
MaxValue = 1.5f,
Default = 1f,
Value = 1f,
Precision = 0.1f
};
[SettingSource("Change size based on combo", "Decrease the flashlight size as combo increases.")]
public override BindableBool ComboBasedSize { get; } = new BindableBool(true);
public override BindableBool ComboBasedSize { get; } = new BindableBool
{
Default = true,
Value = true
};
public override float DefaultFlashlightSize => 350;
@@ -22,8 +22,10 @@ namespace osu.Game.Rulesets.Catch.Mods
"The combo count at which the catcher becomes completely hidden",
SettingControlType = typeof(SettingsSlider<int, HiddenComboSlider>)
)]
public override BindableInt HiddenComboCount { get; } = new BindableInt(10)
public override BindableInt HiddenComboCount { get; } = new BindableInt
{
Default = 10,
Value = 10,
MinValue = 0,
MaxValue = 50,
};
@@ -18,15 +18,21 @@ namespace osu.Game.Rulesets.Mania.Mods
public override Type[] IncompatibleMods => new[] { typeof(ModHidden) };
[SettingSource("Flashlight size", "Multiplier applied to the default flashlight size.")]
public override BindableFloat SizeMultiplier { get; } = new BindableFloat(1)
public override BindableFloat SizeMultiplier { get; } = new BindableFloat
{
MinValue = 0.5f,
MaxValue = 3f,
Default = 1f,
Value = 1f,
Precision = 0.1f
};
[SettingSource("Change size based on combo", "Decrease the flashlight size as combo increases.")]
public override BindableBool ComboBasedSize { get; } = new BindableBool();
public override BindableBool ComboBasedSize { get; } = new BindableBool
{
Default = false,
Value = false
};
public override float DefaultFlashlightSize => 50;
@@ -56,7 +56,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators
if (!(currentObj.BaseObject is Spinner))
{
double jumpDistance = (osuHitObject.StackedPosition - currentHitObject.StackedEndPosition).Length;
double jumpDistance = (osuHitObject.StackedPosition - currentHitObject.EndPosition).Length;
cumulativeStrainTime += lastObj.StrainTime;
+3 -1
View File
@@ -19,10 +19,12 @@ namespace osu.Game.Rulesets.Osu.Mods
public override LocalisableString Description => "Hit them at the right size!";
[SettingSource("Starting Size", "The initial size multiplier applied to all objects.")]
public override BindableNumber<float> StartScale { get; } = new BindableFloat(2)
public override BindableNumber<float> StartScale { get; } = new BindableFloat
{
MinValue = 1f,
MaxValue = 25f,
Default = 2f,
Value = 2f,
Precision = 0.1f,
};
}
@@ -33,15 +33,21 @@ namespace osu.Game.Rulesets.Osu.Mods
};
[SettingSource("Flashlight size", "Multiplier applied to the default flashlight size.")]
public override BindableFloat SizeMultiplier { get; } = new BindableFloat(1)
public override BindableFloat SizeMultiplier { get; } = new BindableFloat
{
MinValue = 0.5f,
MaxValue = 2f,
Default = 1f,
Value = 1f,
Precision = 0.1f
};
[SettingSource("Change size based on combo", "Decrease the flashlight size as combo increases.")]
public override BindableBool ComboBasedSize { get; } = new BindableBool(true);
public override BindableBool ComboBasedSize { get; } = new BindableBool
{
Default = true,
Value = true
};
public override float DefaultFlashlightSize => 180;
+3 -1
View File
@@ -19,10 +19,12 @@ namespace osu.Game.Rulesets.Osu.Mods
public override LocalisableString Description => "Hit them at the right size!";
[SettingSource("Starting Size", "The initial size multiplier applied to all objects.")]
public override BindableNumber<float> StartScale { get; } = new BindableFloat(0.5f)
public override BindableNumber<float> StartScale { get; } = new BindableFloat
{
MinValue = 0f,
MaxValue = 0.99f,
Default = 0.5f,
Value = 0.5f,
Precision = 0.01f,
};
}
+3 -1
View File
@@ -27,8 +27,10 @@ namespace osu.Game.Rulesets.Osu.Mods
"The combo count at which the cursor becomes completely hidden",
SettingControlType = typeof(SettingsSlider<int, HiddenComboSlider>)
)]
public override BindableInt HiddenComboCount { get; } = new BindableInt(10)
public override BindableInt HiddenComboCount { get; } = new BindableInt
{
Default = 10,
Value = 10,
MinValue = 0,
MaxValue = 50,
};
+3 -1
View File
@@ -29,8 +29,10 @@ namespace osu.Game.Rulesets.Osu.Mods
public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(OsuModTarget)).ToArray();
[SettingSource("Angle sharpness", "How sharp angles should be", SettingControlType = typeof(SettingsSlider<float>))]
public BindableFloat AngleSharpness { get; } = new BindableFloat(7)
public BindableFloat AngleSharpness { get; } = new BindableFloat
{
Default = 7,
Value = 7,
MinValue = 1,
MaxValue = 10,
Precision = 0.1f
+5 -1
View File
@@ -53,7 +53,11 @@ namespace osu.Game.Rulesets.Osu.Mods
}).ToArray();
[SettingSource("Seed", "Use a custom seed instead of a random one", SettingControlType = typeof(SettingsNumberBox))]
public Bindable<int?> Seed { get; } = new Bindable<int?>();
public Bindable<int?> Seed { get; } = new Bindable<int?>
{
Default = null,
Value = null
};
[SettingSource("Metronome ticks", "Whether a metronome beat should play in the background")]
public Bindable<bool> Metronome { get; } = new BindableBool(true);
+1 -1
View File
@@ -27,7 +27,7 @@ namespace osu.Game.Rulesets.Osu.Objects
// This is so on repeats ticks don't appear too late to be visually processed by the player.
offset = 200;
else
offset = TimePreempt * 0.66f;
offset = TimeFadeIn * 0.66f;
TimePreempt = (StartTime - SpanStartTime) / 2 + offset;
}
@@ -18,15 +18,21 @@ namespace osu.Game.Rulesets.Taiko.Mods
public override double ScoreMultiplier => UsesDefaultConfiguration ? 1.12 : 1;
[SettingSource("Flashlight size", "Multiplier applied to the default flashlight size.")]
public override BindableFloat SizeMultiplier { get; } = new BindableFloat(1)
public override BindableFloat SizeMultiplier { get; } = new BindableFloat
{
MinValue = 0.5f,
MaxValue = 1.5f,
Default = 1f,
Value = 1f,
Precision = 0.1f
};
[SettingSource("Change size based on combo", "Decrease the flashlight size as combo increases.")]
public override BindableBool ComboBasedSize { get; } = new BindableBool(true);
public override BindableBool ComboBasedSize { get; } = new BindableBool
{
Default = true,
Value = true
};
public override float DefaultFlashlightSize => 250;
@@ -204,23 +204,31 @@ namespace osu.Game.Tests.Online
public override double ScoreMultiplier => 1;
[SettingSource("Initial rate", "The starting speed of the track")]
public override BindableNumber<double> InitialRate { get; } = new BindableDouble(1.5)
public override BindableNumber<double> InitialRate { get; } = new BindableDouble
{
MinValue = 1,
MaxValue = 2,
Default = 1.5,
Value = 1.5,
Precision = 0.01,
};
[SettingSource("Final rate", "The speed increase to ramp towards")]
public override BindableNumber<double> FinalRate { get; } = new BindableDouble(0.5)
public override BindableNumber<double> FinalRate { get; } = new BindableDouble
{
MinValue = 0,
MaxValue = 1,
Default = 0.5,
Value = 0.5,
Precision = 0.01,
};
[SettingSource("Adjust pitch", "Should pitch be adjusted with speed")]
public override BindableBool AdjustPitch { get; } = new BindableBool(true);
public override BindableBool AdjustPitch { get; } = new BindableBool
{
Default = true,
Value = true
};
}
private class TestModDifficultyAdjust : ModDifficultyAdjust
@@ -124,23 +124,31 @@ namespace osu.Game.Tests.Online
public override double ScoreMultiplier => 1;
[SettingSource("Initial rate", "The starting speed of the track")]
public override BindableNumber<double> InitialRate { get; } = new BindableDouble(1.5)
public override BindableNumber<double> InitialRate { get; } = new BindableDouble
{
MinValue = 1,
MaxValue = 2,
Default = 1.5,
Value = 1.5,
Precision = 0.01,
};
[SettingSource("Final rate", "The speed increase to ramp towards")]
public override BindableNumber<double> FinalRate { get; } = new BindableDouble(0.5)
public override BindableNumber<double> FinalRate { get; } = new BindableDouble
{
MinValue = 0,
MaxValue = 1,
Default = 0.5,
Value = 0.5,
Precision = 0.01,
};
[SettingSource("Adjust pitch", "Should pitch be adjusted with speed")]
public override BindableBool AdjustPitch { get; } = new BindableBool(true);
public override BindableBool AdjustPitch { get; } = new BindableBool
{
Default = true,
Value = true
};
}
private class TestModEnum : Mod
@@ -9,7 +9,6 @@ using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Testing;
using osu.Framework.Utils;
using osu.Game.Configuration;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Scoring;
@@ -25,16 +24,6 @@ namespace osu.Game.Tests.Visual.Gameplay
private readonly BindableList<ScoreInfo> scores = new BindableList<ScoreInfo>();
private readonly Bindable<bool> configVisibility = new Bindable<bool>();
private SoloGameplayLeaderboard leaderboard = null!;
[BackgroundDependencyLoader]
private void load(OsuConfigManager config)
{
config.BindWith(OsuSetting.GameplayLeaderboard, configVisibility);
}
[SetUpSteps]
public void SetUpSteps()
{
@@ -48,12 +37,11 @@ namespace osu.Game.Tests.Visual.Gameplay
Id = 2,
};
Child = leaderboard = new SoloGameplayLeaderboard(trackingUser)
Child = new SoloGameplayLeaderboard(trackingUser)
{
Scores = { BindTarget = scores },
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
AlwaysVisible = { Value = false },
Expanded = { Value = true },
};
});
@@ -69,22 +57,6 @@ namespace osu.Game.Tests.Visual.Gameplay
AddSliderStep("combo", 0, 1000, 0, v => scoreProcessor.Combo.Value = v);
}
[Test]
public void TestVisibility()
{
AddStep("set config visible true", () => configVisibility.Value = true);
AddUntilStep("leaderboard visible", () => leaderboard.Alpha == 1);
AddStep("set config visible false", () => configVisibility.Value = false);
AddUntilStep("leaderboard not visible", () => leaderboard.Alpha == 0);
AddStep("set always visible", () => leaderboard.AlwaysVisible.Value = true);
AddUntilStep("leaderboard visible", () => leaderboard.Alpha == 1);
AddStep("set config visible true", () => configVisibility.Value = true);
AddAssert("leaderboard still visible", () => leaderboard.Alpha == 1);
}
private static List<ScoreInfo> createSampleScores()
{
return new[]
@@ -29,7 +29,11 @@ namespace osu.Game.Tests.Visual.Settings
{
Child = textBox = new SettingsTextBox
{
Current = new Bindable<string>("test")
Current = new Bindable<string>
{
Default = "test",
Value = "test"
}
};
});
AddUntilStep("wait for loaded", () => textBox.IsLoaded);
@@ -55,7 +59,11 @@ namespace osu.Game.Tests.Visual.Settings
{
Child = textBox = new SettingsTextBox
{
Current = new Bindable<string>("test")
Current = new Bindable<string>
{
Default = "test",
Value = "test"
}
};
});
AddUntilStep("wait for loaded", () => textBox.IsLoaded);
@@ -67,7 +67,11 @@ namespace osu.Game.Tests.Visual.Settings
};
[SettingSource("Sample number textbox", "Textbox number entry", SettingControlType = typeof(SettingsNumberBox))]
public Bindable<int?> IntTextBoxBindable { get; } = new Bindable<int?>();
public Bindable<int?> IntTextBoxBindable { get; } = new Bindable<int?>
{
Default = null,
Value = null
};
}
private enum TestEnum
@@ -1,6 +1,8 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using System;
using System.Collections.Generic;
using System.Linq;
@@ -34,9 +36,10 @@ namespace osu.Game.Tests.Visual.SongSelect
[Cached(typeof(IDialogOverlay))]
private readonly DialogOverlay dialogOverlay;
private ScoreManager scoreManager = null!;
private RulesetStore rulesetStore = null!;
private BeatmapManager beatmapManager = null!;
private ScoreManager scoreManager;
private RulesetStore rulesetStore;
private BeatmapManager beatmapManager;
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
{
@@ -71,7 +74,7 @@ namespace osu.Game.Tests.Visual.SongSelect
[Test]
public void TestLocalScoresDisplay()
{
BeatmapInfo beatmapInfo = null!;
BeatmapInfo beatmapInfo = null;
AddStep(@"Set scope", () => leaderboard.Scope = BeatmapLeaderboardScope.Local);
@@ -384,7 +387,7 @@ namespace osu.Game.Tests.Visual.SongSelect
private class FailableLeaderboard : BeatmapLeaderboard
{
public new void SetErrorState(LeaderboardState state) => base.SetErrorState(state);
public new void SetScores(IEnumerable<ScoreInfo>? scores, ScoreInfo? userScore = null) => base.SetScores(scores, userScore);
public new void SetScores(IEnumerable<ScoreInfo> scores, ScoreInfo userScore = default) => base.SetScores(scores, userScore);
}
}
}
@@ -163,7 +163,7 @@ namespace osu.Game.Tests.Visual.UserInterface
InputManager.PressButton(MouseButton.Left);
});
AddUntilStep("wait for fetch", () => leaderboard.Scores.Any());
AddUntilStep("wait for fetch", () => leaderboard.Scores != null);
AddUntilStep("score removed from leaderboard", () => leaderboard.Scores.All(s => s.OnlineID != scoreBeingDeleted.OnlineID));
// "Clean up"
@@ -174,7 +174,7 @@ namespace osu.Game.Tests.Visual.UserInterface
public void TestDeleteViaDatabase()
{
AddStep("delete top score", () => scoreManager.Delete(importedScores[0]));
AddUntilStep("wait for fetch", () => leaderboard.Scores.Any());
AddUntilStep("wait for fetch", () => leaderboard.Scores != null);
AddUntilStep("score removed from leaderboard", () => leaderboard.Scores.All(s => s.OnlineID != importedScores[0].OnlineID));
}
}
@@ -107,9 +107,9 @@ namespace osu.Game.Tests.Visual.UserInterface
AddStep("start drag", () =>
{
InputManager.MoveMouseTo(notificationOverlay.ChildrenOfType<Notification>().Single());
InputManager.MoveMouseTo(notification.ChildrenOfType<Notification>().Single());
InputManager.PressButton(MouseButton.Left);
InputManager.MoveMouseTo(notificationOverlay.ChildrenOfType<Notification>().Single().ScreenSpaceDrawQuad.Centre + new Vector2(-500, 0));
InputManager.MoveMouseTo(notification.ChildrenOfType<Notification>().Single().ScreenSpaceDrawQuad.Centre + new Vector2(-500, 0));
});
AddStep("fling away", () =>
@@ -123,45 +123,6 @@ namespace osu.Game.Tests.Visual.UserInterface
AddAssert("unread count zero", () => notificationOverlay.UnreadCount.Value == 0);
}
[Test]
public void TestProgressNotificationCantBeFlung()
{
bool activated = false;
ProgressNotification notification = null!;
AddStep("post", () =>
{
activated = false;
notificationOverlay.Post(notification = new ProgressNotification
{
Text = @"Uploading to BSS...",
CompletionText = "Uploaded to BSS!",
Activated = () => activated = true,
});
progressingNotifications.Add(notification);
});
AddStep("start drag", () =>
{
InputManager.MoveMouseTo(notificationOverlay.ChildrenOfType<Notification>().Single());
InputManager.PressButton(MouseButton.Left);
InputManager.MoveMouseTo(notificationOverlay.ChildrenOfType<Notification>().Single().ScreenSpaceDrawQuad.Centre + new Vector2(-500, 0));
});
AddStep("attempt fling", () =>
{
InputManager.ReleaseButton(MouseButton.Left);
});
AddUntilStep("was not closed", () => !notification.WasClosed);
AddUntilStep("was not cancelled", () => notification.State == ProgressNotificationState.Active);
AddAssert("was not activated", () => !activated);
AddStep("reset mouse position", () => InputManager.MoveMouseTo(Vector2.Zero));
AddUntilStep("was completed", () => notification.State == ProgressNotificationState.Completed);
}
[Test]
public void TestDismissWithoutActivationCloseButton()
{
@@ -24,6 +24,7 @@ namespace osu.Game.Beatmaps.ControlPoints
public readonly BindableDouble SliderVelocityBindable = new BindableDouble(1)
{
Precision = 0.01,
Default = 1,
MinValue = 0.1,
MaxValue = 10
};
@@ -28,6 +28,7 @@ namespace osu.Game.Beatmaps.ControlPoints
public readonly BindableDouble ScrollSpeedBindable = new BindableDouble(1)
{
Precision = 0.01,
Default = 1,
MinValue = 0.01,
MaxValue = 10
};
@@ -45,6 +45,7 @@ namespace osu.Game.Beatmaps.ControlPoints
{
MinValue = 0,
MaxValue = 100,
Default = 100
};
/// <summary>
@@ -49,6 +49,7 @@ namespace osu.Game.Beatmaps.ControlPoints
/// </summary>
public readonly BindableDouble BeatLengthBindable = new BindableDouble(DEFAULT_BEAT_LENGTH)
{
Default = DEFAULT_BEAT_LENGTH,
MinValue = 6,
MaxValue = 60000
};
@@ -131,7 +131,6 @@ namespace osu.Game.Configuration
SetDefault(OsuSetting.ShowHealthDisplayWhenCantFail, true);
SetDefault(OsuSetting.FadePlayfieldWhenHealthLow, true);
SetDefault(OsuSetting.KeyOverlay, false);
SetDefault(OsuSetting.GameplayLeaderboard, true);
SetDefault(OsuSetting.AlwaysPlayFirstComboBreak, true);
SetDefault(OsuSetting.FloatingComments, false);
@@ -295,7 +294,6 @@ namespace osu.Game.Configuration
LightenDuringBreaks,
ShowStoryboard,
KeyOverlay,
GameplayLeaderboard,
PositionalHitsounds,
PositionalHitsoundsLevel,
AlwaysPlayFirstComboBreak,
@@ -79,11 +79,6 @@ namespace osu.Game.Localisation
/// </summary>
public static LocalisableString AlwaysShowKeyOverlay => new TranslatableString(getKey(@"key_overlay"), @"Always show key overlay");
/// <summary>
/// "Always show gameplay leaderboard"
/// </summary>
public static LocalisableString AlwaysShowGameplayLeaderboard => new TranslatableString(getKey(@"gameplay_leaderboard"), @"Always show gameplay leaderboard");
/// <summary>
/// "Always play first combo break sound"
/// </summary>
@@ -228,7 +228,7 @@ namespace osu.Game.Online.API.Requests.Responses
[JsonProperty(@"rank_history")]
private APIRankHistory rankHistory
{
set => Statistics.RankHistory = value;
set => statistics.RankHistory = value;
}
[JsonProperty("badges")]
+18 -19
View File
@@ -1,11 +1,14 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using JetBrains.Annotations;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Development;
@@ -51,23 +54,23 @@ namespace osu.Game.Online.Leaderboards
private readonly Container placeholderContainer;
private readonly UserTopScoreContainer<TScoreInfo> userScoreContainer;
private FillFlowContainer<LeaderboardScore>? scoreFlowContainer;
private FillFlowContainer<LeaderboardScore> scoreFlowContainer;
private readonly LoadingSpinner loading;
private CancellationTokenSource? currentFetchCancellationSource;
private CancellationTokenSource? currentScoresAsyncLoadCancellationSource;
private CancellationTokenSource currentFetchCancellationSource;
private CancellationTokenSource currentScoresAsyncLoadCancellationSource;
private APIRequest? fetchScoresRequest;
private APIRequest fetchScoresRequest;
private LeaderboardState state;
[Resolved(CanBeNull = true)]
private IAPIProvider? api { get; set; }
private IAPIProvider api { get; set; }
private readonly IBindable<APIState> apiState = new Bindable<APIState>();
private TScope scope = default!;
private TScope scope;
public TScope Scope
{
@@ -176,21 +179,16 @@ namespace osu.Game.Online.Leaderboards
/// </summary>
/// <param name="scores">The scores to display.</param>
/// <param name="userScore">The user top score, if any.</param>
protected void SetScores(IEnumerable<TScoreInfo>? scores, TScoreInfo? userScore = default)
protected void SetScores(IEnumerable<TScoreInfo> scores, TScoreInfo userScore = default)
{
this.scores.Clear();
if (scores != null)
this.scores.AddRange(scores);
// Non-delayed schedule may potentially run inline (due to IsMainThread check passing) after leaderboard is disposed.
// This is guarded against in BeatmapLeaderboard via web request cancellation, but let's be extra safe.
if (!IsDisposed)
{
// Schedule needs to be non-delayed here for the weird logic in refetchScores to work.
// If it is removed, the placeholder will be incorrectly updated to "no scores" rather than "retrieving".
// This whole flow should be refactored in the future.
Scheduler.Add(applyNewScores, false);
}
// Schedule needs to be non-delayed here for the weird logic in refetchScores to work.
// If it is removed, the placeholder will be incorrectly updated to "no scores" rather than "retrieving".
// This whole flow should be refactored in the future.
Scheduler.Add(applyNewScores, false);
void applyNewScores()
{
@@ -210,7 +208,8 @@ namespace osu.Game.Online.Leaderboards
/// </summary>
/// <param name="cancellationToken"></param>
/// <returns>An <see cref="APIRequest"/> responsible for the fetch operation. This will be queued and performed automatically.</returns>
protected abstract APIRequest? FetchScores(CancellationToken cancellationToken);
[CanBeNull]
protected abstract APIRequest FetchScores(CancellationToken cancellationToken);
protected abstract LeaderboardScore CreateDrawableScore(TScoreInfo model, int index);
@@ -294,7 +293,7 @@ namespace osu.Game.Online.Leaderboards
#region Placeholder handling
private Placeholder? placeholder;
private Placeholder placeholder;
private void setState(LeaderboardState state)
{
@@ -321,7 +320,7 @@ namespace osu.Game.Online.Leaderboards
placeholder.FadeInFromZero(fade_duration, Easing.OutQuint);
}
private Placeholder? getPlaceholderFor(LeaderboardState state)
private Placeholder getPlaceholderFor(LeaderboardState state)
{
switch (state)
{
@@ -1,6 +1,8 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using System;
using System.Threading;
using osu.Framework.Bindables;
@@ -16,15 +18,13 @@ namespace osu.Game.Online.Leaderboards
{
private const int duration = 500;
public Bindable<TScoreInfo?> Score = new Bindable<TScoreInfo?>();
public Bindable<TScoreInfo> Score = new Bindable<TScoreInfo>();
private readonly Container scoreContainer;
private readonly Func<TScoreInfo, LeaderboardScore> createScoreDelegate;
protected override bool StartHidden => true;
private CancellationTokenSource? loadScoreCancellation;
public UserTopScoreContainer(Func<TScoreInfo, LeaderboardScore> createScoreDelegate)
{
this.createScoreDelegate = createScoreDelegate;
@@ -65,7 +65,9 @@ namespace osu.Game.Online.Leaderboards
Score.BindValueChanged(onScoreChanged);
}
private void onScoreChanged(ValueChangedEvent<TScoreInfo?> score)
private CancellationTokenSource loadScoreCancellation;
private void onScoreChanged(ValueChangedEvent<TScoreInfo> score)
{
var newScore = score.NewValue;
+43 -42
View File
@@ -24,7 +24,6 @@ using osu.Framework.Graphics.Sprites;
using osu.Framework.Input;
using osu.Framework.Input.Bindings;
using osu.Framework.Input.Events;
using osu.Framework.Input.Handlers.Tablet;
using osu.Framework.Localisation;
using osu.Framework.Logging;
using osu.Framework.Screens;
@@ -1039,48 +1038,50 @@ namespace osu.Game
private void forwardTabletLogsToNotifications()
{
const string tablet_prefix = @"[Tablet] ";
bool notifyOnWarning = true;
// Temporarily disabled due to framework downgrade.
Logger.NewEntry += entry =>
{
if (entry.Level < LogLevel.Important || entry.Target != LoggingTarget.Input || !entry.Message.StartsWith(tablet_prefix, StringComparison.OrdinalIgnoreCase))
return;
string message = entry.Message.Replace(tablet_prefix, string.Empty);
if (entry.Level == LogLevel.Error)
{
Schedule(() => Notifications.Post(new SimpleNotification
{
Text = $"Encountered tablet error: \"{message}\"",
Icon = FontAwesome.Solid.PenSquare,
IconColour = Colours.RedDark,
}));
}
else if (notifyOnWarning)
{
Schedule(() => Notifications.Post(new SimpleNotification
{
Text = @"Encountered tablet warning, your tablet may not function correctly. Click here for a list of all tablets supported.",
Icon = FontAwesome.Solid.PenSquare,
IconColour = Colours.YellowDark,
Activated = () =>
{
OpenUrlExternally("https://opentabletdriver.net/Tablets", true);
return true;
}
}));
notifyOnWarning = false;
}
};
Schedule(() =>
{
ITabletHandler tablet = Host.AvailableInputHandlers.OfType<ITabletHandler>().SingleOrDefault();
tablet?.Tablet.BindValueChanged(_ => notifyOnWarning = true, true);
});
// const string tablet_prefix = @"[Tablet] ";
// bool notifyOnWarning = true;
//
// Logger.NewEntry += entry =>
// {
// if (entry.Level < LogLevel.Important || entry.Target != LoggingTarget.Input || !entry.Message.StartsWith(tablet_prefix, StringComparison.OrdinalIgnoreCase))
// return;
//
// string message = entry.Message.Replace(tablet_prefix, string.Empty);
//
// if (entry.Level == LogLevel.Error)
// {
// Schedule(() => Notifications.Post(new SimpleNotification
// {
// Text = $"Encountered tablet error: \"{message}\"",
// Icon = FontAwesome.Solid.PenSquare,
// IconColour = Colours.RedDark,
// }));
// }
// else if (notifyOnWarning)
// {
// Schedule(() => Notifications.Post(new SimpleNotification
// {
// Text = @"Encountered tablet warning, your tablet may not function correctly. Click here for a list of all tablets supported.",
// Icon = FontAwesome.Solid.PenSquare,
// IconColour = Colours.YellowDark,
// Activated = () =>
// {
// OpenUrlExternally("https://opentabletdriver.net/Tablets", true);
// return true;
// }
// }));
//
// notifyOnWarning = false;
// }
// };
//
// Schedule(() =>
// {
// ITabletHandler tablet = Host.AvailableInputHandlers.OfType<ITabletHandler>().SingleOrDefault();
// tablet?.Tablet.BindValueChanged(_ => notifyOnWarning = true, true);
// });
}
private Task asyncLoadStream;
@@ -123,7 +123,7 @@ namespace osu.Game.Overlays.FirstRunSetup
beatmapSubscription?.Dispose();
}
private void beatmapsChanged(IRealmCollection<BeatmapSetInfo> sender, ChangeSet? changes, Exception error) => Schedule(() =>
private void beatmapsChanged(IRealmCollection<BeatmapSetInfo> sender, ChangeSet? changes, Exception error)
{
currentlyLoadedBeatmaps.Text = FirstRunSetupBeatmapScreenStrings.CurrentlyLoadedBeatmaps(sender.Count);
@@ -139,7 +139,7 @@ namespace osu.Game.Overlays.FirstRunSetup
currentlyLoadedBeatmaps.ScaleTo(1.1f)
.ScaleTo(1, 1500, Easing.OutQuint);
}
});
}
private void downloadTutorial()
{
+2 -3
View File
@@ -8,7 +8,6 @@ using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Extensions.EnumExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Effects;
@@ -25,7 +24,7 @@ namespace osu.Game.Overlays.Music
public class PlaylistOverlay : VisibilityContainer
{
private const float transition_duration = 600;
public const float PLAYLIST_HEIGHT = 510;
private const float playlist_height = 510;
private readonly BindableList<Live<BeatmapSetInfo>> beatmapSets = new BindableList<Live<BeatmapSetInfo>>();
@@ -131,7 +130,7 @@ namespace osu.Game.Overlays.Music
filter.Search.HoldFocus = true;
Schedule(() => filter.Search.TakeFocus());
this.ResizeTo(new Vector2(1, RelativeSizeAxes.HasFlagFast(Axes.Y) ? 1f : PLAYLIST_HEIGHT), transition_duration, Easing.OutQuint);
this.ResizeTo(new Vector2(1, playlist_height), transition_duration, Easing.OutQuint);
this.FadeIn(transition_duration, Easing.OutQuint);
}
+7 -4
View File
@@ -58,11 +58,12 @@ namespace osu.Game.Overlays
[Resolved]
private RealmAccess realm { get; set; }
protected override void LoadComplete()
[BackgroundDependencyLoader]
private void load()
{
base.LoadComplete();
beatmap.BindValueChanged(b => changeBeatmap(b.NewValue), true);
// Todo: These binds really shouldn't be here, but are unlikely to cause any issues for now.
// They are placed here for now since some tests rely on setting the beatmap _and_ their hierarchies inside their load(), which runs before the MusicController's load().
beatmap.BindValueChanged(beatmapChanged, true);
mods.BindValueChanged(_ => ResetTrackAdjustments(), true);
}
@@ -262,6 +263,8 @@ namespace osu.Game.Overlays
private IQueryable<BeatmapSetInfo> getBeatmapSets() => realm.Realm.All<BeatmapSetInfo>().Where(s => !s.DeletePending);
private void beatmapChanged(ValueChangedEvent<WorkingBeatmap> beatmap) => changeBeatmap(beatmap.NewValue);
private void changeBeatmap(WorkingBeatmap newWorking)
{
// This method can potentially be triggered multiple times as it is eagerly fired in next() / prev() to ensure correct execution order
+1 -4
View File
@@ -113,12 +113,9 @@ namespace osu.Game.Overlays
if (enabled)
// we want a slight delay before toggling notifications on to avoid the user becoming overwhelmed.
notificationsEnabler = Scheduler.AddDelayed(() => processingPosts = true, State.Value == Visibility.Visible ? 0 : 250);
notificationsEnabler = Scheduler.AddDelayed(() => processingPosts = true, State.Value == Visibility.Visible ? 0 : 100);
else
{
processingPosts = false;
toastTray.FlushAllToasts();
}
}
protected override void LoadComplete()
@@ -68,8 +68,6 @@ namespace osu.Game.Overlays.Notifications
public virtual bool Read { get; set; }
protected virtual bool AllowFlingDismiss => true;
public new bool IsDragged => dragContainer.IsDragged;
protected virtual IconUsage CloseButtonIcon => FontAwesome.Solid.Check;
@@ -317,7 +315,7 @@ namespace osu.Game.Overlays.Notifications
protected override void OnDragEnd(DragEndEvent e)
{
if (notification.AllowFlingDismiss && (Rotation < -10 || velocity.X < -0.3f))
if (Rotation < -10 || velocity.X < -0.3f)
notification.Close(true);
else if (X > 30 || velocity.X > 0.3f)
notification.ForwardToOverlay?.Invoke();
@@ -25,8 +25,6 @@ namespace osu.Game.Overlays.Notifications
public Func<bool>? CancelRequested { get; set; }
protected override bool AllowFlingDismiss => false;
/// <summary>
/// The function to post completion notifications back to.
/// </summary>
+7 -23
View File
@@ -38,7 +38,6 @@ namespace osu.Game.Overlays
private const float transition_length = 800;
private const float progress_height = 10;
private const float bottom_black_area_height = 55;
private const float margin = 10;
private Drawable background;
private ProgressBar progressBar;
@@ -54,7 +53,6 @@ namespace osu.Game.Overlays
private Container dragContainer;
private Container playerContainer;
private Container playlistContainer;
protected override string PopInSampleName => "UI/now-playing-pop-in";
protected override string PopOutSampleName => "UI/now-playing-pop-out";
@@ -71,7 +69,7 @@ namespace osu.Game.Overlays
public NowPlayingOverlay()
{
Width = 400;
Margin = new MarginPadding(margin);
Margin = new MarginPadding(10);
}
[BackgroundDependencyLoader]
@@ -84,6 +82,7 @@ namespace osu.Game.Overlays
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Children = new Drawable[]
{
playerContainer = new Container
@@ -183,13 +182,8 @@ namespace osu.Game.Overlays
}
},
},
playlistContainer = new Container
{
RelativeSizeAxes = Axes.X,
Y = player_height + margin,
}
}
},
}
};
}
@@ -199,10 +193,11 @@ namespace osu.Game.Overlays
{
LoadComponentAsync(playlist = new PlaylistOverlay
{
RelativeSizeAxes = Axes.Both,
RelativeSizeAxes = Axes.X,
Y = player_height + 10,
}, _ =>
{
playlistContainer.Add(playlist);
dragContainer.Add(playlist);
playlist.State.BindValueChanged(s => playlistButton.FadeColour(s.NewValue == Visibility.Visible ? colours.Yellow : Color4.White, 200, Easing.OutQuint), true);
@@ -247,18 +242,7 @@ namespace osu.Game.Overlays
{
base.UpdateAfterChildren();
playlistContainer.Height = MathF.Min(Parent.DrawHeight - margin * 3 - player_height, PlaylistOverlay.PLAYLIST_HEIGHT);
float height = player_height;
if (playlist != null)
{
height += playlist.DrawHeight;
if (playlist.State.Value == Visibility.Visible)
height += margin;
}
Height = dragContainer.Height = height;
Height = dragContainer.Height;
}
protected override void Update()
@@ -38,11 +38,6 @@ namespace osu.Game.Overlays.Settings.Sections.Gameplay
Current = config.GetBindable<bool>(OsuSetting.KeyOverlay),
Keywords = new[] { "counter" },
},
new SettingsCheckbox
{
LabelText = GameplaySettingsStrings.AlwaysShowGameplayLeaderboard,
Current = config.GetBindable<bool>(OsuSetting.GameplayLeaderboard),
},
};
}
}
@@ -215,21 +215,21 @@ namespace osu.Game.Overlays.Settings.Sections.Input
rotation.BindTo(tabletHandler.Rotation);
areaOffset.BindTo(tabletHandler.AreaOffset);
areaOffset.BindValueChanged(val => Schedule(() =>
areaOffset.BindValueChanged(val =>
{
offsetX.Value = val.NewValue.X;
offsetY.Value = val.NewValue.Y;
}), true);
}, true);
offsetX.BindValueChanged(val => areaOffset.Value = new Vector2(val.NewValue, areaOffset.Value.Y));
offsetY.BindValueChanged(val => areaOffset.Value = new Vector2(areaOffset.Value.X, val.NewValue));
areaSize.BindTo(tabletHandler.AreaSize);
areaSize.BindValueChanged(val => Schedule(() =>
areaSize.BindValueChanged(val =>
{
sizeX.Value = val.NewValue.X;
sizeY.Value = val.NewValue.Y;
}), true);
}, true);
sizeX.BindValueChanged(val =>
{
@@ -255,7 +255,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input
});
tablet.BindTo(tabletHandler.Tablet);
tablet.BindValueChanged(val => Schedule(() =>
tablet.BindValueChanged(val =>
{
Scheduler.AddOnce(updateVisibility);
@@ -274,7 +274,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input
sizeY.Default = sizeY.MaxValue = tab.Size.Y;
areaSize.Default = new Vector2(sizeX.Default, sizeY.Default);
}), true);
}, true);
}
private void updateVisibility()
@@ -58,9 +58,6 @@ namespace osu.Game.Rulesets.Configuration
pendingWrites.Clear();
}
if (!changed.Any())
return true;
realm?.Write(r =>
{
foreach (var c in changed)
+11 -3
View File
@@ -36,24 +36,32 @@ namespace osu.Game.Rulesets.Mods
public override Type[] IncompatibleMods => new[] { typeof(ModRateAdjust), typeof(ModTimeRamp), typeof(ModAutoplay) };
[SettingSource("Initial rate", "The starting speed of the track")]
public BindableNumber<double> InitialRate { get; } = new BindableDouble(1)
public BindableNumber<double> InitialRate { get; } = new BindableDouble
{
MinValue = 0.5,
MaxValue = 2,
Default = 1,
Value = 1,
Precision = 0.01
};
[SettingSource("Adjust pitch", "Should pitch be adjusted with speed")]
public BindableBool AdjustPitch { get; } = new BindableBool(true);
public BindableBool AdjustPitch { get; } = new BindableBool
{
Default = true,
Value = true
};
/// <summary>
/// The instantaneous rate of the track.
/// Every frame this mod will attempt to smoothly adjust this to meet <see cref="targetRate"/>.
/// </summary>
public BindableNumber<double> SpeedChange { get; } = new BindableDouble(1)
public BindableNumber<double> SpeedChange { get; } = new BindableDouble
{
MinValue = min_allowable_rate,
MaxValue = max_allowable_rate,
Default = 1,
Value = 1
};
// The two constants below denote the maximum allowable range of rates that `SpeedChange` can take.
+3 -1
View File
@@ -18,10 +18,12 @@ namespace osu.Game.Rulesets.Mods
public override LocalisableString Description => "Zoooooooooom...";
[SettingSource("Speed increase", "The actual increase to apply")]
public override BindableNumber<double> SpeedChange { get; } = new BindableDouble(1.5)
public override BindableNumber<double> SpeedChange { get; } = new BindableDouble
{
MinValue = 1.01,
MaxValue = 2,
Default = 1.5,
Value = 1.5,
Precision = 0.01,
};
}
+3 -1
View File
@@ -18,10 +18,12 @@ namespace osu.Game.Rulesets.Mods
public override LocalisableString Description => "Less zoom...";
[SettingSource("Speed decrease", "The actual decrease to apply")]
public override BindableNumber<double> SpeedChange { get; } = new BindableDouble(0.75)
public override BindableNumber<double> SpeedChange { get; } = new BindableDouble
{
MinValue = 0.5,
MaxValue = 0.99,
Default = 0.75,
Value = 0.75,
Precision = 0.01,
};
}
+18 -4
View File
@@ -36,20 +36,34 @@ namespace osu.Game.Rulesets.Mods
private readonly BindableNumber<int> currentCombo = new BindableInt();
[SettingSource("Enable metronome", "Add a metronome beat to help you keep track of the rhythm.")]
public BindableBool EnableMetronome { get; } = new BindableBool(true);
public BindableBool EnableMetronome { get; } = new BindableBool
{
Default = true,
Value = true
};
[SettingSource("Final volume at combo", "The combo count at which point the track reaches its final volume.", SettingControlType = typeof(SettingsSlider<int, MuteComboSlider>))]
public BindableInt MuteComboCount { get; } = new BindableInt(100)
public BindableInt MuteComboCount { get; } = new BindableInt
{
Default = 100,
Value = 100,
MinValue = 0,
MaxValue = 500,
};
[SettingSource("Start muted", "Increase volume as combo builds.")]
public BindableBool InverseMuting { get; } = new BindableBool();
public BindableBool InverseMuting { get; } = new BindableBool
{
Default = false,
Value = false
};
[SettingSource("Mute hit sounds", "Hit sounds are also muted alongside the track.")]
public BindableBool AffectsHitSounds { get; } = new BindableBool(true);
public BindableBool AffectsHitSounds { get; } = new BindableBool
{
Default = true,
Value = true
};
protected ModMuted()
{
+5 -1
View File
@@ -18,6 +18,10 @@ namespace osu.Game.Rulesets.Mods
public override double ScoreMultiplier => 1;
[SettingSource("Seed", "Use a custom seed instead of a random one", SettingControlType = typeof(SettingsNumberBox))]
public Bindable<int?> Seed { get; } = new Bindable<int?>();
public Bindable<int?> Seed { get; } = new Bindable<int?>
{
Default = null,
Value = null
};
}
}
+3 -1
View File
@@ -39,8 +39,10 @@ namespace osu.Game.Rulesets.Mods
private double finalRateTime;
private double beginRampTime;
public BindableNumber<double> SpeedChange { get; } = new BindableDouble(1)
public BindableNumber<double> SpeedChange { get; } = new BindableDouble
{
Default = 1,
Value = 1,
Precision = 0.01,
};
+11 -3
View File
@@ -18,23 +18,31 @@ namespace osu.Game.Rulesets.Mods
public override IconUsage? Icon => FontAwesome.Solid.ChevronCircleDown;
[SettingSource("Initial rate", "The starting speed of the track")]
public override BindableNumber<double> InitialRate { get; } = new BindableDouble(1)
public override BindableNumber<double> InitialRate { get; } = new BindableDouble
{
MinValue = 0.51,
MaxValue = 2,
Default = 1,
Value = 1,
Precision = 0.01,
};
[SettingSource("Final rate", "The speed increase to ramp towards")]
public override BindableNumber<double> FinalRate { get; } = new BindableDouble(0.75)
public override BindableNumber<double> FinalRate { get; } = new BindableDouble
{
MinValue = 0.5,
MaxValue = 1.99,
Default = 0.75,
Value = 0.75,
Precision = 0.01,
};
[SettingSource("Adjust pitch", "Should pitch be adjusted with speed")]
public override BindableBool AdjustPitch { get; } = new BindableBool(true);
public override BindableBool AdjustPitch { get; } = new BindableBool
{
Default = true,
Value = true
};
public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(ModWindUp)).ToArray();
+11 -3
View File
@@ -18,23 +18,31 @@ namespace osu.Game.Rulesets.Mods
public override IconUsage? Icon => FontAwesome.Solid.ChevronCircleUp;
[SettingSource("Initial rate", "The starting speed of the track")]
public override BindableNumber<double> InitialRate { get; } = new BindableDouble(1)
public override BindableNumber<double> InitialRate { get; } = new BindableDouble
{
MinValue = 0.5,
MaxValue = 1.99,
Default = 1,
Value = 1,
Precision = 0.01,
};
[SettingSource("Final rate", "The speed increase to ramp towards")]
public override BindableNumber<double> FinalRate { get; } = new BindableDouble(1.5)
public override BindableNumber<double> FinalRate { get; } = new BindableDouble
{
MinValue = 0.51,
MaxValue = 2,
Default = 1.5,
Value = 1.5,
Precision = 0.01,
};
[SettingSource("Adjust pitch", "Should pitch be adjusted with speed")]
public override BindableBool AdjustPitch { get; } = new BindableBool(true);
public override BindableBool AdjustPitch { get; } = new BindableBool
{
Default = true,
Value = true
};
public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(ModWindDown)).ToArray();
@@ -60,6 +60,7 @@ namespace osu.Game.Rulesets.UI.Scrolling
/// </summary>
protected readonly BindableDouble TimeRange = new BindableDouble(time_span_default)
{
Default = time_span_default,
MinValue = time_span_min,
MaxValue = time_span_max
};
@@ -4,12 +4,11 @@
#nullable disable
using System;
using System.Diagnostics;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Caching;
using osu.Framework.Graphics;
using osu.Framework.Logging;
using osu.Game.Beatmaps;
using osu.Game.Graphics;
using osu.Game.Screens.Edit.Components.Timelines.Summary.Parts;
@@ -35,6 +34,8 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
[Resolved]
private OsuColour colours { get; set; }
private static readonly int highest_divisor = BindableBeatDivisor.PREDEFINED_DIVISORS.Last();
public TimelineTickDisplay()
{
RelativeSizeAxes = Axes.Both;
@@ -79,19 +80,20 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
{
base.Update();
if (timeline == null || DrawWidth <= 0) return;
(float, float) newRange = (
(ToLocalSpace(timeline.ScreenSpaceDrawQuad.TopLeft).X - PointVisualisation.MAX_WIDTH * 2) / DrawWidth * Content.RelativeChildSize.X,
(ToLocalSpace(timeline.ScreenSpaceDrawQuad.TopRight).X + PointVisualisation.MAX_WIDTH * 2) / DrawWidth * Content.RelativeChildSize.X);
if (visibleRange != newRange)
if (timeline != null)
{
visibleRange = newRange;
var newRange = (
(ToLocalSpace(timeline.ScreenSpaceDrawQuad.TopLeft).X - PointVisualisation.MAX_WIDTH * 2) / DrawWidth * Content.RelativeChildSize.X,
(ToLocalSpace(timeline.ScreenSpaceDrawQuad.TopRight).X + PointVisualisation.MAX_WIDTH * 2) / DrawWidth * Content.RelativeChildSize.X);
// actual regeneration only needs to occur if we've passed one of the known next min/max tick boundaries.
if (nextMinTick == null || nextMaxTick == null || (visibleRange.min < nextMinTick || visibleRange.max > nextMaxTick))
tickCache.Invalidate();
if (visibleRange != newRange)
{
visibleRange = newRange;
// actual regeneration only needs to occur if we've passed one of the known next min/max tick boundaries.
if (nextMinTick == null || nextMaxTick == null || (visibleRange.min < nextMinTick || visibleRange.max > nextMaxTick))
tickCache.Invalidate();
}
}
if (!tickCache.IsValid)
@@ -149,20 +151,6 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
}
}
if (Children.Count > 512)
{
// There should always be a sanely small number of ticks rendered.
// If this assertion triggers, either the zoom logic is broken or a beatmap is
// probably doing weird things...
//
// Let's hope the latter never happens.
// If it does, we can choose to either fix it or ignore it as an outlier.
string message = $"Timeline is rendering many ticks ({Children.Count})";
Logger.Log(message);
Debug.Fail(message);
}
int usedDrawables = drawableIndex;
// save a few drawables beyond the currently used for edge cases.
@@ -56,14 +56,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
protected ZoomableScrollContainer()
: base(Direction.Horizontal)
{
base.Content.Add(zoomedContent = new Container
{
RelativeSizeAxes = Axes.Y,
// We must hide content until SetupZoom is called.
// If not, a child component that relies on its DrawWidth (via RelativeSizeAxes) may see a very incorrect value
// momentarily, as noticed in the TimelineTickDisplay, which would render thousands of ticks incorrectly.
Alpha = 0,
});
base.Content.Add(zoomedContent = new Container { RelativeSizeAxes = Axes.Y });
AddLayout(zoomedContentWidthCache);
}
@@ -101,8 +94,6 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
maxZoom = maximum;
CurrentZoom = zoomTarget = initial;
isZoomSetUp = true;
zoomedContent.Show();
}
/// <summary>
@@ -127,9 +118,9 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
CurrentZoom = zoomTarget = newZoom;
}
protected override void UpdateAfterChildren()
protected override void Update()
{
base.UpdateAfterChildren();
base.Update();
if (!zoomedContentWidthCache.IsValid)
updateZoomedContentWidth();
@@ -1,6 +1,8 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using System.Threading;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
@@ -14,7 +16,7 @@ namespace osu.Game.Screens.OnlinePlay.Match.Components
public class MatchLeaderboard : Leaderboard<MatchLeaderboardScope, APIUserScoreAggregate>
{
[Resolved(typeof(Room), nameof(Room.RoomID))]
private Bindable<long?> roomId { get; set; } = null!;
private Bindable<long?> roomId { get; set; }
[BackgroundDependencyLoader]
private void load()
@@ -31,7 +33,7 @@ namespace osu.Game.Screens.OnlinePlay.Match.Components
protected override bool IsOnlineScope => true;
protected override APIRequest? FetchScores(CancellationToken cancellationToken)
protected override APIRequest FetchScores(CancellationToken cancellationToken)
{
if (roomId.Value == null)
return null;
@@ -1,6 +1,8 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using System;
using osu.Framework.Timing;
using osu.Game.Online.Multiplayer;
@@ -105,8 +105,7 @@ namespace osu.Game.Screens.OnlinePlay
while (this.IsCurrentScreen())
this.Exit();
}
// Also handle the case where a child screen is current (ie. gameplay).
else if (this.GetChildScreen() != null)
else
{
this.MakeCurrent();
Schedule(forcefullyExit);
@@ -1,6 +1,8 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
@@ -10,7 +12,6 @@ using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Extensions;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Extensions.ObjectExtensions;
using osu.Game.Configuration;
using osu.Game.Database;
using osu.Game.Graphics;
@@ -33,20 +34,19 @@ namespace osu.Game.Screens.Play.HUD
public readonly SortedDictionary<int, BindableLong> TeamScores = new SortedDictionary<int, BindableLong>();
[Resolved]
private OsuColour colours { get; set; } = null!;
private OsuColour colours { get; set; }
[Resolved]
private SpectatorClient spectatorClient { get; set; } = null!;
private SpectatorClient spectatorClient { get; set; }
[Resolved]
private MultiplayerClient multiplayerClient { get; set; } = null!;
private MultiplayerClient multiplayerClient { get; set; }
[Resolved]
private UserLookupCache userLookupCache { get; set; } = null!;
private Bindable<ScoringMode> scoringMode = null!;
private UserLookupCache userLookupCache { get; set; }
private readonly MultiplayerRoomUser[] playingUsers;
private Bindable<ScoringMode> scoringMode;
private readonly IBindableList<int> playingUserIds = new BindableList<int>();
@@ -126,17 +126,14 @@ namespace osu.Game.Screens.Play.HUD
playingUserIds.BindCollectionChanged(playingUsersChanged);
}
protected override GameplayLeaderboardScore CreateLeaderboardScoreDrawable(IUser? user, bool isTracked)
protected override GameplayLeaderboardScore CreateLeaderboardScoreDrawable(IUser user, bool isTracked)
{
var leaderboardScore = base.CreateLeaderboardScoreDrawable(user, isTracked);
if (user != null)
if (UserScores[user.OnlineID].Team is int team)
{
if (UserScores[user.OnlineID].Team is int team)
{
leaderboardScore.BackgroundColour = getTeamColour(team).Lighten(1.2f);
leaderboardScore.TextColour = Color4.White;
}
leaderboardScore.BackgroundColour = getTeamColour(team).Lighten(1.2f);
leaderboardScore.TextColour = Color4.White;
}
return leaderboardScore;
@@ -192,7 +189,7 @@ namespace osu.Game.Screens.Play.HUD
{
base.Dispose(isDisposing);
if (spectatorClient.IsNotNull())
if (spectatorClient != null)
{
foreach (var user in playingUsers)
spectatorClient.StopWatchingUser(user.UserID);
@@ -5,8 +5,6 @@ using System.Collections.Generic;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Game.Configuration;
using osu.Game.Rulesets.Scoring;
using osu.Game.Scoring;
using osu.Game.Users;
@@ -15,9 +13,6 @@ namespace osu.Game.Screens.Play.HUD
{
public class SoloGameplayLeaderboard : GameplayLeaderboard
{
private const int duration = 100;
private readonly Bindable<bool> configVisibility = new Bindable<bool>();
private readonly IUser trackingUser;
public readonly IBindableList<ScoreInfo> Scores = new BindableList<ScoreInfo>();
@@ -31,33 +26,15 @@ namespace osu.Game.Screens.Play.HUD
[Resolved]
private ScoreManager scoreManager { get; set; } = null!;
/// <summary>
/// Whether the leaderboard should be visible regardless of the configuration value.
/// This is true by default, but can be changed.
/// </summary>
public readonly Bindable<bool> AlwaysVisible = new Bindable<bool>(true);
public SoloGameplayLeaderboard(IUser trackingUser)
{
this.trackingUser = trackingUser;
}
[BackgroundDependencyLoader]
private void load(OsuConfigManager config)
{
config.BindWith(OsuSetting.GameplayLeaderboard, configVisibility);
}
protected override void LoadComplete()
{
base.LoadComplete();
Scores.BindCollectionChanged((_, _) => Scheduler.AddOnce(showScores), true);
// Alpha will be updated via `updateVisibility` below.
Alpha = 0;
AlwaysVisible.BindValueChanged(_ => updateVisibility());
configVisibility.BindValueChanged(_ => updateVisibility(), true);
}
private void showScores()
@@ -92,8 +69,5 @@ namespace osu.Game.Screens.Play.HUD
// Local score should always show lower than any existing scores in cases of ties.
local.DisplayOrder.Value = long.MaxValue;
}
private void updateVisibility() =>
this.FadeTo(AlwaysVisible.Value || configVisibility.Value ? 1 : 0, duration);
}
}
@@ -39,7 +39,6 @@ namespace osu.Game.Screens.Play
{
Direction = FillDirection.Horizontal,
AutoSizeAxes = Axes.Both,
Alpha = 0,
};
}
@@ -34,6 +34,7 @@ namespace osu.Game.Screens.Play
public readonly BindableNumber<double> UserPlaybackRate = new BindableDouble(1)
{
Default = 1,
MinValue = 0.5,
MaxValue = 2,
Precision = 0.1,
@@ -31,6 +31,8 @@ namespace osu.Game.Screens.Play.PlayerSettings
public BindableDouble Current { get; } = new BindableDouble
{
Default = 0,
Value = 0,
MinValue = -50,
MaxValue = 50,
Precision = 0.1,
@@ -17,6 +17,7 @@ namespace osu.Game.Screens.Play.PlayerSettings
public readonly Bindable<double> UserPlaybackRate = new BindableDouble(1)
{
Default = 1,
MinValue = 0.5,
MaxValue = 2,
Precision = 0.1,
-1
View File
@@ -62,7 +62,6 @@ namespace osu.Game.Screens.Play
protected override GameplayLeaderboard CreateGameplayLeaderboard() =>
new SoloGameplayLeaderboard(Score.ScoreInfo.User)
{
AlwaysVisible = { Value = true },
Scores = { BindTarget = LeaderboardScores }
};
-1
View File
@@ -48,7 +48,6 @@ namespace osu.Game.Screens.Play
protected override GameplayLeaderboard CreateGameplayLeaderboard() =>
new SoloGameplayLeaderboard(Score.ScoreInfo.User)
{
AlwaysVisible = { Value = false },
Scores = { BindTarget = LeaderboardScores }
};
@@ -1,6 +1,8 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using System;
using System.Collections.Generic;
using System.Diagnostics;
@@ -23,11 +25,11 @@ namespace osu.Game.Screens.Select.Leaderboards
{
public class BeatmapLeaderboard : Leaderboard<BeatmapLeaderboardScope, ScoreInfo>
{
public Action<ScoreInfo>? ScoreSelected;
public Action<ScoreInfo> ScoreSelected;
private BeatmapInfo? beatmapInfo;
private BeatmapInfo beatmapInfo;
public BeatmapInfo? BeatmapInfo
public BeatmapInfo BeatmapInfo
{
get => beatmapInfo;
set
@@ -68,26 +70,24 @@ namespace osu.Game.Screens.Select.Leaderboards
}
[Resolved]
private ScoreManager scoreManager { get; set; } = null!;
private ScoreManager scoreManager { get; set; }
[Resolved]
private IBindable<RulesetInfo> ruleset { get; set; } = null!;
private IBindable<RulesetInfo> ruleset { get; set; }
[Resolved]
private IBindable<IReadOnlyList<Mod>> mods { get; set; } = null!;
private IBindable<IReadOnlyList<Mod>> mods { get; set; }
[Resolved]
private IAPIProvider api { get; set; } = null!;
private IAPIProvider api { get; set; }
[Resolved]
private RulesetStore rulesets { get; set; } = null!;
private RulesetStore rulesets { get; set; }
[Resolved]
private RealmAccess realm { get; set; } = null!;
private RealmAccess realm { get; set; }
private IDisposable? scoreSubscription;
private GetScoresRequest? scoreRetrievalRequest;
private IDisposable scoreSubscription;
[BackgroundDependencyLoader]
private void load()
@@ -102,9 +102,10 @@ namespace osu.Game.Screens.Select.Leaderboards
protected override bool IsOnlineScope => Scope != BeatmapLeaderboardScope.Local;
protected override APIRequest? FetchScores(CancellationToken cancellationToken)
protected override APIRequest FetchScores(CancellationToken cancellationToken)
{
var fetchBeatmapInfo = BeatmapInfo;
var fetchRuleset = ruleset.Value ?? fetchBeatmapInfo.Ruleset;
if (fetchBeatmapInfo == null)
{
@@ -112,15 +113,13 @@ namespace osu.Game.Screens.Select.Leaderboards
return null;
}
var fetchRuleset = ruleset.Value ?? fetchBeatmapInfo.Ruleset;
if (Scope == BeatmapLeaderboardScope.Local)
{
subscribeToLocalScores(fetchBeatmapInfo, cancellationToken);
return null;
}
if (!api.IsLoggedIn)
if (api?.IsLoggedIn != true)
{
SetErrorState(LeaderboardState.NotLoggedIn);
return null;
@@ -144,7 +143,7 @@ namespace osu.Game.Screens.Select.Leaderboards
return null;
}
IReadOnlyList<Mod>? requestMods = null;
IReadOnlyList<Mod> requestMods = null;
if (filterMods && !mods.Value.Any())
// add nomod for the request
@@ -152,14 +151,15 @@ namespace osu.Game.Screens.Select.Leaderboards
else if (filterMods)
requestMods = mods.Value;
scoreRetrievalRequest = new GetScoresRequest(fetchBeatmapInfo, fetchRuleset, Scope, requestMods);
var req = new GetScoresRequest(fetchBeatmapInfo, fetchRuleset, Scope, requestMods);
scoreRetrievalRequest.Success += response => SetScores(
scoreManager.OrderByTotalScore(response.Scores.Select(s => s.ToScoreInfo(rulesets, fetchBeatmapInfo))),
response.UserScore?.CreateScoreInfo(rulesets, fetchBeatmapInfo)
);
// Schedule is required to avoid potential object disposed exception when LoadComponentAsync is eventually called.
req.Success += r => Schedule(() => SetScores(
scoreManager.OrderByTotalScore(r.Scores.Select(s => s.ToScoreInfo(rulesets, fetchBeatmapInfo))),
r.UserScore?.CreateScoreInfo(rulesets, fetchBeatmapInfo)
));
return scoreRetrievalRequest;
return req;
}
protected override LeaderboardScore CreateDrawableScore(ScoreInfo model, int index) => new LeaderboardScore(model, index, IsOnlineScope)
@@ -185,7 +185,7 @@ namespace osu.Game.Screens.Select.Leaderboards
+ $" AND {nameof(ScoreInfo.DeletePending)} == false"
, beatmapInfo.ID, ruleset.Value.ShortName), localScoresChanged);
void localScoresChanged(IRealmCollection<ScoreInfo> sender, ChangeSet? changes, Exception exception)
void localScoresChanged(IRealmCollection<ScoreInfo> sender, ChangeSet changes, Exception exception)
{
if (cancellationToken.IsCancellationRequested)
return;
@@ -219,9 +219,7 @@ namespace osu.Game.Screens.Select.Leaderboards
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
scoreSubscription?.Dispose();
scoreRetrievalRequest?.Cancel();
}
}
}
@@ -128,7 +128,7 @@ namespace osu.Game.Storyboards.Drawables
//
// In the case of storyboard animations, we want to synchronise with game time perfectly
// so let's get a correct time based on gameplay clock and earliest transform.
PlaybackPosition = (beatSyncProvider.Clock?.CurrentTime ?? Clock.CurrentTime) - Animation.EarliestTransformTime;
PlaybackPosition = (beatSyncProvider?.Clock?.CurrentTime ?? Clock.CurrentTime) - Animation.EarliestTransformTime;
}
private void skinSourceChanged()
@@ -140,7 +140,6 @@ namespace osu.Game.Tests.Visual
{
c.RelativeSizeAxes = Axes.None;
c.AutoSizeAxes = Axes.None;
c.Size = Vector2.Zero;
c.RelativeSizeAxes = !autoSize ? Axes.Both : Axes.None;
c.AutoSizeAxes = autoSize ? Axes.Both : Axes.None;
+1 -1
View File
@@ -35,7 +35,7 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Realm" Version="10.15.1" />
<PackageReference Include="ppy.osu.Framework" Version="2022.922.0" />
<PackageReference Include="ppy.osu.Framework" Version="2022.916.1" />
<PackageReference Include="ppy.osu.Game.Resources" Version="2022.831.0" />
<PackageReference Include="Sentry" Version="3.20.1" />
<PackageReference Include="SharpCompress" Version="0.32.2" />
+2 -2
View File
@@ -61,7 +61,7 @@
<Reference Include="System.Net.Http" />
</ItemGroup>
<ItemGroup Label="Package References">
<PackageReference Include="ppy.osu.Framework.iOS" Version="2022.922.0" />
<PackageReference Include="ppy.osu.Framework.iOS" Version="2022.916.1" />
<PackageReference Include="ppy.osu.Game.Resources" Version="2022.831.0" />
</ItemGroup>
<!-- See https://github.com/dotnet/runtime/issues/35988 (can be removed after Xamarin uses net6.0) -->
@@ -82,7 +82,7 @@
<PackageReference Include="DiffPlex" Version="1.7.1" />
<PackageReference Include="Humanizer" Version="2.14.1" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="ppy.osu.Framework" Version="2022.922.0" />
<PackageReference Include="ppy.osu.Framework" Version="2022.916.1" />
<PackageReference Include="SharpCompress" Version="0.32.1" />
<PackageReference Include="NUnit" Version="3.13.3" />
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />