the browser-facing portion of osu!
at master 83 lines 3.1 kB view raw
1<?php 2 3// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the GNU Affero General Public License v3.0. 4// See the LICENCE file in the repository root for full licence text. 5 6namespace App\Models\Traits; 7 8use App\Libraries\Score\FetchDedupedScores; 9use App\Libraries\Search\ScoreSearchParams; 10use App\Models\Beatmap; 11use App\Models\Solo\Score; 12use Illuminate\Database\Eloquent\Collection; 13 14trait UserScoreable 15{ 16 private array $beatmapBestScoreIds = []; 17 private array $beatmapBestScores = []; 18 19 public function aggregatedScoresBest(string $mode, null | true $legacyOnly, int $size): array 20 { 21 return (new FetchDedupedScores('beatmap_id', ScoreSearchParams::fromArray([ 22 'exclude_without_pp' => true, 23 'is_legacy' => $legacyOnly, 24 'limit' => $size, 25 'ruleset_id' => Beatmap::MODES[$mode], 26 'sort' => 'pp_desc', 27 'user_id' => $this->getKey(), 28 ]), "aggregatedScoresBest_{$mode}"))->all(); 29 } 30 31 public function beatmapBestScoreIds(string $mode, null | true $legacyOnly) 32 { 33 $key = $mode.'-'.($legacyOnly ? '1' : '0'); 34 35 if (!isset($this->beatmapBestScoreIds[$key])) { 36 // aggregations do not support regular pagination. 37 // always fetching 100 to cache; we're not supporting beyond 100, either. 38 $this->beatmapBestScoreIds[$key] = cache_remember_mutexed( 39 "search-cache:beatmapBestScoresSolo:{$this->getKey()}:{$key}", 40 $GLOBALS['cfg']['osu']['scores']['es_cache_duration'], 41 [], 42 function () use ($key, $legacyOnly, $mode) { 43 $this->beatmapBestScores[$key] = $this->aggregatedScoresBest($mode, $legacyOnly, 100); 44 45 return array_column($this->beatmapBestScores[$key], 'id'); 46 }, 47 function () { 48 // TODO: propagate a more useful message back to the client 49 // for now we just mark the exception as handled. 50 return true; 51 } 52 ); 53 } 54 55 return $this->beatmapBestScoreIds[$key]; 56 } 57 58 public function beatmapBestScores(string $mode, int $limit, int $offset, array $with, null | true $legacyOnly): Collection 59 { 60 $ids = $this->beatmapBestScoreIds($mode, $legacyOnly); 61 $key = $mode.'-'.($legacyOnly ? '1' : '0'); 62 63 if (isset($this->beatmapBestScores[$key])) { 64 $results = new Collection(array_slice($this->beatmapBestScores[$key], $offset, $limit)); 65 } else { 66 $ids = array_slice($ids, $offset, $limit); 67 $results = Score::whereKey($ids)->orderByField('id', $ids)->default()->get(); 68 } 69 70 $results->load($with); 71 72 // fill in positions for weighting 73 // also preload the user relation 74 $position = $offset; 75 foreach ($results as $result) { 76 $result->weight = pow(0.95, $position); 77 $result->setRelation('user', $this); 78 $position++; 79 } 80 81 return $results; 82 } 83}