hanli/src/Core/GameSession.php
hant 7308af1c1b Fix web state management: handleInput now returns structured data
Issues fixed:
- GameSession.handleInput() was returning plain text, causing WebSocket frontend
  to lose state information after each input
- GameWebSocketServer.handleGameInput() was calling unnecessary getStateInfo()
- Duplicate state saves in runCurrentState() and handleInput()

Changes:
1. GameSession.php:
   - handleInput() now returns structured array with output + state info
   - runCurrentState() no longer saves state (already done in handleInput)
   - Consistent return format: { output, state, stateName, playerInfo }

2. GameWebSocketServer.php:
   - handleGameInput() simplified to use handleInput() return value
   - Direct merge of result into WebSocket message

3. web/server.php:
   - handleGameInput() simplified to just return handleInput() result
   - No duplicate getStateInfo() call

Results:
- Web frontend now receives complete state info after each input
- State transitions in submenus now work correctly
- No more state desynchronization between client and server

Testing:
- Input in level 3+ menus now executes correctly
- State name updates properly in header
- Player info (HP, etc) stays synchronized

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-07 13:14:48 +08:00

199 lines
5.3 KiB
PHP
Raw 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
namespace Game\Core;
/**
* Web 游戏会话 - 使用完整的 Game 逻辑
*/
class GameSession
{
private Game $game;
private WebOutput $output;
private string $userId;
public function __construct(string $userId)
{
$this->userId = $userId;
$this->output = new WebOutput();
// 设置 Web 输入模式
$webInput = WebInput::getInstance();
$webInput->setWebMode(true);
// 创建 Game 实例,使用 WebOutput 和用户 ID
$this->game = new Game(null, $this->output, $userId);
}
/**
* 渲染当前界面(不需要输入)
*/
public function render(): string
{
$this->output->clear();
try {
$this->runCurrentState();
} catch (NeedInputException $e) {
// 正常情况,界面渲染完成,等待输入
}
return $this->output->getOutput();
}
/**
* 处理用户输入并返回新界面(支持时间戳数据)
*/
public function handleInput(string $input): string|array
{
$this->output->clear();
// 将输入推入队列
$webInput = WebInput::getInstance();
$webInput->clear();
$webInput->push($input);
try {
$this->runCurrentState();
} catch (NeedInputException $e) {
// 需要更多输入,返回当前输出
}
// 保存状态
$this->game->saveState();
// 获取当前状态信息
$stateInfo = $this->getStateInfo();
$output = $this->output->getOutput();
// 返回包含状态信息的结构化数据
return [
'output' => $output,
'state' => $stateInfo['state'],
'stateName' => $stateInfo['stateName'],
'playerInfo' => $stateInfo['playerInfo'],
];
}
/**
* SSE 流式战斗模式
* 当用户进入战斗时使用SSE直接推送日志
*/
public function streamBattle(string $input): void
{
// 使用SSEOutput替换普通输出
$sseOutput = new \Game\Core\SSEOutput();
// 替换game的output对象
$this->game->output = $sseOutput;
// 将输入推入队列
$webInput = WebInput::getInstance();
$webInput->clear();
$webInput->push($input);
try {
$this->runCurrentState();
} catch (NeedInputException $e) {
// 战斗中可能需要更多输入
}
// 保存状态
$this->game->saveState();
// 发送完成信号
$sseOutput->complete();
}
/**
* 执行当前状态的逻辑
*/
private function runCurrentState(): void
{
if ($this->game->state == 0){
$this->game->state = 1;
}
switch ($this->game->state) {
case Game::MENU:
(new \Game\Modules\Menu($this->game))->show();
break;
case Game::DUNGEON_SELECT:
(new \Game\Modules\DungeonSelectPanel($this->game))->show();
break;
case Game::BATTLE:
(new \Game\Modules\Battle($this->game))->start();
break;
case Game::STATS:
(new \Game\Modules\StatsPanel($this->game))->show();
break;
case Game::INVENTORY:
(new \Game\Modules\InventoryPanel($this->game))->show();
break;
case Game::EQUIPMENT_ENHANCE:
(new \Game\Modules\EquipmentEnhancePanel($this->game))->show();
break;
case Game::NPC:
(new \Game\Modules\NpcPanel($this->game))->show();
break;
case Game::TALENT:
(new \Game\Modules\TalentPanel($this->game))->show();
break;
}
}
/**
* 获取当前游戏状态
*/
public function getState(): int
{
return $this->game->state;
}
/**
* 获取玩家信息
*/
public function getPlayerInfo(): array
{
$stats = $this->game->player->getStats();
return [
'level' => $this->game->player->level,
'hp' => $this->game->player->hp,
'maxHp' => $stats['maxHp'],
'mana' => $this->game->player->mana,
'maxMana' => $stats['maxMana'],
'spiritStones' => $this->game->player->spiritStones,
'exp' => $this->game->player->exp,
'maxExp' => $this->game->player->maxExp,
];
}
/**
* 获取当前游戏状态信息
*/
public function getStateInfo(): array
{
return [
'state' => $this->game->state,
'stateName' => $this->getStateName(),
'playerInfo' => $this->getPlayerInfo(),
];
}
/**
* 将状态常量转换为名称
*/
private function getStateName(): string
{
return match($this->game->state) {
Game::MENU => 'MENU',
Game::DUNGEON_SELECT => 'DUNGEON_SELECT',
Game::BATTLE => 'BATTLE',
Game::STATS => 'STATS',
Game::INVENTORY => 'INVENTORY',
Game::EQUIPMENT_ENHANCE => 'EQUIPMENT_ENHANCE',
Game::NPC => 'NPC',
Game::TALENT => 'TALENT',
Game::EXIT => 'EXIT',
default => 'UNKNOWN'
};
}
}