Я создаю веб-сайт, где пользователи могут присоединяться к комнатам (играть в пошаговые настольные игры).Пользователь присоединяется к комнате через маршрут к действию контроллера (который использует метод рендеринга);и когда ход игрока сделан (или когда он присоединяется), информация о действиях игрока отправляется через сокет на сервер, который затем должен отправить обратно новое содержимое страницы каждому пользователю в комнате.
Итак, перед началом игры, когда новый игрок присоединяется, они отправляют первое сообщение на сервер сокетов, который сохранит соединение и отправит новый контент страницы другим игрокам.Когда интерфейсный пользователь получает сообщение (обновленная часть страницы), он помещает его на уже обработанную страницу.
Сокет на стороне сервера - это класс, который расширяет Ratchet \ MessageComponentInterface .В сообщении он вызывает метод handleAction GameController с декодированными аргументами.GameController доступен как сервис.
Вот урезанная версия Socket:
namespace AGORA\Game\AugustusBundle\Controller;
use AGORA\Game\AugustusBundle\Controller\GameController;
use Ratchet\ConnectionInterface;
use Ratchet\MessageComponentInterface;
use SplObjectStorage;
use Symfony\Component\DependencyInjection\Container;
class AugustusSocket implements MessageComponentInterface {
/**
* @var $games Map<String, Game>
*/
private $games;
private $container;
private $controller;
public function __construct(Container $container) {
$this->container = $container;
// this service is the GameController
$this->controller = $this->container->get('agora_game.augustusController');
$this->controller->setContainer($container);
}
function onMessage(ConnectionInterface $from, $msg) {
$content = json_decode($msg);
$this->controller->handleAction($from, $content->gameId, $content->playerId, $content->action);
}
}
А вот один из GameController:
namespace AGORA\Game\AugustusBundle\Controller;
use AGORA\Game\AugustusBundle\Service\AugustusService;
use AGORA\Game\AugustusBundle\Entity\AugustusGame;
use AGORA\Game\Socket\ConnectionStorage;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use FOS\UserBundle\Model\UserInterface;
class GameController extends Controller {
protected $connectionStorage;
function __construct() {
$this->connectionStorage = new ConnectionStorage();
}
public function indexAction($gameId) {
$user = $this->getUser();
//this service handles the logic of the game
$service = $this->container->get('agora_game.augustus');
$game = $service->getGame($gameId);
$player = $service->getPlayerFromUser($user, $gameId)
return $this->render('AugustusBundle:Default:game.html.twig',
array(
'game' => $game,
'board' => $game->getBoard(),
'me' => $player
)
);
}
public function renderBody($gameId, $playerId) {
$service = $this->container->get('agora_game.augustus');
$game = $service->getGame($gameId);
$player = $service->getPlayerFromId($playerId, $gameId);
return $this->render('AugustusBundle:Default:gameBody.html.twig',
array(
'game' => $game,
'board' => $game->getBoard(),
'me' => $player,
)
);
}
public function handleAction($conn, $gameId, $playerId, $action) {
$service = $this->container->get('agora_game.augustus');
if ($action->type == "connect") {
$this->connectionStorage->addConnection($gameId, $playerId, $conn);
foreach ($service->getPlayers($gameId) as $player) {
$c = $this->connectionStorage->getConnection($gameId, $player->getId());
$id = $player->getId();
//$c->send($this->renderBody($gameId, $player->getId()));
}
return;
}
// other cases of updates (each turn)...
}
Соединениеработает хорошо, но моя проблема здесь в том, что часть «сокета» GameController не имеет нужной информации об игре.Например, если player1 создает комнату для 2 (по маршруту), игра отображается в хорошем состоянии «ожидание игрока 2», тогда сервер сокетов видит, что player1 присоединился к игре, поэтому отправляет каждому обновленному игрокучасть страницы (которая не изменится в этом случае).Затем, когда игрок 2 присоединяется (через маршрут), игра запускается, и страница отображается соответствующим образом, но затем сервер сокетов видит, что игрок2 присоединился, и отправляет игроку 1 (только) страницу в том же состоянии ожидания, что ираньше.
Это потому, что каждая информация, которую он «думает», что в комнате все еще есть один игрок и что игра еще не началась.Но когда к той же информации обращаются непосредственно через URL, информация отображается так, как и должна.Информация об игре извлекается из базы данных точным набором методов в сервисе, который обрабатывает логику.Но в одном случае (маршруты URL) это правильная информация (игра началась), а в другом случае (handleAction вызывается сокетом) это информация о прошлом (комната ждет игрока 2).Все это в одном классе.Единственная разница заключается в том, как он вызывается (через маршруты или вызов метода сервиса).
У вас есть идеи, что может вызвать это?Заранее спасибо, надеюсь, мой вопрос не слишком запутан.