Skip to content

Commit 5c784b7

Browse files
authoredMar 24, 2025
Merge pull request #11988 from bdach/realtime-multiplayer-fail-allowance
Allow failed scores to display on results pages in realtime multiplayer
2 parents f1e68a7 + 2ec03bf commit 5c784b7

File tree

6 files changed

+95
-33
lines changed

6 files changed

+95
-33
lines changed
 

Diff for: ‎app/Models/Multiplayer/PlaylistItemUserHighScore.php

+5-1
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,11 @@ public function updateWithScoreLink(ScoreLink $scoreLink): bool
127127
{
128128
$score = $scoreLink->score;
129129

130-
if ($score === null || !$score->passed || $score->total_score <= $this->total_score) {
130+
if ($score === null || $score->total_score <= $this->total_score) {
131+
return false;
132+
}
133+
134+
if (!$score->passed && !$scoreLink->playlistItem->room->isRealtime()) {
131135
return false;
132136
}
133137

Diff for: ‎app/Models/Multiplayer/Room.php

+4
Original file line numberDiff line numberDiff line change
@@ -460,6 +460,10 @@ public function completePlay(ScoreToken $scoreToken, array $params): ScoreLink
460460
$this->assertValidCompletePlay();
461461

462462
return $this->getConnection()->transaction(function () use ($params, $scoreToken) {
463+
$playlistItem = $scoreToken->playlistItem()->firstOrFail();
464+
$playlistItem->setRelation('room', $this);
465+
$scoreToken->setRelation('playlistItem', $playlistItem);
466+
463467
$scoreLink = ScoreLink::complete($scoreToken, $params);
464468
$user = $scoreLink->user;
465469
$agg = UserScoreAggregate::new($user, $this);

Diff for: ‎app/Models/Multiplayer/ScoreLink.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public static function complete(ScoreToken $token, array $params): static
3131
// multiplayer scores are always preserved.
3232
$score = Score::createFromJsonOrExplode([...$params, 'preserve' => true]);
3333

34-
$playlistItem = $token->playlistItem()->firstOrFail();
34+
$playlistItem = $token->playlistItem;
3535
$requiredMods = array_column($playlistItem->required_mods, 'acronym');
3636
$mods = array_column($score->data->mods, 'acronym');
3737
$mods = app('mods')->excludeModsAlwaysValidForSubmission($score->ruleset_id, $mods);

Diff for: ‎app/Models/Multiplayer/UserScoreAggregate.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ public function recalculate()
121121
$scoreLinks = ScoreLink
122122
::whereHas('playlistItem', fn ($q) => $q->where('room_id', $this->room_id))
123123
->where('user_id', $this->user_id)
124-
->with('score')
124+
->with(['score', 'playlistItem.room'])
125125
->get();
126126
foreach ($scoreLinks as $scoreLink) {
127127
($playlistItemAggs[$scoreLink->playlist_item_id]

Diff for: ‎app/Models/ScoreToken.php

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
* @property int|null $build_id
1818
* @property \Carbon\Carbon|null $created_at
1919
* @property int $id
20+
* @property \App\Models\Multiplayer\PlaylistItem $playlistItem
2021
* @property int $ruleset_id
2122
* @property \App\Models\Solo\Score $score
2223
* @property int $score_id

Diff for: ‎tests/Models/Multiplayer/UserScoreAggregateTest.php

+83-30
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
namespace Tests\Models\Multiplayer;
99

1010
use App\Models\Multiplayer\PlaylistItem;
11+
use App\Models\Multiplayer\PlaylistItemUserHighScore;
1112
use App\Models\Multiplayer\Room;
1213
use App\Models\Multiplayer\UserScoreAggregate;
1314
use App\Models\User;
@@ -16,12 +17,19 @@
1617

1718
class UserScoreAggregateTest extends TestCase
1819
{
19-
private Room $room;
20+
private static function createPlaylistItem(Room $room): PlaylistItem
21+
{
22+
return PlaylistItem::factory()->create([
23+
'owner_id' => $room->host,
24+
'room_id' => $room,
25+
]);
26+
}
2027

2128
public function testAddingHigherScore(): void
2229
{
2330
$user = User::factory()->create();
24-
$playlistItem = $this->createPlaylistItem();
31+
$room = Room::factory()->create();
32+
$playlistItem = self::createPlaylistItem($room);
2533

2634
// first play
2735
$scoreLink = $this->roomAddPlay($user, $playlistItem, [
@@ -30,7 +38,7 @@ public function testAddingHigherScore(): void
3038
'total_score' => 10,
3139
]);
3240

33-
$agg = UserScoreAggregate::new($user, $this->room);
41+
$agg = UserScoreAggregate::new($user, $room);
3442
$this->assertSame(1, $agg->completed);
3543
$this->assertSame(0.5, $agg->accuracy);
3644
$this->assertSame(10, $agg->total_score);
@@ -53,7 +61,8 @@ public function testAddingHigherScore(): void
5361
public function testAddingLowerScore(): void
5462
{
5563
$user = User::factory()->create();
56-
$playlistItem = $this->createPlaylistItem();
64+
$room = Room::factory()->create();
65+
$playlistItem = self::createPlaylistItem($room);
5766

5867
// first play
5968
$scoreLink = $this->roomAddPlay($user, $playlistItem, [
@@ -62,7 +71,7 @@ public function testAddingLowerScore(): void
6271
'total_score' => 10,
6372
]);
6473

65-
$agg = UserScoreAggregate::new($user, $this->room);
74+
$agg = UserScoreAggregate::new($user, $room);
6675
$this->assertSame(1, $agg->completed);
6776
$this->assertSame(0.5, $agg->accuracy);
6877
$this->assertSame(10, $agg->total_score);
@@ -86,7 +95,8 @@ public function testAddingEqualScore(): void
8695
{
8796
$firstUser = User::factory()->create();
8897
$secondUser = User::factory()->create();
89-
$playlistItem = $this->createPlaylistItem();
98+
$room = Room::factory()->create();
99+
$playlistItem = self::createPlaylistItem($room);
90100

91101
// first user sets play
92102
$firstUserPlay = $this->roomAddPlay($firstUser, $playlistItem, [
@@ -95,7 +105,7 @@ public function testAddingEqualScore(): void
95105
'total_score' => 10,
96106
]);
97107

98-
$firstUserAgg = UserScoreAggregate::new($firstUser, $this->room);
108+
$firstUserAgg = UserScoreAggregate::new($firstUser, $room);
99109
$this->assertSame(1, $firstUserAgg->completed);
100110
$this->assertSame(0.5, $firstUserAgg->accuracy);
101111
$this->assertSame(10, $firstUserAgg->total_score);
@@ -109,7 +119,7 @@ public function testAddingEqualScore(): void
109119
'total_score' => 10,
110120
]);
111121

112-
$secondUserAgg = UserScoreAggregate::new($secondUser, $this->room);
122+
$secondUserAgg = UserScoreAggregate::new($secondUser, $room);
113123
$this->assertSame(1, $secondUserAgg->completed);
114124
$this->assertSame(0.5, $secondUserAgg->accuracy);
115125
$this->assertSame(10, $secondUserAgg->total_score);
@@ -137,8 +147,9 @@ public function testAddingEqualScore(): void
137147
public function testAddingMultiplePlaylistItems(): void
138148
{
139149
$user = User::factory()->create();
140-
$playlistItem = $this->createPlaylistItem();
141-
$playlistItem2 = $this->createPlaylistItem();
150+
$room = Room::factory()->create();
151+
$playlistItem = self::createPlaylistItem($room);
152+
$playlistItem2 = self::createPlaylistItem($room);
142153

143154
// first playlist item
144155
$this->roomAddPlay($user, $playlistItem, [
@@ -147,7 +158,7 @@ public function testAddingMultiplePlaylistItems(): void
147158
'total_score' => 10,
148159
]);
149160

150-
$agg = UserScoreAggregate::new($user, $this->room);
161+
$agg = UserScoreAggregate::new($user, $room);
151162
$this->assertSame(1, $agg->completed);
152163
$this->assertSame(0.5, $agg->accuracy);
153164
$this->assertSame(0.5, $agg->averageAccuracy());
@@ -171,10 +182,11 @@ public function testAddingMultiplePlaylistItems(): void
171182
public function testStartingPlayIncreasesAttempts(): void
172183
{
173184
$user = User::factory()->create();
174-
$playlistItem = $this->createPlaylistItem();
185+
$room = Room::factory()->create();
186+
$playlistItem = self::createPlaylistItem($room);
175187

176188
static::roomStartPlay($user, $playlistItem);
177-
$agg = UserScoreAggregate::new($user, $this->room);
189+
$agg = UserScoreAggregate::new($user, $room);
178190

179191
$this->assertSame(1, $agg->attempts);
180192
$this->assertSame(0, $agg->completed);
@@ -183,22 +195,23 @@ public function testStartingPlayIncreasesAttempts(): void
183195
public function testFailedScoresAreAttemptsOnly(): void
184196
{
185197
$user = User::factory()->create();
186-
$playlistItem = $this->createPlaylistItem();
198+
$room = Room::factory()->create();
199+
$playlistItem = self::createPlaylistItem($room);
187200

188201
$this->roomAddPlay($user, $playlistItem, [
189202
'accuracy' => 0.1,
190203
'passed' => false,
191204
'total_score' => 10,
192205
]);
193206

194-
$playlistItem2 = $this->createPlaylistItem();
207+
$playlistItem2 = self::createPlaylistItem($room);
195208
$this->roomAddPlay($user, $playlistItem2, [
196209
'accuracy' => 1,
197210
'passed' => true,
198211
'total_score' => 1,
199212
]);
200213

201-
$agg = UserScoreAggregate::new($user, $this->room);
214+
$agg = UserScoreAggregate::new($user, $room);
202215

203216
$this->assertSame(2, $agg->attempts);
204217
$this->assertSame(1, $agg->completed);
@@ -209,15 +222,16 @@ public function testFailedScoresAreAttemptsOnly(): void
209222
public function testPassedScoresIncrementsCompletedCount(): void
210223
{
211224
$user = User::factory()->create();
212-
$playlistItem = $this->createPlaylistItem();
225+
$room = Room::factory()->create();
226+
$playlistItem = self::createPlaylistItem($room);
213227

214228
$this->roomAddPlay($user, $playlistItem, [
215229
'accuracy' => 1,
216230
'passed' => true,
217231
'total_score' => 1,
218232
]);
219233

220-
$agg = UserScoreAggregate::new($user, $this->room);
234+
$agg = UserScoreAggregate::new($user, $room);
221235

222236
$this->assertSame(1, $agg->completed);
223237
$this->assertSame(1, $agg->total_score);
@@ -226,8 +240,9 @@ public function testPassedScoresIncrementsCompletedCount(): void
226240
public function testPassedScoresAreAveragedInTransformer(): void
227241
{
228242
$user = User::factory()->create();
229-
$playlistItem = $this->createPlaylistItem();
230-
$playlistItem2 = $this->createPlaylistItem();
243+
$room = Room::factory()->create();
244+
$playlistItem = self::createPlaylistItem($room);
245+
$playlistItem2 = self::createPlaylistItem($room);
231246

232247
$this->roomAddPlay($user, $playlistItem, [
233248
'accuracy' => 0.1,
@@ -253,7 +268,7 @@ public function testPassedScoresAreAveragedInTransformer(): void
253268
'total_score' => 1,
254269
]);
255270

256-
$agg = UserScoreAggregate::new($user, $this->room);
271+
$agg = UserScoreAggregate::new($user, $room);
257272

258273
$result = json_item($agg, new UserScoreAggregateTransformer());
259274

@@ -262,14 +277,15 @@ public function testPassedScoresAreAveragedInTransformer(): void
262277

263278
public function testRecalculate(): void
264279
{
265-
$playlistItem = $this->createPlaylistItem();
280+
$room = Room::factory()->create();
281+
$playlistItem = self::createPlaylistItem($room);
266282
$user = User::factory()->create();
267283
$this->roomAddPlay($user, $playlistItem, [
268284
'accuracy' => 0.3,
269285
'passed' => true,
270286
'total_score' => 1,
271287
]);
272-
$agg = UserScoreAggregate::new($user, $this->room);
288+
$agg = UserScoreAggregate::new($user, $room);
273289
$agg->recalculate();
274290
$agg->refresh();
275291

@@ -279,18 +295,55 @@ public function testRecalculate(): void
279295
$this->assertSame(1, $agg->completed);
280296
}
281297

282-
protected function setUp(): void
298+
public function testFailedScoresCountToAggregateInRealtime(): void
283299
{
284-
parent::setUp();
300+
$user = User::factory()->create();
301+
$room = Room::factory()->create([
302+
'type' => 'head_to_head',
303+
]);
304+
$playlistItem = self::createPlaylistItem($room);
285305

286-
$this->room = Room::factory()->create();
306+
$scoreLink = $this->roomAddPlay($user, $playlistItem, [
307+
'accuracy' => 0.6,
308+
'passed' => false,
309+
'total_score' => 1000,
310+
]);
311+
312+
$agg = UserScoreAggregate::new($user, $room);
313+
314+
$this->assertSame(1, $agg->completed);
315+
$this->assertSame(1000, $agg->total_score);
316+
317+
$userHighScore = PlaylistItemUserHighScore::where([
318+
'playlist_item_id' => $playlistItem->getKey(),
319+
'user_id' => $user->getKey(),
320+
])->first();
321+
$this->assertSame($scoreLink->score_id, $userHighScore->score_id);
287322
}
288323

289-
private function createPlaylistItem(): PlaylistItem
324+
public function testFailedScoresDoNotCountToAggregateInPlaylists(): void
290325
{
291-
return PlaylistItem::factory()->create([
292-
'owner_id' => $this->room->host,
293-
'room_id' => $this->room,
326+
$user = User::factory()->create();
327+
$room = Room::factory()->create([
328+
'type' => 'playlists',
294329
]);
330+
$playlistItem = self::createPlaylistItem($room);
331+
332+
$this->roomAddPlay($user, $playlistItem, [
333+
'accuracy' => 0.6,
334+
'passed' => false,
335+
'total_score' => 1000,
336+
]);
337+
338+
$agg = UserScoreAggregate::new($user, $room);
339+
340+
$this->assertSame(0, $agg->completed);
341+
$this->assertSame(0, $agg->total_score);
342+
343+
$userHighScore = PlaylistItemUserHighScore::where([
344+
'playlist_item_id' => $playlistItem->getKey(),
345+
'user_id' => $user->getKey(),
346+
])->first();
347+
$this->assertNull($userHighScore->score_id);
295348
}
296349
}

0 commit comments

Comments
 (0)