1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-11 11:20:04 +08:00

Merge branch 'master' into hud/kc-skinnable

This commit is contained in:
Ruki 2023-06-18 18:30:44 +02:00 committed by GitHub
commit 9c6c6bf1ea
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
42 changed files with 191 additions and 139 deletions

View File

@ -11,7 +11,7 @@
<AndroidManifestMerger>manifestmerger.jar</AndroidManifestMerger>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="ppy.osu.Framework.Android" Version="2023.608.0" />
<PackageReference Include="ppy.osu.Framework.Android" Version="2023.618.0" />
</ItemGroup>
<ItemGroup>
<AndroidManifestOverlay Include="$(MSBuildThisFileDirectory)osu.Android\Properties\AndroidManifestOverlay.xml" />

View File

@ -2,12 +2,10 @@
// See the LICENCE file in the repository root for full licence text.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.Versioning;
using System.Threading.Tasks;
using Microsoft.Win32;
using osu.Desktop.Security;
using osu.Framework.Platform;
@ -17,7 +15,6 @@ using osu.Framework;
using osu.Framework.Logging;
using osu.Game.Updater;
using osu.Desktop.Windows;
using osu.Framework.Threading;
using osu.Game.IO;
using osu.Game.IPC;
using osu.Game.Utils;
@ -138,52 +135,10 @@ namespace osu.Desktop
desktopWindow.CursorState |= CursorState.Hidden;
desktopWindow.Title = Name;
desktopWindow.DragDrop += f =>
{
// on macOS, URL associations are handled via SDL_DROPFILE events.
if (f.StartsWith(OSU_PROTOCOL, StringComparison.Ordinal))
{
HandleLink(f);
return;
}
fileDrop(new[] { f });
};
}
protected override BatteryInfo CreateBatteryInfo() => new SDL2BatteryInfo();
private readonly List<string> importableFiles = new List<string>();
private ScheduledDelegate? importSchedule;
private void fileDrop(string[] filePaths)
{
lock (importableFiles)
{
importableFiles.AddRange(filePaths);
Logger.Log($"Adding {filePaths.Length} files for import");
// File drag drop operations can potentially trigger hundreds or thousands of these calls on some platforms.
// In order to avoid spawning multiple import tasks for a single drop operation, debounce a touch.
importSchedule?.Cancel();
importSchedule = Scheduler.AddDelayed(handlePendingImports, 100);
}
}
private void handlePendingImports()
{
lock (importableFiles)
{
Logger.Log($"Handling batch import of {importableFiles.Count} files");
string[] paths = importableFiles.ToArray();
importableFiles.Clear();
Task.Factory.StartNew(() => Import(paths), TaskCreationOptions.LongRunning);
}
}
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);

View File

@ -8,6 +8,7 @@ using NUnit.Framework;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.Mania.UI;
using osuTK;
namespace osu.Game.Rulesets.Mania.Tests.Skinning
{
@ -25,22 +26,35 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning
new StageDefinition(2)
};
SetContents(_ => new ManiaPlayfield(stageDefinitions));
SetContents(_ => new ManiaInputManager(new ManiaRuleset().RulesetInfo, 2)
{
Child = new ManiaPlayfield(stageDefinitions)
});
});
}
[Test]
public void TestDualStages()
[TestCase(2)]
[TestCase(3)]
[TestCase(5)]
public void TestDualStages(int columnCount)
{
AddStep("create stage", () =>
{
stageDefinitions = new List<StageDefinition>
{
new StageDefinition(2),
new StageDefinition(2)
new StageDefinition(columnCount),
new StageDefinition(columnCount)
};
SetContents(_ => new ManiaPlayfield(stageDefinitions));
SetContents(_ => new ManiaInputManager(new ManiaRuleset().RulesetInfo, (int)PlayfieldType.Dual + 2 * columnCount)
{
Child = new ManiaPlayfield(stageDefinitions)
{
// bit of a hack to make sure the dual stages fit on screen without overlapping each other.
Size = new Vector2(1.5f),
Scale = new Vector2(1 / 1.5f)
}
});
});
}

