Skip to content

Commit 8c2ced6

Browse files
authored
Merge pull request #11760 from smoogipoo/multiplayer-free-style
Add support for "freestyle" in multiplayer
2 parents f1d2b72 + 6e84fed commit 8c2ced6

File tree

4 files changed

+70
-7
lines changed

4 files changed

+70
-7
lines changed

app/Models/Multiplayer/PlaylistItem.php

+10
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
* @property int $owner_id
2222
* @property int|null $playlist_order
2323
* @property json|null $required_mods
24+
* @property bool $freestyle
2425
* @property Room $room
2526
* @property int $room_id
2627
* @property int|null $ruleset_id
@@ -35,6 +36,7 @@ class PlaylistItem extends Model
3536
protected $casts = [
3637
'allowed_mods' => 'object',
3738
'expired' => 'boolean',
39+
'freestyle' => 'boolean',
3840
'required_mods' => 'object',
3941
];
4042

@@ -64,6 +66,7 @@ public static function fromJsonParams(User $owner, $json)
6466
$obj->$field = $value;
6567
}
6668

69+
$obj->freestyle = get_bool($json['freestyle'] ?? false);
6770
$obj->max_attempts = get_int($json['max_attempts'] ?? null);
6871

6972
$modsHelper = app('mods');
@@ -169,6 +172,13 @@ private function assertValidRuleset()
169172

170173
private function assertValidMods()
171174
{
175+
if ($this->freestyle) {
176+
if (count($this->allowed_mods) !== 0 || count($this->required_mods) !== 0) {
177+
throw new InvariantException("mod isn't allowed in freestyle");
178+
}
179+
return;
180+
}
181+
172182
$allowedModIds = array_column($this->allowed_mods, 'acronym');
173183
$requiredModIds = array_column($this->required_mods, 'acronym');
174184

app/Models/Multiplayer/Room.php

+26-7
Original file line numberDiff line numberDiff line change
@@ -662,9 +662,21 @@ public function startPlay(User $user, PlaylistItem $playlistItem, array $rawPara
662662
{
663663
priv_check_user($user, 'MultiplayerScoreSubmit', $this)->ensureCan();
664664

665-
$this->assertValidStartPlay($user, $playlistItem);
665+
$params = get_params($rawParams, null, [
666+
'beatmap_hash',
667+
'beatmap_id:int',
668+
'build_id',
669+
'ruleset_id:int',
670+
], ['null_missing' => true]);
671+
672+
if (!$playlistItem->freestyle) {
673+
$params['beatmap_id'] = $playlistItem->beatmap_id;
674+
$params['ruleset_id'] = $playlistItem->ruleset_id;
675+
}
666676

667-
return $this->getConnection()->transaction(function () use ($playlistItem, $rawParams, $user) {
677+
$this->assertValidStartPlay($user, $playlistItem, $params);
678+
679+
return $this->getConnection()->transaction(function () use ($params, $playlistItem, $user) {
668680
$agg = UserScoreAggregate::new($user, $this);
669681
if ($agg->wasRecentlyCreated) {
670682
$this->incrementInstance('participant_count');
@@ -676,11 +688,11 @@ public function startPlay(User $user, PlaylistItem $playlistItem, array $rawPara
676688
$playlistItemAgg->updateUserAttempts();
677689

678690
return ScoreToken::create([
679-
'beatmap_hash' => get_string($rawParams['beatmap_hash'] ?? null),
680-
'beatmap_id' => $playlistItem->beatmap_id,
681-
'build_id' => $rawParams['build_id'],
691+
'beatmap_hash' => $params['beatmap_hash'],
692+
'beatmap_id' => $params['beatmap_id'],
693+
'build_id' => $params['build_id'],
682694
'playlist_item_id' => $playlistItem->getKey(),
683-
'ruleset_id' => $playlistItem->ruleset_id,
695+
'ruleset_id' => $params['ruleset_id'],
684696
'user_id' => $user->getKey(),
685697
]);
686698
});
@@ -741,14 +753,21 @@ private function assertValidStartGame()
741753
}
742754
}
743755

744-
private function assertValidStartPlay(User $user, PlaylistItem $playlistItem)
756+
private function assertValidStartPlay(User $user, PlaylistItem $playlistItem, array $params): void
745757
{
746758
// todo: check against room's end time (to see if player has enough time to play this beatmap) and is under the room's max attempts limit
747759

748760
if ($this->hasEnded()) {
749761
throw new InvariantException('Room has already ended.');
750762
}
751763

764+
if ($playlistItem->freestyle) {
765+
// assert the beatmap_id is part of playlist item's beatmapset
766+
if ($playlistItem->beatmap->beatmapset_id !== Beatmap::find($params['beatmap_id'])?->beatmapset_id) {
767+
throw new InvariantException('Specified beatmap_id is not allowed');
768+
}
769+
}
770+
752771
$userId = $user->getKey();
753772
if ($this->max_attempts !== null) {
754773
$roomStats = $this->userHighScores()->where('user_id', $userId)->first();

app/Transformers/Multiplayer/PlaylistItemTransformer.php

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ public function transform(PlaylistItem $item)
2424
'ruleset_id' => $item->ruleset_id,
2525
'allowed_mods' => $item->allowed_mods,
2626
'required_mods' => $item->required_mods,
27+
'freestyle' => $item->freestyle,
2728
'expired' => $item->expired,
2829
'owner_id' => $item->owner_id,
2930
'playlist_order' => $item->playlist_order,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
// Copyright (c) ppy Pty Ltd <[email protected]>. Licensed under the GNU Affero General Public License v3.0.
4+
// See the LICENCE file in the repository root for full licence text.
5+
6+
declare(strict_types=1);
7+
8+
use Illuminate\Database\Migrations\Migration;
9+
use Illuminate\Database\Schema\Blueprint;
10+
use Illuminate\Support\Facades\Schema;
11+
12+
return new class extends Migration
13+
{
14+
/**
15+
* Run the migrations.
16+
*/
17+
public function up(): void
18+
{
19+
Schema::table('multiplayer_playlist_items', function (Blueprint $table) {
20+
$table->boolean('freestyle')->after('required_mods')->default(false);
21+
});
22+
}
23+
24+
/**
25+
* Reverse the migrations.
26+
*/
27+
public function down(): void
28+
{
29+
Schema::table('multiplayer_playlist_items', function (Blueprint $table) {
30+
$table->dropColumn('freestyle');
31+
});
32+
}
33+
};

0 commit comments

Comments
 (0)