39001-vm/room.php
2026-03-05 10:39:31 +00:00

206 lines
7.8 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
declare(strict_types=1);
@ini_set('display_errors', '1');
@error_reporting(E_ALL);
@date_default_timezone_set('UTC');
session_start();
require_once __DIR__ . '/includes/rooms.php';
ensure_rooms_schema();
$roomId = (int) ($_GET['id'] ?? 0);
if ($roomId <= 0) {
http_response_code(404);
echo 'Room not found';
exit;
}
if (isset($_GET['leave'])) {
$sessionPlayer = get_session_player($roomId);
if ($sessionPlayer) {
$room = get_room($roomId);
if ($room) {
$newRoom = remove_player_from_room($room, $sessionPlayer['token']);
if ($newRoom === null) {
delete_room($roomId);
} else {
save_room_state($roomId, $newRoom['state'], $newRoom['status']);
}
}
}
unset($_SESSION['room_players'][$roomId]);
header('Location: /');
exit;
}
$room = get_room($roomId);
if (!$room) {
http_response_code(404);
echo 'Room not found';
exit;
}
$errors = [];
if ($_SERVER['REQUEST_METHOD'] === 'POST' && ($_POST['action'] ?? '') === 'join') {
$playerName = trim($_POST['player_name'] ?? '');
if ($playerName === '') {
$errors[] = 'Введите ник.';
} else {
try {
$token = random_token();
$state = add_player_to_room($room, $playerName, $token);
save_room_state($roomId, $state, $room['status']);
set_session_player($roomId, $token, $playerName);
$room['state'] = $state;
} catch (RuntimeException $e) {
$errors[] = $e->getMessage();
}
}
}
$sessionPlayer = get_session_player($roomId);
$state = $room['state'];
$players = $state['players'] ?? [];
$isMember = false;
$isHost = false;
foreach ($players as $player) {
if ($sessionPlayer && $player['token'] === $sessionPlayer['token']) {
$isMember = true;
$isHost = !empty($player['is_host']);
break;
}
}
$phpVersion = PHP_VERSION;
?>
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Комната <?= htmlspecialchars($room['name']) ?> — Bomber Rooms</title>
<?php
$projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? '';
$projectImageUrl = $_SERVER['PROJECT_IMAGE_URL'] ?? '';
?>
<?php if ($projectDescription): ?>
<meta name="description" content='<?= htmlspecialchars($projectDescription) ?>' />
<meta property="og:description" content="<?= htmlspecialchars($projectDescription) ?>" />
<meta property="twitter:description" content="<?= htmlspecialchars($projectDescription) ?>" />
<?php endif; ?>
<?php if ($projectImageUrl): ?>
<meta property="og:image" content="<?= htmlspecialchars($projectImageUrl) ?>" />
<meta property="twitter:image" content="<?= htmlspecialchars($projectImageUrl) ?>" />
<?php endif; ?>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet" />
<link rel="stylesheet" href="assets/css/custom.css?v=<?= time(); ?>" />
</head>
<body>
<nav class="navbar navbar-light bg-white border-bottom small shadow-sm sticky-top">
<div class="container">
<a class="navbar-brand fw-semibold text-dark" href="/">Bomber Rooms</a>
<div class="d-flex gap-2">
<a class="btn btn-outline-dark btn-sm" href="/">Лобби</a>
<a class="btn btn-dark btn-sm" href="room.php?id=<?= (int) $roomId ?>&leave=1">Выйти</a>
</div>
</div>
</nav>
<main class="py-5">
<div class="container">
<div class="d-flex justify-content-between align-items-start flex-wrap gap-3 mb-4">
<div>
<p class="text-uppercase text-muted small mb-2">Комната #<?= (int) $roomId ?></p>
<h1 class="h3 fw-semibold mb-2"><?= htmlspecialchars($room['name']) ?></h1>
<p class="text-muted mb-0">Статус: <span class="badge text-bg-light border"><?= htmlspecialchars($room['status']) ?></span></p>
</div>
<div class="panel px-3 py-2 small text-muted">
Игроков: <strong><?= count($players) ?> / <?= (int) $room['max_players'] ?></strong>
</div>
</div>
<?php if ($errors): ?>
<div class="alert alert-danger"><?= htmlspecialchars(implode(' ', $errors)) ?></div>
<?php endif; ?>
<?php if (!$isMember): ?>
<div class="panel p-4 mb-4">
<h2 class="h5 fw-semibold mb-3">Войти в комнату</h2>
<form method="post" class="row g-3">
<input type="hidden" name="action" value="join">
<div class="col-md-6">
<label class="form-label small text-muted">Ваш ник</label>
<input type="text" name="player_name" class="form-control" required>
</div>
<div class="col-12">
<button class="btn btn-dark">Войти и ожидать</button>
</div>
</form>
</div>
<?php endif; ?>
<div class="row g-4">
<div class="col-lg-4">
<div class="panel p-4 h-100">
<h2 class="h6 text-uppercase text-muted">Игроки в комнате</h2>
<ul id="player-list" class="list-unstyled small mb-4"></ul>
<div class="d-grid gap-2">
<?php if ($isHost && $room['status'] === 'waiting'): ?>
<button id="start-match" class="btn btn-dark">Запустить матч</button>
<?php endif; ?>
<?php if ($room['status'] === 'playing'): ?>
<a class="btn btn-dark" href="match.php?id=<?= (int) $roomId ?>">Перейти в матч</a>
<?php endif; ?>
<?php if ($room['status'] === 'finished'): ?>
<a class="btn btn-outline-dark" href="match.php?id=<?= (int) $roomId ?>">Смотреть итог</a>
<?php endif; ?>
<a class="btn btn-outline-dark" href="/">Вернуться в лобби</a>
</div>
</div>
</div>
<div class="col-lg-8">
<div class="panel p-4 h-100">
<h2 class="h6 text-uppercase text-muted">Ожидание старта</h2>
<p class="text-muted">Матч запустится после команды хоста. Статус обновляется автоматически.</p>
<div class="room-status-grid">
<div>
<div class="label">Подключено</div>
<div id="room-count" class="value">—</div>
</div>
<div>
<div class="label">Состояние</div>
<div id="room-state" class="value">—</div>
</div>
<div>
<div class="label">Победитель</div>
<div id="room-winner" class="value">—</div>
</div>
</div>
<div class="mt-4 small text-muted">
<strong>Подсказка:</strong> комната обновляется в realtime через pushstream, fallback — обычный polling.
</div>
</div>
</div>
</div>
</div>
</main>
<div class="toast-container position-fixed bottom-0 end-0 p-3">
<div id="room-toast" class="toast align-items-center text-bg-dark border-0" role="alert" aria-live="assertive" aria-atomic="true">
<div class="d-flex">
<div class="toast-body" id="room-toast-body">Обновление комнаты.</div>
<button type="button" class="btn-close btn-close-white me-2 m-auto" data-bs-dismiss="toast"></button>
</div>
</div>
</div>
<script>
window.ROOM_ID = <?= (int) $roomId ?>;
window.PLAYER_TOKEN = <?= $sessionPlayer ? json_encode($sessionPlayer['token']) : 'null' ?>;
</script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
<script src="assets/js/main.js?v=<?= time(); ?>"></script>
</body>
</html>