View File

@ -242,18 +242,23 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
bodyPiece.Y = (Direction.Value == ScrollingDirection.Up ? 1 : -1) * Head.Height / 2;
bodyPiece.Height = DrawHeight - Head.Height / 2 + Tail.Height / 2;
// As the note is being held, adjust the size of the sizing container. This has two effects:
// 1. The contained masking container will mask the body and ticks.
// 2. The head note will move along with the new "head position" in the container.
//
// As per stable, this should not apply for early hits, waiting until the object starts to touch the
// judgement area first.
if (Head.IsHit && releaseTime == null && DrawHeight > 0 && Time.Current >= HitObject.StartTime)
if (Time.Current >= HitObject.StartTime)
{
// How far past the hit target this hold note is.
float yOffset = Direction.Value == ScrollingDirection.Up ? -Y : Y;
sizingContainer.Height = 1 - yOffset / DrawHeight;
// As the note is being held, adjust the size of the sizing container. This has two effects:
// 1. The contained masking container will mask the body and ticks.
// 2. The head note will move along with the new "head position" in the container.
//
// As per stable, this should not apply for early hits, waiting until the object starts to touch the
// judgement area first.
if (Head.IsHit && releaseTime == null && DrawHeight > 0)
{
// How far past the hit target this hold note is.
float yOffset = Direction.Value == ScrollingDirection.Up ? -Y : Y;
sizingContainer.Height = 1 - yOffset / DrawHeight;
}
}
else
sizingContainer.Height = 1;
}
protected override void CheckForResult(bool userTriggered, double timeOffset)

View File

@ -35,10 +35,12 @@ namespace osu.Game.Rulesets.Mania.Skinning.Default
var stage = beatmap.GetStageForColumnIndex(column);
if (stage.IsSpecialColumn(column))
int columnInStage = column % stage.Columns;
if (stage.IsSpecialColumn(columnInStage))
return SkinUtils.As<TValue>(new Bindable<Color4>(colourSpecial));
int distanceToEdge = Math.Min(column, (stage.Columns - 1) - column);
int distanceToEdge = Math.Min(columnInStage, (stage.Columns - 1) - columnInStage);
return SkinUtils.As<TValue>(new Bindable<Color4>(distanceToEdge % 2 == 0 ? colourOdd : colourEven));
}
}

View File

@ -86,6 +86,7 @@ namespace osu.Game.Tests.Visual.Online
StarRating = 9.99,
DifficultyName = @"TEST",
Length = 456000,
HitLength = 400000,
RulesetID = 3,
CircleSize = 1,
DrainRate = 2.3f,

View File

@ -101,6 +101,10 @@ namespace osu.Game.Tests.Visual.UserInterface
},
};
}
protected override void PopIn()
{
}
}
}
}

View File

@ -33,7 +33,7 @@ namespace osu.Game.Beatmaps
IBeatmapSetInfo? BeatmapSet { get; }
/// <summary>
/// The playable length in milliseconds of this beatmap.
/// The total length in milliseconds of this beatmap.
/// </summary>
double Length { get; }

View File

@ -59,5 +59,10 @@ namespace osu.Game.Beatmaps
int PassCount { get; }
APIFailTimes? FailTimes { get; }
/// <summary>
/// The playable length in milliseconds of this beatmap.
/// </summary>
double HitLength { get; }
}
}

View File

