mirror of
https://github.com/Deathgarden-Rebirth/Deathgarden_Rebirth-Rewrite.git
synced 2026-09-08 11:15:09 -05:00
179 lines
6.9 KiB
PHP
179 lines
6.9 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Api;
|
|
|
|
use App\Enums\Game\Faction;
|
|
use App\Enums\Game\Leaderboard\Window;
|
|
use App\Http\Controllers\Controller;
|
|
use App\Http\Requests\Api\Leaderboard\GetScoresRequest;
|
|
use App\Http\Responses\Api\Leaderboard\GetScoresResponse;
|
|
use App\Http\Responses\Api\Leaderboard\LeaderboardEntry;
|
|
use App\Models\Admin\Archive\ArchivedPlayerProgression;
|
|
use Illuminate\Database\Eloquent\Builder;
|
|
use Illuminate\Support\Carbon;
|
|
use Illuminate\Database\Eloquent\Collection;
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
class LeaderboardController extends Controller
|
|
{
|
|
public function getScores(GetScoresRequest $request)
|
|
{
|
|
return match ($request->window) {
|
|
Window::PersonalBest => static::handlePersonalBestWindow($request),
|
|
Window::Lobby => static::handleLobbyWindow($request),
|
|
};
|
|
}
|
|
|
|
public static function handlePersonalBestWindow(GetScoresRequest $request)
|
|
{
|
|
$response = new GetScoresResponse();
|
|
|
|
$topScores = [];
|
|
$startDate = static::getCurrentLeaderboardStartDate();
|
|
|
|
static::getLeaderboardTopScores(5, $request->faction, $startDate)
|
|
->each(function (ArchivedPlayerProgression $item, int $rank) use (&$topScores) {
|
|
$topScores[] = new LeaderboardEntry(
|
|
$item->user,
|
|
$item->gained_experience,
|
|
$rank + 1,
|
|
);
|
|
});
|
|
|
|
foreach ($request->playerIds as $playerId) {
|
|
$entries = static::getLeaderboardEntriesForPlayer($playerId, $request->faction, $startDate);
|
|
$response->playerScores[$playerId] = [];
|
|
|
|
$entries->each(function (ArchivedPlayerProgression $item) use (&$response, $playerId) {
|
|
$response->playerScores[$playerId][] = new LeaderboardEntry(
|
|
$item->user,
|
|
$item->gained_experience,
|
|
$item->rank,
|
|
);
|
|
});
|
|
}
|
|
|
|
$response->topScores = $topScores;
|
|
$response->leaderboardSize = static::getLeaderboardSize($request->faction, $startDate);
|
|
$response->leaderboardReset = static::getCurrentLeaderboardEndDate();
|
|
|
|
return $response;
|
|
}
|
|
|
|
public static function handleLobbyWindow(GetScoresRequest $request)
|
|
{
|
|
$response = new GetScoresResponse();
|
|
|
|
$startDate = static::getCurrentLeaderboardStartDate();
|
|
|
|
static::getLeaderboardEntriesForPlayer($request->playerIds, $request->faction, $startDate)
|
|
->each(function (ArchivedPlayerProgression $item) use (&$response, &$lobbyScores) {
|
|
$response->playerScores[$item->user_id][] = new LeaderboardEntry(
|
|
$item->user,
|
|
$item->gained_experience,
|
|
$item->rank,
|
|
);
|
|
});
|
|
|
|
$response->leaderboardSize = static::getLeaderboardSize($request->faction, $startDate);
|
|
$response->leaderboardReset = static::getCurrentLeaderboardEndDate();
|
|
|
|
return $response;
|
|
}
|
|
|
|
/**
|
|
* @param string|array $userId Select the given user id. if its an array it only selects them and no one around.
|
|
* @param Faction $faction
|
|
* @param Carbon $startDate Player scores before this Time won't get selected.
|
|
* @param ?Carbon $endDate scores after this time won't be selected, defaults to now when null.
|
|
* @return Collection<int, ArchivedPlayerProgression>
|
|
*/
|
|
public static function getLeaderboardEntriesForPlayer(string|array $userId, Faction $faction, Carbon $startDate, ?Carbon $endDate = null): Collection
|
|
{
|
|
$endDate ??= Carbon::now();
|
|
|
|
$subSubQuery = static::getBaseSelectQuery($faction, $startDate, $endDate);
|
|
|
|
$query = ArchivedPlayerProgression::query();
|
|
$query->orderBy('gained_experience', 'desc');
|
|
$query->select(['user_id', 'gained_experience'])
|
|
->addSelect(DB::raw('ROW_NUMBER() OVER (ORDER BY gained_experience DESC) AS "rank"'));
|
|
$query->fromSub($subSubQuery, 'a');
|
|
|
|
$mainQuery = ArchivedPlayerProgression::query();
|
|
$mainQuery->fromSub($query, 'b');
|
|
|
|
if (is_array($userId)) {
|
|
$mainQuery->whereIn('user_id', $userId);
|
|
} else {
|
|
$mainQuery->where('rank', '<=', function (\Illuminate\Database\Query\Builder $whereQuery) use ($userId, $query) {
|
|
$whereQuery->where('user_id', $userId);
|
|
$whereQuery->fromSub($query, 'c');
|
|
$whereQuery->selectRaw('(c.rank + (CASE c.rank WHEN 1 THEN 4 WHEN 2 THEN 3 WHEN 3 THEN 2 ELSE 1 END))');
|
|
});
|
|
}
|
|
$mainQuery->orderByDesc('rank');
|
|
$mainQuery->limit(is_array($userId) ? count($userId) : 5);
|
|
|
|
return $mainQuery->get();
|
|
}
|
|
|
|
/**
|
|
* @param int $count
|
|
* @param Faction $faction
|
|
* @param Carbon $startDate Player scores before this Time won't get selected.
|
|
* @param ?Carbon $endDate scores after this time won't be selected, defaults to now when null.
|
|
* @return Collection<int, ArchivedPlayerProgression>
|
|
*/
|
|
public static function getLeaderboardTopScores(int $count, Faction $faction, Carbon $startDate, ?Carbon $endDate = null): Collection
|
|
{
|
|
$endDate ??= Carbon::now();
|
|
|
|
$query = static::getBaseSelectQuery($faction, $startDate, $endDate);
|
|
$query->limit($count);
|
|
|
|
return $query->get();
|
|
}
|
|
|
|
public static function getCurrentLeaderboardStartDate(): Carbon
|
|
{
|
|
return Carbon::today()->firstOfMonth()->addHours(20);
|
|
}
|
|
|
|
public static function getCurrentLeaderboardEndDate(): Carbon {
|
|
return Carbon::today()->addMonth()->firstOfMonth()->addHours(20);
|
|
}
|
|
|
|
/**
|
|
* @param Faction $faction
|
|
* @param Carbon $startDate Player scores before this Time won't get selected.
|
|
* @param ?Carbon $endDate scores after this time won't be selected, defaults to now when null.
|
|
* @return int
|
|
*/
|
|
public static function getLeaderboardSize(Faction $faction, Carbon $startDate, ?Carbon $endDate = null): int
|
|
{
|
|
$endDate ??= Carbon::now();
|
|
|
|
$query = ArchivedPlayerProgression::query();
|
|
$query->whereDate('created_at', '>=', $startDate);
|
|
$query->whereDate('created_at', '<=', $endDate);
|
|
$query->whereIn('played_character', $faction->getCharacterList());
|
|
$query->distinct('user_id');
|
|
$query->selectRaw('user_id');
|
|
|
|
return $query->count('user_id');
|
|
}
|
|
|
|
protected static function getBaseSelectQuery(Faction $faction, Carbon $startDate, Carbon $endDate): Builder
|
|
{
|
|
$subSubQuery = ArchivedPlayerProgression::query();
|
|
$subSubQuery->select(['user_id'])->addSelect(DB::raw('MAX(gained_experience) as gained_experience'));
|
|
$subSubQuery->whereDate('created_at', '>=', $startDate);
|
|
$subSubQuery->whereDate('created_at', '<=', $endDate);
|
|
$subSubQuery->whereIn('played_character', $faction->getCharacterList());
|
|
$subSubQuery->groupBy('user_id');
|
|
$subSubQuery->orderByDesc('gained_experience');
|
|
|
|
return $subSubQuery;
|
|
}
|
|
} |