Compare commits
19 Commits
490a6fd724
...
fb7ccba4ba
| Author | SHA1 | Date | |
|---|---|---|---|
| fb7ccba4ba | |||
|
|
42b184f167 | ||
|
|
27737bd4e9 | ||
|
|
8bb885a0dc | ||
|
|
0b06acb29d | ||
|
|
b129837e57 | ||
|
|
3e221c7f61 | ||
|
|
7106a6a5e5 | ||
|
|
eaf2721f5b | ||
|
|
59a27dad3d | ||
|
|
d6cd748d2a | ||
|
|
c23d6b7fd1 | ||
|
|
582ff999aa | ||
|
|
a96b024ac5 | ||
|
|
1c10acba76 | ||
|
|
4ae4c700ae | ||
|
|
2be50d917a | ||
|
|
35fdc6f8b9 | ||
|
|
d04029bcc7 |
@@ -10,7 +10,7 @@
|
||||
<EmbedAssembliesIntoApk>true</EmbedAssembliesIntoApk>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2025.1205.1" />
|
||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2025.1209.0" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup>
|
||||
<!-- Fody does not handle Android build well, and warns when unchanged.
|
||||
|
||||
@@ -22,6 +22,7 @@ namespace osu.Game.Rulesets.Taiko.Mods
|
||||
public override ModType Type => ModType.Conversion;
|
||||
public override double ScoreMultiplier => 1;
|
||||
public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(ModRandom)).ToArray();
|
||||
public override bool Ranked => true;
|
||||
|
||||
public void ApplyToBeatmap(IBeatmap beatmap)
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// 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.
|
||||
|
||||
using System;
|
||||
using NUnit.Framework;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Online.Multiplayer.MatchTypes.Matchmaking;
|
||||
@@ -149,5 +150,33 @@ namespace osu.Game.Tests.Online.Matchmaking
|
||||
Assert.AreEqual(5, state.Users.GetOrAdd(5).Placement);
|
||||
Assert.AreEqual(6, state.Users.GetOrAdd(6).Placement);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AbandonOrder()
|
||||
{
|
||||
var state = new MatchmakingRoomState();
|
||||
|
||||
state.AdvanceRound();
|
||||
state.RecordScores(
|
||||
[
|
||||
new SoloScoreInfo { UserID = 1, TotalScore = 1000 },
|
||||
new SoloScoreInfo { UserID = 2, TotalScore = 500 },
|
||||
], placement_points);
|
||||
|
||||
Assert.AreEqual(1, state.Users.GetOrAdd(1).Placement);
|
||||
Assert.AreEqual(2, state.Users.GetOrAdd(2).Placement);
|
||||
|
||||
state.Users.GetOrAdd(1).AbandonedAt = DateTimeOffset.Now;
|
||||
state.RecordScores([], placement_points);
|
||||
|
||||
Assert.AreEqual(2, state.Users.GetOrAdd(1).Placement);
|
||||
Assert.AreEqual(1, state.Users.GetOrAdd(2).Placement);
|
||||
|
||||
state.Users.GetOrAdd(2).AbandonedAt = DateTimeOffset.Now - TimeSpan.FromMinutes(1);
|
||||
state.RecordScores([], placement_points);
|
||||
|
||||
Assert.AreEqual(1, state.Users.GetOrAdd(1).Placement);
|
||||
Assert.AreEqual(2, state.Users.GetOrAdd(2).Placement);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Framework.Utils;
|
||||
@@ -26,8 +27,15 @@ namespace osu.Game.Tests.Visual.Matchmaking
|
||||
|
||||
AddStep("join room", () => JoinRoom(CreateDefaultRoom(MatchType.Matchmaking)));
|
||||
WaitForJoined();
|
||||
}
|
||||
|
||||
setupRequestHandler();
|
||||
[TestCase(2)]
|
||||
[TestCase(4)]
|
||||
[TestCase(8)]
|
||||
[TestCase(16)]
|
||||
public void TestDisplayScores(int scoreCount)
|
||||
{
|
||||
setupRequestHandler(scoreCount);
|
||||
|
||||
AddStep("load screen", () =>
|
||||
{
|
||||
@@ -40,7 +48,7 @@ namespace osu.Game.Tests.Visual.Matchmaking
|
||||
});
|
||||
}
|
||||
|
||||
private void setupRequestHandler()
|
||||
private void setupRequestHandler(int scoreCount)
|
||||
{
|
||||
AddStep("setup request handler", () =>
|
||||
{
|
||||
@@ -71,7 +79,7 @@ namespace osu.Game.Tests.Visual.Matchmaking
|
||||
case IndexPlaylistScoresRequest index:
|
||||
var result = new IndexedMultiplayerScores();
|
||||
|
||||
for (int i = 0; i < 8; ++i)
|
||||
for (int i = 0; i < scoreCount; ++i)
|
||||
{
|
||||
result.Scores.Add(new MultiplayerScore
|
||||
{
|
||||
|
||||
@@ -603,7 +603,7 @@ namespace osu.Game.Online.API
|
||||
cancellationToken.Cancel();
|
||||
}
|
||||
|
||||
private class WebRequestFlushedException : Exception
|
||||
internal class WebRequestFlushedException : Exception
|
||||
{
|
||||
public WebRequestFlushedException(APIState state)
|
||||
: base($@"Request failed from flush operation (state {state})")
|
||||
|
||||
@@ -153,7 +153,7 @@ namespace osu.Game.Online.Multiplayer
|
||||
/// <summary>
|
||||
/// Signals that a user has requested to skip the beatmap intro.
|
||||
/// </summary>
|
||||
Task UserVotedToSkipIntro(int userId);
|
||||
Task UserVotedToSkipIntro(int userId, bool voted);
|
||||
|
||||
/// <summary>
|
||||
/// Signals that the vote to skip the beatmap intro has passed.
|
||||
|
||||
@@ -36,5 +36,11 @@ namespace osu.Game.Online.Multiplayer.MatchTypes.Matchmaking
|
||||
/// </summary>
|
||||
[Key(3)]
|
||||
public MatchmakingRoundList Rounds { get; set; } = new MatchmakingRoundList();
|
||||
|
||||
/// <summary>
|
||||
/// The time at which this user abandoned the match.
|
||||
/// </summary>
|
||||
[Key(4)]
|
||||
public DateTimeOffset? AbandonedAt { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,42 +23,53 @@ namespace osu.Game.Online.Multiplayer.MatchTypes.Matchmaking
|
||||
ArgumentNullException.ThrowIfNull(x);
|
||||
ArgumentNullException.ThrowIfNull(y);
|
||||
|
||||
// X appears earlier in the list if it has more points.
|
||||
if (x.Points > y.Points)
|
||||
return -1;
|
||||
int compare = compareAbandonedAt(x, y);
|
||||
if (compare != 0)
|
||||
return compare;
|
||||
|
||||
// Y appears earlier in the list if it has more points.
|
||||
if (y.Points > x.Points)
|
||||
return 1;
|
||||
compare = comparePoints(x, y);
|
||||
if (compare != 0)
|
||||
return compare;
|
||||
|
||||
// Tiebreaker 1 (likely): From each user's point-of-view, their earliest and best placement.
|
||||
compare = compareRoundPlacements(x, y);
|
||||
if (compare != 0)
|
||||
return compare;
|
||||
|
||||
return compareUserIds(x, y);
|
||||
}
|
||||
|
||||
private int compareAbandonedAt(MatchmakingUser x, MatchmakingUser y)
|
||||
{
|
||||
DateTimeOffset xAbandonedAt = x.AbandonedAt ?? DateTimeOffset.MaxValue;
|
||||
DateTimeOffset yAbandonedAt = y.AbandonedAt ?? DateTimeOffset.MaxValue;
|
||||
return -xAbandonedAt.CompareTo(yAbandonedAt);
|
||||
}
|
||||
|
||||
private int comparePoints(MatchmakingUser x, MatchmakingUser y)
|
||||
{
|
||||
return -x.Points.CompareTo(y.Points);
|
||||
}
|
||||
|
||||
private int compareRoundPlacements(MatchmakingUser x, MatchmakingUser y)
|
||||
{
|
||||
for (int r = 1; r <= rounds; r++)
|
||||
{
|
||||
MatchmakingRound? xRound;
|
||||
x.Rounds.RoundsDictionary.TryGetValue(r, out xRound);
|
||||
x.Rounds.RoundsDictionary.TryGetValue(r, out var xRound);
|
||||
y.Rounds.RoundsDictionary.TryGetValue(r, out var yRound);
|
||||
|
||||
MatchmakingRound? yRound;
|
||||
y.Rounds.RoundsDictionary.TryGetValue(r, out yRound);
|
||||
int xPlacement = xRound?.Placement ?? int.MaxValue;
|
||||
int yPlacement = yRound?.Placement ?? int.MaxValue;
|
||||
|
||||
// Nothing to do if both players haven't played this round.
|
||||
if (xRound == null && yRound == null)
|
||||
continue;
|
||||
|
||||
// X appears later in the list if it hasn't played this round.
|
||||
if (xRound == null)
|
||||
return 1;
|
||||
|
||||
// Y appears later in the list if it hasn't played this round.
|
||||
if (yRound == null)
|
||||
return -1;
|
||||
|
||||
// X appears earlier in the list if it has a better placement in the round.
|
||||
int compare = xRound.Placement.CompareTo(yRound.Placement);
|
||||
int compare = xPlacement.CompareTo(yPlacement);
|
||||
if (compare != 0)
|
||||
return compare;
|
||||
}
|
||||
|
||||
// Tiebreaker 2 (unlikely): User ID.
|
||||
return 0;
|
||||
}
|
||||
|
||||
private int compareUserIds(MatchmakingUser x, MatchmakingUser y)
|
||||
{
|
||||
return x.UserId.CompareTo(y.UserId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,7 +131,7 @@ namespace osu.Game.Online.Multiplayer
|
||||
public event Action<int, long>? MatchmakingItemDeselected;
|
||||
public event Action<MatchRoomState>? MatchRoomStateChanged;
|
||||
|
||||
public event Action<int>? UserVotedToSkipIntro;
|
||||
public event Action<int, bool>? UserVotedToSkipIntro;
|
||||
public event Action? VoteToSkipIntroPassed;
|
||||
|
||||
public event Action<MultiplayerRoomUser, BeatmapAvailability>? BeatmapAvailabilityChanged;
|
||||
@@ -854,10 +854,6 @@ namespace osu.Game.Online.Multiplayer
|
||||
handleRoomRequest(() =>
|
||||
{
|
||||
Debug.Assert(Room != null);
|
||||
|
||||
foreach (var user in Room.Users)
|
||||
user.VotedToSkipIntro = false;
|
||||
|
||||
GameplayStarted?.Invoke();
|
||||
});
|
||||
|
||||
@@ -928,7 +924,7 @@ namespace osu.Game.Online.Multiplayer
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
Task IMultiplayerClient.UserVotedToSkipIntro(int userId)
|
||||
Task IMultiplayerClient.UserVotedToSkipIntro(int userId, bool voted)
|
||||
{
|
||||
handleRoomRequest(() =>
|
||||
{
|
||||
@@ -940,9 +936,8 @@ namespace osu.Game.Online.Multiplayer
|
||||
if (user == null)
|
||||
return;
|
||||
|
||||
user.VotedToSkipIntro = true;
|
||||
|
||||
UserVotedToSkipIntro?.Invoke(userId);
|
||||
user.VotedToSkipIntro = voted;
|
||||
UserVotedToSkipIntro?.Invoke(userId, voted);
|
||||
});
|
||||
|
||||
return Task.CompletedTask;
|
||||
@@ -1117,7 +1112,7 @@ namespace osu.Game.Online.Multiplayer
|
||||
|
||||
Task IMatchmakingClient.MatchmakingItemSelected(int userId, long playlistItemId)
|
||||
{
|
||||
Scheduler.Add(() =>
|
||||
handleRoomRequest(() =>
|
||||
{
|
||||
MatchmakingItemSelected?.Invoke(userId, playlistItemId);
|
||||
RoomUpdated?.Invoke();
|
||||
@@ -1128,7 +1123,7 @@ namespace osu.Game.Online.Multiplayer
|
||||
|
||||
Task IMatchmakingClient.MatchmakingItemDeselected(int userId, long playlistItemId)
|
||||
{
|
||||
Scheduler.Add(() =>
|
||||
handleRoomRequest(() =>
|
||||
{
|
||||
MatchmakingItemDeselected?.Invoke(userId, playlistItemId);
|
||||
RoomUpdated?.Invoke();
|
||||
|
||||
@@ -70,7 +70,7 @@ namespace osu.Game.Online.Multiplayer
|
||||
connection.On<MultiplayerPlaylistItem>(nameof(IMultiplayerClient.PlaylistItemAdded), ((IMultiplayerClient)this).PlaylistItemAdded);
|
||||
connection.On<long>(nameof(IMultiplayerClient.PlaylistItemRemoved), ((IMultiplayerClient)this).PlaylistItemRemoved);
|
||||
connection.On<MultiplayerPlaylistItem>(nameof(IMultiplayerClient.PlaylistItemChanged), ((IMultiplayerClient)this).PlaylistItemChanged);
|
||||
connection.On<int>(nameof(IMultiplayerClient.UserVotedToSkipIntro), ((IMultiplayerClient)this).UserVotedToSkipIntro);
|
||||
connection.On<int, bool>(nameof(IMultiplayerClient.UserVotedToSkipIntro), ((IMultiplayerClient)this).UserVotedToSkipIntro);
|
||||
connection.On(nameof(IMultiplayerClient.VoteToSkipIntroPassed), ((IMultiplayerClient)this).VoteToSkipIntroPassed);
|
||||
|
||||
connection.On(nameof(IMatchmakingClient.MatchmakingQueueJoined), ((IMatchmakingClient)this).MatchmakingQueueJoined);
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match
|
||||
resetPlaceholderText();
|
||||
|
||||
TextBox.HoldFocus = false;
|
||||
TextBox.ReleaseFocusOnCommit = true;
|
||||
TextBox.ReleaseFocusOnCommit = false;
|
||||
TextBox.Focus = () => TextBox.PlaceholderText = ChatStrings.InputPlaceholder;
|
||||
TextBox.FocusLost = resetPlaceholderText;
|
||||
|
||||
|
||||
@@ -520,6 +520,9 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match
|
||||
|
||||
private void onBeatmapAvailabilityChanged(MultiplayerRoomUser user, BeatmapAvailability availability) => Scheduler.Add(() =>
|
||||
{
|
||||
if (!user.Equals(RoomUser))
|
||||
return;
|
||||
|
||||
if (availability.State == DownloadState.Downloading)
|
||||
downloadProgressBar.FadeIn(200, Easing.OutPow10);
|
||||
else
|
||||
|
||||
@@ -23,6 +23,7 @@ using osu.Game.Online.Rooms;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Scoring;
|
||||
using osu.Game.Screens.Ranking;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match.RoundResults
|
||||
{
|
||||
@@ -31,8 +32,6 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match.RoundResults
|
||||
/// </summary>
|
||||
public partial class SubScreenRoundResults : MatchmakingSubScreen
|
||||
{
|
||||
private const int panel_spacing = 5;
|
||||
|
||||
public override PanelDisplayStyle PlayersDisplayStyle => PanelDisplayStyle.Hidden;
|
||||
public override Drawable? PlayersDisplayArea => null;
|
||||
|
||||
@@ -51,7 +50,7 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match.RoundResults
|
||||
[Resolved]
|
||||
private RulesetStore rulesets { get; set; } = null!;
|
||||
|
||||
private AutoScrollContainer scrollContainer = null!;
|
||||
private PanelContainer panelContainer = null!;
|
||||
private LoadingSpinner loadingSpinner = null!;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
@@ -59,7 +58,7 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match.RoundResults
|
||||
{
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
scrollContainer = new AutoScrollContainer
|
||||
panelContainer = new PanelContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both
|
||||
},
|
||||
@@ -136,78 +135,57 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match.RoundResults
|
||||
|
||||
private void setScores(ScoreInfo[] scores) => Scheduler.Add(() =>
|
||||
{
|
||||
Container panels;
|
||||
|
||||
scrollContainer.Child = panels = new Container
|
||||
panelContainer.ChildrenEnumerable = scores.Select(s => new RoundResultsScorePanel(s)
|
||||
{
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Width = scores.Length * (ScorePanel.CONTRACTED_WIDTH + panel_spacing),
|
||||
ChildrenEnumerable = scores.Select(s => new RoundResultsScorePanel(s)
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft
|
||||
})
|
||||
};
|
||||
|
||||
for (int i = 0; i < panels.Count; i++)
|
||||
{
|
||||
panels[i].MoveToX(panels.DrawWidth * 2)
|
||||
.Delay(i * 100)
|
||||
.MoveToX((ScorePanel.CONTRACTED_WIDTH + panel_spacing) * i, 500, Easing.OutQuint);
|
||||
}
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre
|
||||
});
|
||||
});
|
||||
|
||||
private partial class RoundResultsScorePanel : CompositeDrawable
|
||||
{
|
||||
public RoundResultsScorePanel(ScoreInfo score)
|
||||
{
|
||||
AutoSizeAxes = Axes.Both;
|
||||
InternalChild = new InstantSizingScorePanel(score);
|
||||
Size = new Vector2(ScorePanel.CONTRACTED_WIDTH, ScorePanel.CONTRACTED_HEIGHT);
|
||||
|
||||
InternalChild = new ScorePanel(score);
|
||||
}
|
||||
|
||||
public override bool PropagateNonPositionalInputSubTree => false;
|
||||
public override bool PropagatePositionalInputSubTree => false;
|
||||
|
||||
private partial class InstantSizingScorePanel : ScorePanel
|
||||
{
|
||||
public InstantSizingScorePanel(ScoreInfo score, bool isNewLocalScore = false)
|
||||
: base(score, isNewLocalScore)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
private partial class PanelContainer : Container<RoundResultsScorePanel>
|
||||
{
|
||||
base.LoadComplete();
|
||||
FinishTransforms(true);
|
||||
protected override Container<RoundResultsScorePanel> Content => flowContainer;
|
||||
|
||||
private readonly Container centreingContainer;
|
||||
private readonly Container<RoundResultsScorePanel> flowContainer;
|
||||
|
||||
public PanelContainer()
|
||||
{
|
||||
InternalChild = new OsuScrollContainer(Direction.Horizontal)
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Child = centreingContainer = new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Child = flowContainer = new FillFlowContainer<RoundResultsScorePanel>
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
AutoSizeAxes = Axes.X,
|
||||
Spacing = new Vector2(5)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private partial class AutoScrollContainer : UserTrackingScrollContainer
|
||||
{
|
||||
private const float initial_offset = -0.5f;
|
||||
private const double scroll_duration = 20000;
|
||||
|
||||
private double? scrollStartTime;
|
||||
|
||||
public AutoScrollContainer()
|
||||
: base(Direction.Horizontal)
|
||||
{
|
||||
};
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
if (!UserScrolling && Children.Count > 0)
|
||||
{
|
||||
scrollStartTime ??= Time.Current;
|
||||
|
||||
double scrollOffset = (Time.Current - scrollStartTime.Value) / scroll_duration;
|
||||
|
||||
if (scrollOffset < 1)
|
||||
ScrollTo(DrawWidth * (initial_offset + scrollOffset), false);
|
||||
}
|
||||
centreingContainer.Width = Math.Max(DrawWidth, flowContainer.DrawWidth);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
|
||||
|
||||
private void onUserStateChanged(MultiplayerRoomUser user, MultiplayerUserState state) => Schedule(updateCount);
|
||||
|
||||
private void onUserVotedToSkipIntro(int userId) => Schedule(() =>
|
||||
private void onUserVotedToSkipIntro(int userId, bool voted) => Schedule(() =>
|
||||
{
|
||||
FadingContent.TriggerShow();
|
||||
updateCount();
|
||||
|
||||
@@ -37,7 +37,7 @@ namespace osu.Game.Screens.Ranking
|
||||
/// <summary>
|
||||
/// Height of the panel when contracted.
|
||||
/// </summary>
|
||||
private const float contracted_height = 385;
|
||||
public const float CONTRACTED_HEIGHT = 385;
|
||||
|
||||
/// <summary>
|
||||
/// Width of the panel when expanded.
|
||||
@@ -280,7 +280,7 @@ namespace osu.Game.Screens.Ranking
|
||||
break;
|
||||
|
||||
case PanelState.Contracted:
|
||||
Size = new Vector2(CONTRACTED_WIDTH, contracted_height);
|
||||
Size = new Vector2(CONTRACTED_WIDTH, CONTRACTED_HEIGHT);
|
||||
|
||||
topLayerBackground.FadeColour(getColour(contracted_top_layer_colour), RESIZE_DURATION, Easing.OutQuint);
|
||||
middleLayerBackground.FadeColour(getColour(contracted_middle_layer_colour), RESIZE_DURATION, Easing.OutQuint);
|
||||
|
||||
@@ -568,7 +568,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
|
||||
public async Task UserVoteToSkipIntro(int userId)
|
||||
{
|
||||
await ((IMultiplayerClient)this).UserVotedToSkipIntro(userId).ConfigureAwait(false);
|
||||
await ((IMultiplayerClient)this).UserVotedToSkipIntro(userId, true).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
protected override Task<MultiplayerRoom> CreateRoomInternal(MultiplayerRoom room)
|
||||
|
||||
@@ -2,10 +2,14 @@
|
||||
// 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.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Net.WebSockets;
|
||||
using System.Threading.Tasks;
|
||||
using osu.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
@@ -17,6 +21,7 @@ using osu.Game.Beatmaps;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Models;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Rulesets;
|
||||
@@ -219,20 +224,35 @@ namespace osu.Game.Utils
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly HashSet<int> ignored_io_exception_hresults =
|
||||
[
|
||||
// see https://stackoverflow.com/a/9294382 for how these are synthesised
|
||||
unchecked((int)0x80070020), // ERROR_SHARING_VIOLATION
|
||||
unchecked((int)0x80070027), // ERROR_HANDLE_DISK_FULL
|
||||
unchecked((int)0x80070070), // ERROR_DISK_FULL
|
||||
];
|
||||
|
||||
private bool shouldSubmitException(Exception exception)
|
||||
{
|
||||
switch (exception)
|
||||
{
|
||||
case IOException ioe:
|
||||
// disk full exceptions, see https://stackoverflow.com/a/9294382
|
||||
const int hr_error_handle_disk_full = unchecked((int)0x80070027);
|
||||
const int hr_error_disk_full = unchecked((int)0x80070070);
|
||||
// disk I/O failures, invalid formats, etc.
|
||||
|
||||
if (ioe.HResult == hr_error_handle_disk_full || ioe.HResult == hr_error_disk_full)
|
||||
case IOException ioe:
|
||||
if (ignored_io_exception_hresults.Contains(ioe.HResult))
|
||||
return false;
|
||||
|
||||
break;
|
||||
|
||||
case UnauthorizedAccessException:
|
||||
case SharpCompress.Common.InvalidFormatException:
|
||||
return false;
|
||||
|
||||
// connectivity failures
|
||||
|
||||
case TimeoutException te:
|
||||
return !te.Message.Contains(@"elapsed without receiving a message from the server");
|
||||
|
||||
case WebException we:
|
||||
switch (we.Status)
|
||||
{
|
||||
@@ -242,6 +262,16 @@ namespace osu.Game.Utils
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case WebSocketException:
|
||||
case SocketException:
|
||||
return false;
|
||||
|
||||
// stuff that should really never make it to sentry
|
||||
|
||||
case APIAccess.WebRequestFlushedException:
|
||||
case TaskCanceledException:
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
</PackageReference>
|
||||
<PackageReference Include="Realm" Version="20.1.0" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2025.1205.1" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2025.1209.0" />
|
||||
<PackageReference Include="jvnkosu.Resources" Version="2025.1119.0" />
|
||||
<PackageReference Include="Sentry" Version="5.1.1" />
|
||||
<!-- Held back due to 0.34.0 failing AOT compilation on ZstdSharp.dll dependency. -->
|
||||
|
||||
@@ -17,6 +17,6 @@
|
||||
<MtouchInterpreter>-all</MtouchInterpreter>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ppy.osu.Framework.iOS" Version="2025.1205.1" />
|
||||
<PackageReference Include="ppy.osu.Framework.iOS" Version="2025.1209.0" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
Reference in New Issue
Block a user