@ -114,8 +114,6 @@ namespace osu.Game.Collections
protected override void PopIn()
{
base.PopIn();
lowPassFilter.CutoffTo(300, 100, Easing.OutCubic);
this.FadeIn(enter_duration, Easing.OutQuint);
this.ScaleTo(0.9f).Then().ScaleTo(1f, enter_duration, Easing.OutQuint);

View File

@ -178,6 +178,7 @@ namespace osu.Game.Configuration
SetDefault(OsuSetting.EditorWaveformOpacity, 0.25f, 0f, 1f, 0.25f);
SetDefault(OsuSetting.EditorShowHitMarkers, true);
SetDefault(OsuSetting.EditorAutoSeekOnPlacement, true);
SetDefault(OsuSetting.EditorLimitedDistanceSnap, false);
SetDefault(OsuSetting.LastProcessedMetadataId, -1);
@ -383,5 +384,6 @@ namespace osu.Game.Configuration
SafeAreaConsiderations,
ComboColourNormalisationAmount,
ProfileCoverExpanded,
EditorLimitedDistanceSnap
}
}

View File

@ -152,7 +152,6 @@ namespace osu.Game.Graphics.Containers
protected override void PopOut()
{
base.PopOut();
previewTrackManager.StopAnyPlaying(this);
}

View File

@ -167,9 +167,12 @@ namespace osu.Game.Graphics.UserInterface
{
base.Update();
double elapsedDrawFrameTime = drawClock.ElapsedFrameTime;
double elapsedUpdateFrameTime = updateClock.ElapsedFrameTime;
// If the game goes into a suspended state (ie. debugger attached or backgrounded on a mobile device)
// we want to ignore really long periods of no processing.
if (updateClock.ElapsedFrameTime > 10000)
if (elapsedUpdateFrameTime > 10000)
return;
mainContent.Width = Math.Max(mainContent.Width, counters.DrawWidth);
@ -178,17 +181,17 @@ namespace osu.Game.Graphics.UserInterface
// frame limiter (we want to show the FPS as it's changing, even if it isn't an outlier).
bool aimRatesChanged = updateAimFPS();
bool hasUpdateSpike = displayedFrameTime < spike_time_ms && updateClock.ElapsedFrameTime > spike_time_ms;
bool hasUpdateSpike = displayedFrameTime < spike_time_ms && elapsedUpdateFrameTime > spike_time_ms;
// use elapsed frame time rather then FramesPerSecond to better catch stutter frames.
bool hasDrawSpike = displayedFpsCount > (1000 / spike_time_ms) && drawClock.ElapsedFrameTime > spike_time_ms;
bool hasDrawSpike = displayedFpsCount > (1000 / spike_time_ms) && elapsedDrawFrameTime > spike_time_ms;
const float damp_time = 100;
displayedFrameTime = Interpolation.DampContinuously(displayedFrameTime, updateClock.ElapsedFrameTime, hasUpdateSpike ? 0 : damp_time, updateClock.ElapsedFrameTime);
displayedFrameTime = Interpolation.DampContinuously(displayedFrameTime, elapsedUpdateFrameTime, hasUpdateSpike ? 0 : damp_time, elapsedUpdateFrameTime);
if (hasDrawSpike)
// show spike time using raw elapsed value, to account for `FramesPerSecond` being so averaged spike frames don't show.
displayedFpsCount = 1000 / drawClock.ElapsedFrameTime;
displayedFpsCount = 1000 / elapsedDrawFrameTime;
else
displayedFpsCount = Interpolation.DampContinuously(displayedFpsCount, drawClock.FramesPerSecond, damp_time, Time.Elapsed);

View File

@ -109,6 +109,11 @@ namespace osu.Game.Localisation
/// </summary>
public static LocalisableString RotationSnapped(float newRotation) => new TranslatableString(getKey(@"rotation_snapped"), @"{0:0}° (snapped)", newRotation);
/// <summary>
/// "Limit distance snap placement to current time"
/// </summary>
public static LocalisableString LimitedDistanceSnap => new TranslatableString(getKey(@"limited_distance_snap_grid"), @"Limit distance snap placement to current time");
private static string getKey(string key) => $@"{prefix}:{key}";
}
}

View File

