Symfony Controller не ведет себя одинаково при вызове с маршрута или из сокета - PullRequest
0 голосов
/ 26 марта 2019

Я создаю веб-сайт, где пользователи могут присоединяться к комнатам (играть в пошаговые настольные игры).Пользователь присоединяется к комнате через маршрут к действию контроллера (который использует метод рендеринга);и когда ход игрока сделан (или когда он присоединяется), информация о действиях игрока отправляется через сокет на сервер, который затем должен отправить обратно новое содержимое страницы каждому пользователю в комнате.

Итак, перед началом игры, когда новый игрок присоединяется, они отправляют первое сообщение на сервер сокетов, который сохранит соединение и отправит новый контент страницы другим игрокам.Когда интерфейсный пользователь получает сообщение (обновленная часть страницы), он помещает его на уже обработанную страницу.

Сокет на стороне сервера - это класс, который расширяет 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).Все это в одном классе.Единственная разница заключается в том, как он вызывается (через маршруты или вызов метода сервиса).

У вас есть идеи, что может вызвать это?Заранее спасибо, надеюсь, мой вопрос не слишком запутан.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...