108 lines
4.3 KiB
PHP
108 lines
4.3 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
header('Content-Type: application/json; charset=utf-8');
|
|
|
|
require_once __DIR__ . '/../game_bootstrap.php';
|
|
|
|
function jsonResponse(array $payload, int $status = 200): void
|
|
{
|
|
http_response_code($status);
|
|
echo json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
|
exit;
|
|
}
|
|
|
|
function safeLength(string $value): int
|
|
{
|
|
return function_exists('mb_strlen') ? mb_strlen($value) : strlen($value);
|
|
}
|
|
|
|
try {
|
|
ensureFpsMatchesTable();
|
|
|
|
if ($_SERVER['REQUEST_METHOD'] === 'GET') {
|
|
if (isset($_GET['id'])) {
|
|
$id = filter_var($_GET['id'], FILTER_VALIDATE_INT, ['options' => ['min_range' => 1]]);
|
|
if (!$id) {
|
|
jsonResponse(['success' => false, 'error' => 'Invalid match id.'], 422);
|
|
}
|
|
|
|
$match = fetchMatchById($id);
|
|
if (!$match) {
|
|
jsonResponse(['success' => false, 'error' => 'Match not found.'], 404);
|
|
}
|
|
|
|
jsonResponse(['success' => true, 'match' => $match]);
|
|
}
|
|
|
|
$limit = filter_var($_GET['limit'] ?? 8, FILTER_VALIDATE_INT, ['options' => ['min_range' => 1, 'max_range' => 20]]) ?: 8;
|
|
jsonResponse(['success' => true, 'matches' => fetchRecentMatches($limit)]);
|
|
}
|
|
|
|
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
|
jsonResponse(['success' => false, 'error' => 'Method not allowed.'], 405);
|
|
}
|
|
|
|
$raw = file_get_contents('php://input') ?: '';
|
|
$payload = json_decode($raw, true);
|
|
if (!is_array($payload)) {
|
|
jsonResponse(['success' => false, 'error' => 'Invalid request payload.'], 422);
|
|
}
|
|
|
|
$playerName = trim((string)($payload['player_name'] ?? 'Operator'));
|
|
$weaponKey = trim((string)($payload['weapon_key'] ?? 'carbine'));
|
|
$weaponName = trim((string)($payload['weapon_name'] ?? 'Carbine'));
|
|
$outcome = trim((string)($payload['outcome'] ?? 'defeat'));
|
|
|
|
if ($playerName === '' || safeLength($playerName) > 80) {
|
|
jsonResponse(['success' => false, 'error' => 'Player name must be between 1 and 80 characters.'], 422);
|
|
}
|
|
|
|
if ($weaponKey === '' || safeLength($weaponKey) > 40 || $weaponName === '' || safeLength($weaponName) > 80) {
|
|
jsonResponse(['success' => false, 'error' => 'Weapon metadata is invalid.'], 422);
|
|
}
|
|
|
|
if (!in_array($outcome, ['victory', 'defeat', 'timeout'], true)) {
|
|
$outcome = 'defeat';
|
|
}
|
|
|
|
$kills = max(0, min(999, (int)($payload['kills'] ?? 0)));
|
|
$shotsFired = max(0, min(9999, (int)($payload['shots_fired'] ?? 0)));
|
|
$shotsHit = max(0, min($shotsFired, (int)($payload['shots_hit'] ?? 0)));
|
|
$damageTaken = max(0, min(999, (int)($payload['damage_taken'] ?? 0)));
|
|
$durationSeconds = max(0, min(3600, (int)($payload['duration_seconds'] ?? 0)));
|
|
$score = max(0, min(999999, (int)($payload['score'] ?? 0)));
|
|
$accuracy = $shotsFired > 0 ? round(($shotsHit / $shotsFired) * 100, 2) : 0.0;
|
|
|
|
$stmt = db()->prepare(
|
|
'INSERT INTO fps_matches (
|
|
player_name, weapon_key, weapon_name, kills, shots_fired, shots_hit, accuracy,
|
|
damage_taken, duration_seconds, score, outcome
|
|
) VALUES (
|
|
:player_name, :weapon_key, :weapon_name, :kills, :shots_fired, :shots_hit, :accuracy,
|
|
:damage_taken, :duration_seconds, :score, :outcome
|
|
)'
|
|
);
|
|
|
|
$stmt->bindValue(':player_name', $playerName, PDO::PARAM_STR);
|
|
$stmt->bindValue(':weapon_key', $weaponKey, PDO::PARAM_STR);
|
|
$stmt->bindValue(':weapon_name', $weaponName, PDO::PARAM_STR);
|
|
$stmt->bindValue(':kills', $kills, PDO::PARAM_INT);
|
|
$stmt->bindValue(':shots_fired', $shotsFired, PDO::PARAM_INT);
|
|
$stmt->bindValue(':shots_hit', $shotsHit, PDO::PARAM_INT);
|
|
$stmt->bindValue(':accuracy', $accuracy);
|
|
$stmt->bindValue(':damage_taken', $damageTaken, PDO::PARAM_INT);
|
|
$stmt->bindValue(':duration_seconds', $durationSeconds, PDO::PARAM_INT);
|
|
$stmt->bindValue(':score', $score, PDO::PARAM_INT);
|
|
$stmt->bindValue(':outcome', $outcome, PDO::PARAM_STR);
|
|
$stmt->execute();
|
|
|
|
$id = (int)db()->lastInsertId();
|
|
$match = fetchMatchById($id);
|
|
|
|
jsonResponse(['success' => true, 'message' => 'Match saved.', 'match' => $match], 201);
|
|
} catch (Throwable $e) {
|
|
error_log('fps_matches API error: ' . $e->getMessage());
|
|
jsonResponse(['success' => false, 'error' => 'Unable to process match request right now.'], 500);
|
|
}
|