@ -63,6 +63,16 @@ namespace osu.Game.Online.API.Requests.Responses
set => Length = TimeSpan.FromSeconds(value).TotalMilliseconds;
}
[JsonIgnore]
public double HitLength { get; set; }
[JsonProperty(@"hit_length")]
private double hitLengthInSeconds
{
get => TimeSpan.FromMilliseconds(HitLength).TotalSeconds;
set => HitLength = TimeSpan.FromSeconds(value).TotalMilliseconds;
}
[JsonProperty(@"convert")]
public bool Convert { get; set; }

View File

@ -6,6 +6,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@ -28,6 +29,7 @@ using osu.Framework.Input.Events;
using osu.Framework.Input.Handlers.Tablet;
using osu.Framework.Localisation;
using osu.Framework.Logging;
using osu.Framework.Platform;
using osu.Framework.Screens;
using osu.Framework.Threading;
using osu.Game.Beatmaps;
@ -281,6 +283,52 @@ namespace osu.Game
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) =>
dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
private readonly List<string> dragDropFiles = new List<string>();
private ScheduledDelegate dragDropImportSchedule;
public override void SetHost(GameHost host)
{
base.SetHost(host);
if (host.Window is SDL2Window sdlWindow)
{
sdlWindow.DragDrop += path =>
{
// on macOS/iOS, URL associations are handled via SDL_DROPFILE events.
if (path.StartsWith(OSU_PROTOCOL, StringComparison.Ordinal))
{
HandleLink(path);
return;
}
lock (dragDropFiles)
{
dragDropFiles.Add(path);
Logger.Log($@"Adding ""{Path.GetFileName(path)}"" for import");
// File drag drop operations can potentially trigger hundreds or thousands of these calls on some platforms.
// In order to avoid spawning multiple import tasks for a single drop operation, debounce a touch.
dragDropImportSchedule?.Cancel();
dragDropImportSchedule = Scheduler.AddDelayed(handlePendingDragDropImports, 100);
}
};
}
}
private void handlePendingDragDropImports()
{
lock (dragDropFiles)
{
Logger.Log($"Handling batch import of {dragDropFiles.Count} files");
string[] paths = dragDropFiles.ToArray();
dragDropFiles.Clear();
Task.Factory.StartNew(() => Import(paths), TaskCreationOptions.LongRunning);
}
}
[BackgroundDependencyLoader]
private void load()
{

View File

@ -90,7 +90,6 @@ namespace osu.Game.Overlays
protected override void PopIn()
{
base.PopIn();
this.FadeIn(transition_time, Easing.OutQuint);
if (welcomeScreen.GetChildScreen() != null)

View File

@ -68,13 +68,13 @@ namespace osu.Game.Overlays.BeatmapSet
}
else
{
length.TooltipText = BeatmapsetsStrings.ShowStatsTotalLength(TimeSpan.FromMilliseconds(beatmapInfo.Length).ToFormattedDuration());
length.Value = TimeSpan.FromMilliseconds(beatmapInfo.Length).ToFormattedDuration();
var onlineInfo = beatmapInfo as IBeatmapOnlineInfo;
if (beatmapInfo is not IBeatmapOnlineInfo onlineInfo) return;
circleCount.Value = (onlineInfo?.CircleCount ?? 0).ToLocalisableString(@"N0");
sliderCount.Value = (onlineInfo?.SliderCount ?? 0).ToLocalisableString(@"N0");
circleCount.Value = onlineInfo.CircleCount.ToLocalisableString(@"N0");
sliderCount.Value = onlineInfo.SliderCount.ToLocalisableString(@"N0");
length.TooltipText = BeatmapsetsStrings.ShowStatsTotalLength(TimeSpan.FromMilliseconds(onlineInfo.HitLength).ToFormattedDuration());
}
}

View File

