243 lines
6.1 KiB
PHP
243 lines
6.1 KiB
PHP
<?php
|
||
/**
|
||
* Web 游戏服务器入口
|
||
* 使用方法: php -S 0.0.0.0:8080 web/server.php
|
||
*/
|
||
|
||
// 设置错误报告
|
||
error_reporting(E_ALL);
|
||
ini_set('display_errors', 0);
|
||
|
||
// 自动加载
|
||
require_once __DIR__ . '/../vendor/autoload.php';
|
||
|
||
use Game\Core\UserManager;
|
||
use Game\Core\GameSession;
|
||
use Game\Core\WebInput;
|
||
|
||
// 设置 Web 模式
|
||
WebInput::getInstance()->setWebMode(true);
|
||
|
||
// 启动会话
|
||
session_start();
|
||
|
||
// 设置响应头
|
||
header('Content-Type: application/json; charset=utf-8');
|
||
header('Access-Control-Allow-Origin: *');
|
||
header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
|
||
header('Access-Control-Allow-Headers: Content-Type');
|
||
|
||
// 处理 OPTIONS 预检请求
|
||
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
|
||
http_response_code(200);
|
||
exit;
|
||
}
|
||
|
||
// 获取请求路径
|
||
$requestUri = $_SERVER['REQUEST_URI'];
|
||
$path = parse_url($requestUri, PHP_URL_PATH);
|
||
|
||
// 静态文件处理
|
||
if ($path === '/' || $path === '/process.html') {
|
||
header('Content-Type: text/html; charset=utf-8');
|
||
readfile(__DIR__ . '/process.html');
|
||
exit;
|
||
}
|
||
|
||
// API 路由
|
||
$response = ['success' => false, 'message' => '未知请求'];
|
||
|
||
try {
|
||
switch ($path) {
|
||
case '/api/register':
|
||
$response = handleRegister();
|
||
break;
|
||
|
||
case '/api/login':
|
||
$response = handleLogin();
|
||
break;
|
||
|
||
case '/api/logout':
|
||
$response = handleLogout();
|
||
break;
|
||
|
||
case '/api/status':
|
||
$response = handleStatus();
|
||
break;
|
||
|
||
case '/api/game/render':
|
||
$response = handleGameRender();
|
||
break;
|
||
|
||
case '/api/game/input':
|
||
$response = handleGameInput();
|
||
break;
|
||
|
||
case '/api/game/battle-stream':
|
||
// SSE 实时战斗流
|
||
handleBattleStream();
|
||
exit;
|
||
break;
|
||
|
||
default:
|
||
// 检查是否是静态文件
|
||
$filePath = __DIR__ . $path;
|
||
if (file_exists($filePath) && is_file($filePath)) {
|
||
$ext = pathinfo($path, PATHINFO_EXTENSION);
|
||
$mimeTypes = [
|
||
'js' => 'application/javascript',
|
||
'css' => 'text/css',
|
||
'html' => 'text/html',
|
||
'png' => 'image/png',
|
||
'jpg' => 'image/jpeg',
|
||
'gif' => 'image/gif',
|
||
];
|
||
header('Content-Type: ' . ($mimeTypes[$ext] ?? 'application/octet-stream'));
|
||
readfile($filePath);
|
||
exit;
|
||
}
|
||
http_response_code(404);
|
||
$response = ['success' => false, 'message' => '未找到'];
|
||
}
|
||
} catch (Exception $e) {
|
||
http_response_code(500);
|
||
$response = ['success' => false, 'message' => '服务器错误: ' . $e->getMessage()];
|
||
}
|
||
|
||
echo json_encode($response, JSON_UNESCAPED_UNICODE);
|
||
|
||
// ============ 处理函数 ============
|
||
|
||
function getInput(): array
|
||
{
|
||
$input = file_get_contents('php://input');
|
||
return json_decode($input, true) ?? [];
|
||
}
|
||
|
||
function handleRegister(): array
|
||
{
|
||
$data = getInput();
|
||
$username = $data['username'] ?? '';
|
||
$password = $data['password'] ?? '';
|
||
|
||
$userManager = new UserManager();
|
||
$result = $userManager->register($username, $password);
|
||
|
||
if ($result['success']) {
|
||
$_SESSION['user_id'] = $result['userId'];
|
||
$_SESSION['username'] = $username;
|
||
}
|
||
|
||
return $result;
|
||
}
|
||
|
||
function handleLogin(): array
|
||
{
|
||
$data = getInput();
|
||
$username = $data['username'] ?? '';
|
||
$password = $data['password'] ?? '';
|
||
|
||
$userManager = new UserManager();
|
||
$result = $userManager->login($username, $password);
|
||
|
||
if ($result['success']) {
|
||
$_SESSION['user_id'] = $result['userId'];
|
||
$_SESSION['username'] = $username;
|
||
}
|
||
|
||
return $result;
|
||
}
|
||
|
||
function handleLogout(): array
|
||
{
|
||
session_destroy();
|
||
return ['success' => true, 'message' => '已退出登录'];
|
||
}
|
||
|
||
function handleStatus(): array
|
||
{
|
||
if (empty($_SESSION['user_id'])) {
|
||
return ['success' => false, 'loggedIn' => false, 'message' => '未登录'];
|
||
}
|
||
|
||
return [
|
||
'success' => true,
|
||
'loggedIn' => true,
|
||
'userId' => $_SESSION['user_id'],
|
||
'username' => $_SESSION['username'] ?? '未知',
|
||
];
|
||
}
|
||
|
||
function handleGameRender(): array
|
||
{
|
||
if (empty($_SESSION['user_id'])) {
|
||
return ['success' => false, 'message' => '请先登录'];
|
||
}
|
||
|
||
$session = new GameSession($_SESSION['user_id']);
|
||
$output = $session->render();
|
||
$stateInfo = $session->getStateInfo();
|
||
|
||
return [
|
||
'success' => true,
|
||
'output' => $output,
|
||
'state' => $stateInfo['state'],
|
||
'stateName' => $stateInfo['stateName'],
|
||
'playerInfo' => $stateInfo['playerInfo'],
|
||
];
|
||
}
|
||
|
||
function handleGameInput(): array
|
||
{
|
||
if (empty($_SESSION['user_id'])) {
|
||
return ['success' => false, 'message' => '请先登录'];
|
||
}
|
||
|
||
$data = getInput();
|
||
$input = $data['input'] ?? '';
|
||
|
||
$session = new GameSession($_SESSION['user_id']);
|
||
$result = $session->handleInput($input);
|
||
|
||
// 现在handleInput返回的是数组:output, state, stateName, playerInfo
|
||
return array_merge(['success' => true], $result);
|
||
}
|
||
|
||
/**
|
||
* 处理 SSE 实时战斗流
|
||
*/
|
||
function handleBattleStream(): void
|
||
{
|
||
if (empty($_SESSION['user_id'])) {
|
||
http_response_code(401);
|
||
echo "data: " . json_encode(['error' => '请先登录']) . "\n\n";
|
||
return;
|
||
}
|
||
|
||
// 从URL参数或POST数据获取输入
|
||
$input = $_GET['input'] ?? $_POST['input'] ?? '';
|
||
|
||
// 设置 SSE 响应头
|
||
header('Content-Type: text/event-stream');
|
||
header('Cache-Control: no-cache');
|
||
header('Connection: keep-alive');
|
||
header('X-Accel-Buffering: no'); // 禁用代理缓冲
|
||
|
||
// 发送初始化消息
|
||
echo "event: start\n";
|
||
echo "data: " . json_encode(['message' => '战斗开始']) . "\n\n";
|
||
ob_flush();
|
||
flush();
|
||
|
||
// 创建游戏会话并流式处理战斗
|
||
try {
|
||
$session = new GameSession($_SESSION['user_id']);
|
||
$session->streamBattle($input);
|
||
} catch (Exception $e) {
|
||
echo "event: error\n";
|
||
echo "data: " . json_encode(['message' => $e->getMessage()]) . "\n\n";
|
||
ob_flush();
|
||
flush();
|
||
}
|
||
}
|