mirror of
https://github.com/ppy/osu.git
synced 2026-05-17 21:13:01 +08:00
Merge pull request #35923 from smoogipoo/qp-abandoned-at
Consider abandon time for user placements
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user