@ -47,9 +47,6 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
[Resolved]
private RulesetStore rulesets { get; set; }
[Resolved]
private ScoreManager scoreManager { get; set; }
private GetScoresRequest getScoresRequest;
private CancellationTokenSource loadCancellationSource;
@ -85,7 +82,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
MD5Hash = apiBeatmap.MD5Hash
};
var scores = scoreManager.OrderByTotalScore(value.Scores.Select(s => s.ToScoreInfo(rulesets, beatmapInfo))).ToArray();
var scores = value.Scores.Select(s => s.ToScoreInfo(rulesets, beatmapInfo)).OrderByTotalScore().ToArray();
var topScore = scores.First();
scoreTable.DisplayScores(scores, apiBeatmap.Status.GrantsPerformancePoints());

View File

@ -276,8 +276,6 @@ namespace osu.Game.Overlays
protected override void PopIn()
{
base.PopIn();
this.MoveToY(0, transition_length, Easing.OutQuint);
this.FadeIn(transition_length, Easing.OutQuint);
}

View File

@ -99,7 +99,6 @@ namespace osu.Game.Overlays
protected override void PopIn()
{
base.PopIn();
lowPassFilter.CutoffTo(300, 100, Easing.OutCubic);
}

View File

@ -75,8 +75,6 @@ namespace osu.Game.Overlays
protected override void PopIn()
{
base.PopIn();
panel.Bounding = true;
this.FadeIn(transition_time, Easing.OutQuint);

View File

@ -246,9 +246,13 @@ namespace osu.Game.Overlays
}
}
protected override void PopIn()
{
this.FadeIn(200);
}
protected override void PopOut()
{
base.PopOut();
this.FadeOut(200);
}

View File

@ -130,7 +130,6 @@ namespace osu.Game.Overlays.Mods
{
const double fade_in_duration = 400;
base.PopIn();
this.FadeIn(fade_in_duration, Easing.OutQuint);
Header.MoveToY(0, fade_in_duration, Easing.OutQuint);

View File

@ -206,8 +206,6 @@ namespace osu.Game.Overlays
protected override void PopIn()
{
base.PopIn();
this.MoveToX(0, TRANSITION_LENGTH, Easing.OutQuint);
mainContent.FadeTo(1, TRANSITION_LENGTH, Easing.OutQuint);
mainContent.FadeEdgeEffectTo(WaveContainer.SHADOW_OPACITY, WaveContainer.APPEAR_DURATION, Easing.Out);

View File

@ -229,8 +229,6 @@ namespace osu.Game.Overlays
protected override void PopIn()
{
base.PopIn();
this.FadeIn(transition_length, Easing.OutQuint);
dragContainer.ScaleTo(1, transition_length, Easing.OutElastic);
}

View File

@ -163,8 +163,6 @@ namespace osu.Game.Overlays
protected override void PopIn()
{
base.PopIn();
ContentContainer.MoveToX(ExpandedPosition, TRANSITION_LENGTH, Easing.OutQuint);
SectionsContainer.FadeEdgeEffectTo(WaveContainer.SHADOW_OPACITY, WaveContainer.APPEAR_DURATION, Easing.Out);

View File

@ -34,8 +34,6 @@ namespace osu.Game.Overlays
protected override void PopIn()
{
base.PopIn();
Waves.Show();
this.FadeIn(100, Easing.OutQuint);
}

View File

@ -1,9 +1,10 @@
// 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.Collections.Generic;
using System.Linq;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Scoring
{
@ -13,5 +14,23 @@ namespace osu.Game.Scoring
/// A user-presentable display title representing this score.
/// </summary>
public static string GetDisplayTitle(this IScoreInfo scoreInfo) => $"{scoreInfo.User.Username} playing {scoreInfo.Beatmap.GetDisplayTitle()}";
/// <summary>
/// Orders an array of <see cref="ScoreInfo"/>s by total score.
/// </summary>
/// <param name="scores">The array of <see cref="ScoreInfo"/>s to reorder.</param>
/// <returns>The given <paramref name="scores"/> ordered by decreasing total score.</returns>
public static IEnumerable<ScoreInfo> OrderByTotalScore(this IEnumerable<ScoreInfo> scores)
=> scores.OrderByDescending(s => s.TotalScore)
.ThenBy(s => s.OnlineID)
// Local scores may not have an online ID. Fall back to date in these cases.
.ThenBy(s => s.Date);
/// <summary>
/// Retrieves the maximum achievable combo for the provided score.
/// </summary>
/// <param name="score">The <see cref="ScoreInfo"/> to compute the maximum achievable combo for.</param>
/// <returns>The maximum achievable combo.</returns>
public static int GetMaximumAchievableCombo(this ScoreInfo score) => score.MaximumStatistics.Where(kvp => kvp.Key.AffectsCombo()).Sum(kvp => kvp.Value);
}
}

View File

@ -69,17 +69,6 @@ namespace osu.Game.Scoring
return Realm.Run(r => r.All<ScoreInfo>().FirstOrDefault(query)?.Detach());
}
/// <summary>
/// Orders an array of <see cref="ScoreInfo"/>s by total score.
/// </summary>
/// <param name="scores">The array of <see cref="ScoreInfo"/>s to reorder.</param>
/// <returns>The given <paramref name="scores"/> ordered by decreasing total score.</returns>
public IEnumerable<ScoreInfo> OrderByTotalScore(IEnumerable<ScoreInfo> scores)
=> scores.OrderByDescending(s => s.TotalScore)
.ThenBy(s => s.OnlineID)
// Local scores may not have an online ID. Fall back to date in these cases.
.ThenBy(s => s.Date);
/// <summary>
/// Retrieves a bindable that represents the total score of a <see cref="ScoreInfo"/>.
/// </summary>
@ -100,13 +89,6 @@ namespace osu.Game.Scoring
/// <returns>The bindable containing the formatted total score string.</returns>
public Bindable<string> GetBindableTotalScoreString([NotNull] ScoreInfo score) => new TotalScoreStringBindable(GetBindableTotalScore(score));
/// <summary>
/// Retrieves the maximum achievable combo for the provided score.
/// </summary>
/// <param name="score">The <see cref="ScoreInfo"/> to compute the maximum achievable combo for.</param>
/// <returns>The maximum achievable combo.</returns>
public int GetMaximumAchievableCombo([NotNull] ScoreInfo score) => score.MaximumStatistics.Where(kvp => kvp.Key.AffectsCombo()).Sum(kvp => kvp.Value);
/// <summary>
/// Provides the total score of a <see cref="ScoreInfo"/>. Responds to changes in the currently-selected <see cref="ScoringMode"/>.
/// </summary>

View File

@ -18,6 +18,9 @@ namespace osu.Game.Screens.Edit.Compose.Components
{
public abstract partial class CircularDistanceSnapGrid : DistanceSnapGrid
{
[Resolved]
private EditorClock editorClock { get; set; }
protected CircularDistanceSnapGrid(HitObject referenceObject, Vector2 startPosition, double startTime, double? endTime = null)
: base(referenceObject, startPosition, startTime, endTime)
{
@ -98,9 +101,12 @@ namespace osu.Game.Screens.Edit.Compose.Components
if (travelLength < DistanceBetweenTicks)
travelLength = DistanceBetweenTicks;
// When interacting with the resolved snap provider, the distance spacing multiplier should first be removed
// to allow for snapping at a non-multiplied ratio.
float snappedDistance = SnapProvider.FindSnappedDistance(ReferenceObject, travelLength / distanceSpacingMultiplier);
float snappedDistance = LimitedDistanceSnap.Value
? SnapProvider.DurationToDistance(ReferenceObject, editorClock.CurrentTime - ReferenceObject.GetEndTime())
// When interacting with the resolved snap provider, the distance spacing multiplier should first be removed
// to allow for snapping at a non-multiplied ratio.
: SnapProvider.FindSnappedDistance(ReferenceObject, travelLength / distanceSpacingMultiplier);
double snappedTime = StartTime + SnapProvider.DistanceToDuration(ReferenceObject, snappedDistance);
if (snappedTime > LatestEndTime)

View File

@ -10,6 +10,7 @@ using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Layout;
using osu.Game.Configuration;
using osu.Game.Graphics;
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Objects;
@ -60,6 +61,18 @@ namespace osu.Game.Screens.Edit.Compose.Components
[Resolved]
private BindableBeatDivisor beatDivisor { get; set; }
/// <summary>
/// When enabled, distance snap should only snap to the current time (as per the editor clock).
/// This is to emulate stable behaviour.
/// </summary>
protected Bindable<bool> LimitedDistanceSnap { get; private set; }
[BackgroundDependencyLoader]
private void load(OsuConfigManager config)
{
LimitedDistanceSnap = config.GetBindable<bool>(OsuSetting.EditorLimitedDistanceSnap);
}
private readonly LayoutValue gridCache = new LayoutValue(Invalidation.RequiredParentSizeToFit);
protected readonly HitObject ReferenceObject;

View File

@ -185,6 +185,7 @@ namespace osu.Game.Screens.Edit
private Bindable<float> editorBackgroundDim;
private Bindable<bool> editorHitMarkers;
private Bindable<bool> editorAutoSeekOnPlacement;
private Bindable<bool> editorLimitedDistanceSnap;
public Editor(EditorLoader loader = null)
{
@ -276,6 +277,7 @@ namespace osu.Game.Screens.Edit
editorBackgroundDim = config.GetBindable<float>(OsuSetting.EditorDim);
editorHitMarkers = config.GetBindable<bool>(OsuSetting.EditorShowHitMarkers);
editorAutoSeekOnPlacement = config.GetBindable<bool>(OsuSetting.EditorAutoSeekOnPlacement);
editorLimitedDistanceSnap = config.GetBindable<bool>(OsuSetting.EditorLimitedDistanceSnap);
AddInternal(new OsuContextMenuContainer
{
@ -337,6 +339,10 @@ namespace osu.Game.Screens.Edit
new ToggleMenuItem(EditorStrings.AutoSeekOnPlacement)
{
State = { BindTarget = editorAutoSeekOnPlacement },
},
new ToggleMenuItem(EditorStrings.LimitedDistanceSnap)
{
State = { BindTarget = editorLimitedDistanceSnap },
}
}
},

View File

@ -54,14 +54,12 @@ namespace osu.Game.Screens.OnlinePlay.Match.Components
protected override void PopIn()
{
base.PopIn();
Settings.MoveToY(0, TRANSITION_DURATION, Easing.OutQuint);
Settings.FadeIn(TRANSITION_DURATION / 2);
}
protected override void PopOut()
{
base.PopOut();
Settings.MoveToY(-1, TRANSITION_DURATION, Easing.InSine);
Settings.Delay(TRANSITION_DURATION / 2).FadeOut(TRANSITION_DURATION / 2);
}

View File

@ -182,7 +182,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
/// <param name="pivot">An optional pivot around which the scores were retrieved.</param>
private void performSuccessCallback([NotNull] Action<IEnumerable<ScoreInfo>> callback, [NotNull] List<MultiplayerScore> scores, [CanBeNull] MultiplayerScores pivot = null) => Schedule(() =>
{
var scoreInfos = scoreManager.OrderByTotalScore(scores.Select(s => s.CreateScoreInfo(scoreManager, rulesets, playlistItem, Beatmap.Value.BeatmapInfo))).ToArray();
var scoreInfos = scores.Select(s => s.CreateScoreInfo(scoreManager, rulesets, playlistItem, Beatmap.Value.BeatmapInfo)).OrderByTotalScore().ToArray();
// Select a score if we don't already have one selected.
// Note: This is done before the callback so that the panel list centres on the selected score before panels are added (eliminating initial scroll).

View File

@ -73,7 +73,7 @@ namespace osu.Game.Screens.Ranking.Expanded
var topStatistics = new List<StatisticDisplay>
{
new AccuracyStatistic(score.Accuracy),
new ComboStatistic(score.MaxCombo, scoreManager.GetMaximumAchievableCombo(score)),
new ComboStatistic(score.MaxCombo, score.GetMaximumAchievableCombo()),
new PerformanceStatistic(score),
};

View File

@ -29,9 +29,6 @@ namespace osu.Game.Screens.Select.Carousel
[Resolved]
private RealmAccess realm { get; set; } = null!;
[Resolved]
private ScoreManager scoreManager { get; set; } = null!;
[Resolved]
private IAPIProvider api { get; set; } = null!;
@ -78,7 +75,7 @@ namespace osu.Game.Screens.Select.Carousel
if (changes?.HasCollectionChanges() == false)
return;
ScoreInfo? topScore = scoreManager.OrderByTotalScore(sender.Detach()).FirstOrDefault();
ScoreInfo? topScore = sender.Detach().OrderByTotalScore().FirstOrDefault();
updateable.Rank = topScore?.Rank;
updateable.Alpha = topScore != null ? 1 : 0;

View File

@ -67,9 +67,6 @@ namespace osu.Game.Screens.Select.Leaderboards
}
}
[Resolved]
private ScoreManager scoreManager { get; set; } = null!;
[Resolved]
private IBindable<RulesetInfo> ruleset { get; set; } = null!;
@ -164,7 +161,7 @@ namespace osu.Game.Screens.Select.Leaderboards
return;
SetScores(
scoreManager.OrderByTotalScore(response.Scores.Select(s => s.ToScoreInfo(rulesets, fetchBeatmapInfo))),
response.Scores.Select(s => s.ToScoreInfo(rulesets, fetchBeatmapInfo)).OrderByTotalScore(),
response.UserScore?.CreateScoreInfo(rulesets, fetchBeatmapInfo)
);
});
@ -222,7 +219,7 @@ namespace osu.Game.Screens.Select.Leaderboards
scores = scores.Where(s => selectedMods.SetEquals(s.Mods.Select(m => m.Acronym)));
}
scores = scoreManager.OrderByTotalScore(scores.Detach());
scores = scores.Detach().OrderByTotalScore();
SetScores(scores);
}

View File

@ -86,8 +86,6 @@ namespace osu.Game.Screens.Select.Options
protected override void PopIn()
{
base.PopIn();
this.FadeIn(transition_duration, Easing.OutQuint);
if (buttonsContainer.Position.X == 1 || Alpha == 0)

View File

@ -5,7 +5,6 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Humanizer;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
@ -864,7 +863,7 @@ namespace osu.Game.Screens.Select
{
// Intentionally not localised until we have proper support for this (see https://github.com/ppy/osu-framework/pull/4918
// but also in this case we want support for formatting a number within a string).
FilterControl.InformationalText = $"{"match".ToQuantity(Carousel.CountDisplayed, "#,0")}";
FilterControl.InformationalText = Carousel.CountDisplayed != 1 ? $"{Carousel.CountDisplayed:#,0} matches" : $"{Carousel.CountDisplayed:#,0} match";
}
private bool boundLocalBindables;

View File

@ -36,7 +36,7 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Realm" Version="10.20.0" />
<PackageReference Include="ppy.osu.Framework" Version="2023.608.0" />
<PackageReference Include="ppy.osu.Framework" Version="2023.618.0" />
<PackageReference Include="ppy.osu.Game.Resources" Version="2023.605.0" />
<PackageReference Include="Sentry" Version="3.28.1" />
<PackageReference Include="SharpCompress" Version="0.32.2" />

View File

@ -16,6 +16,6 @@
<RuntimeIdentifier>iossimulator-x64</RuntimeIdentifier>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="ppy.osu.Framework.iOS" Version="2023.608.0" />
<PackageReference Include="ppy.osu.Framework.iOS" Version="2023.618.0" />
</ItemGroup>
</Project>