2026-04-09 20:21:01 +02:00
|
|
|
<?php declare(strict_types=1);
|
2019-10-27 18:51:28 +01:00
|
|
|
/**
|
|
|
|
|
* This file is part of the SplendidBear Websites' projects.
|
|
|
|
|
*
|
|
|
|
|
* Copyright (c) 2019 @ www.splendidbear.org
|
|
|
|
|
*
|
|
|
|
|
* For the full copyright and license information, please view the LICENSE
|
|
|
|
|
* file that was distributed with this source code.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
namespace App\Util;
|
|
|
|
|
|
|
|
|
|
use App\Entity\Gamer;
|
|
|
|
|
use App\Entity\PlayedGame;
|
|
|
|
|
use App\Entity\Step;
|
2026-04-09 22:00:53 +02:00
|
|
|
use App\Entity\User;
|
2026-04-09 20:21:01 +02:00
|
|
|
use App\Interfaces\TopicManagerInterface;
|
2019-10-27 18:51:28 +01:00
|
|
|
use DateTime;
|
|
|
|
|
use Doctrine\ORM\EntityManagerInterface;
|
|
|
|
|
use Exception;
|
2026-04-09 22:00:53 +02:00
|
|
|
use RuntimeException;
|
|
|
|
|
use JsonException;
|
2019-10-27 18:51:28 +01:00
|
|
|
use Psr\Log\LoggerInterface;
|
2026-04-09 22:00:53 +02:00
|
|
|
use Symfony\Component\Mercure\HubInterface;
|
|
|
|
|
use Symfony\Component\Mercure\Update;
|
|
|
|
|
use Symfony\Component\Security\Core\User\UserInterface;
|
2019-10-27 18:51:28 +01:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Class TopicManager
|
|
|
|
|
*
|
2026-04-09 20:21:01 +02:00
|
|
|
* @package App\Util
|
|
|
|
|
* @author Lang <https://www.splendidbear.org>
|
|
|
|
|
* @category Class
|
|
|
|
|
* @license https://www.gnu.org/licenses/lgpl-3.0.en.html GNU Lesser General Public License
|
|
|
|
|
* @link www.splendidbear.org
|
|
|
|
|
* @since 2026. 04. 09.
|
2019-10-27 18:51:28 +01:00
|
|
|
*/
|
2026-04-09 22:00:53 +02:00
|
|
|
class TopicManager implements TopicManagerInterface
|
2019-10-27 18:51:28 +01:00
|
|
|
{
|
|
|
|
|
public function __construct(
|
2026-04-09 22:00:53 +02:00
|
|
|
private readonly HubInterface $hub,
|
|
|
|
|
private readonly EntityManagerInterface $entityManager,
|
|
|
|
|
private readonly LoggerInterface $logger
|
|
|
|
|
) {
|
2019-10-27 18:51:28 +01:00
|
|
|
}
|
|
|
|
|
|
2026-04-09 22:00:53 +02:00
|
|
|
public function subscribe(string $gameAssoc, string $userName, ?UserInterface $user): void
|
2019-10-27 18:51:28 +01:00
|
|
|
{
|
2026-04-09 22:00:53 +02:00
|
|
|
$playedGame = $this->getPlayedGame($gameAssoc);
|
|
|
|
|
if (null === $playedGame) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$users = $this->getUserCollection($playedGame);
|
|
|
|
|
$count = $this->getPlayerCount($users);
|
|
|
|
|
$isKnown = in_array($userName, array_filter(array_values($users)), true);
|
|
|
|
|
|
|
|
|
|
/** Reject a third player who is not a reconnecting player */
|
|
|
|
|
if ($count >= 2 && !$isKnown) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Save the player to the database on a fresh join */
|
|
|
|
|
if (!$isKnown && $count < 2) {
|
|
|
|
|
$users = $this->saveUserToDb($gameAssoc, $userName, $user, $count + 1);
|
|
|
|
|
$count = $this->getPlayerCount($users);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$topic = 'mineseeker/channel/' . $gameAssoc;
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
$this->hub->publish(new Update(
|
|
|
|
|
$topic,
|
|
|
|
|
json_encode([
|
|
|
|
|
'userTopicId' => $userName,
|
|
|
|
|
'channel' => $topic,
|
|
|
|
|
'user' => $userName,
|
|
|
|
|
'userCnt' => $count,
|
|
|
|
|
'users' => $users,
|
|
|
|
|
], JSON_THROW_ON_ERROR)
|
|
|
|
|
));
|
|
|
|
|
} catch (JsonException $e) {
|
|
|
|
|
throw new RuntimeException($e->getMessage());
|
2019-10-27 18:51:28 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-09 22:00:53 +02:00
|
|
|
public function unSubscribe(string $gameAssoc, string $userName): void
|
2019-10-27 18:51:28 +01:00
|
|
|
{
|
2026-04-09 22:00:53 +02:00
|
|
|
$topic = 'mineseeker/channel/' . $gameAssoc;
|
|
|
|
|
|
|
|
|
|
$this->hub->publish(new Update(
|
|
|
|
|
$topic,
|
|
|
|
|
json_encode(['msg' => $userName . ' has left ' . $topic])
|
|
|
|
|
));
|
2019-10-27 18:51:28 +01:00
|
|
|
}
|
|
|
|
|
|
2026-04-09 22:00:53 +02:00
|
|
|
public function publish(string $gameAssoc, string $userName, array $event): void
|
2019-10-27 18:51:28 +01:00
|
|
|
{
|
|
|
|
|
null === $event['resign']
|
2026-04-09 22:00:53 +02:00
|
|
|
? $this->saveStepToDb($gameAssoc, $event)
|
|
|
|
|
: $this->saveResignToDb($gameAssoc, $event['resign']);
|
|
|
|
|
|
|
|
|
|
$playedGame = $this->getPlayedGame($gameAssoc);
|
|
|
|
|
$users = $this->getUserCollection($playedGame);
|
|
|
|
|
$count = $this->getPlayerCount($users);
|
|
|
|
|
$topic = 'mineseeker/channel/' . $gameAssoc;
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
$this->hub->publish(new Update(
|
|
|
|
|
$topic,
|
|
|
|
|
json_encode([
|
|
|
|
|
'userTopicId' => $userName,
|
|
|
|
|
'channel' => $topic,
|
|
|
|
|
'user' => $userName,
|
|
|
|
|
'userCnt' => $count,
|
|
|
|
|
'data' => $event,
|
|
|
|
|
], JSON_THROW_ON_ERROR)
|
|
|
|
|
));
|
|
|
|
|
} catch (JsonException $e) {
|
|
|
|
|
throw new RuntimeException($e->getMessage());
|
|
|
|
|
}
|
2019-10-27 18:51:28 +01:00
|
|
|
}
|
|
|
|
|
|
2026-04-09 22:00:53 +02:00
|
|
|
private function getPlayedGame(string $gameAssoc): ?PlayedGame
|
2019-10-27 18:51:28 +01:00
|
|
|
{
|
2026-04-09 22:00:53 +02:00
|
|
|
return $this->entityManager
|
2019-10-27 18:51:28 +01:00
|
|
|
->getRepository(PlayedGame::class)
|
|
|
|
|
->findOneByGameAssoc($gameAssoc);
|
2026-04-09 22:00:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private function getPlayerCount(array $users): int
|
|
|
|
|
{
|
|
|
|
|
$red = '' !== $users['red'] || '' !== $users['redAnon'] ? 1 : 0;
|
|
|
|
|
$blue = '' !== $users['blue'] || '' !== $users['blueAnon'] ? 1 : 0;
|
|
|
|
|
|
|
|
|
|
return $red + $blue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private function saveResignToDb(string $gameAssoc, string $color): void
|
|
|
|
|
{
|
|
|
|
|
$playedGame = $this->getPlayedGame($gameAssoc);
|
2019-10-27 18:51:28 +01:00
|
|
|
|
|
|
|
|
$playedGame->setResign($color);
|
|
|
|
|
|
|
|
|
|
$this->entityManager->persist($playedGame);
|
|
|
|
|
$this->entityManager->flush();
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-09 22:00:53 +02:00
|
|
|
private function saveStepToDb(string $gameAssoc, array $event): void
|
2019-10-27 18:51:28 +01:00
|
|
|
{
|
|
|
|
|
try {
|
2026-04-09 22:00:53 +02:00
|
|
|
$playedGame = $this->getPlayedGame($gameAssoc);
|
2019-10-27 18:51:28 +01:00
|
|
|
|
|
|
|
|
$step = new Step();
|
|
|
|
|
$step->setRow($event['coords'][0]);
|
|
|
|
|
$step->setCol($event['coords'][1]);
|
|
|
|
|
$step->setWBomb($event['bomb']);
|
|
|
|
|
$step->setPlayedGame($playedGame);
|
|
|
|
|
$step->setCreated(new DateTime());
|
|
|
|
|
$this->entityManager->persist($step);
|
|
|
|
|
|
|
|
|
|
$playedGame->setBluePoints($event['bluePoints']);
|
|
|
|
|
$playedGame->setRedPoints($event['redPoints']);
|
|
|
|
|
$playedGame->setBlueExplodedBomb($event['blueExplodedBomb'] ? true : null);
|
|
|
|
|
$playedGame->setRedExplodedBomb($event['redExplodedBomb'] ? true : null);
|
|
|
|
|
$playedGame->setUpdated(new DateTime());
|
|
|
|
|
$this->entityManager->persist($playedGame);
|
|
|
|
|
|
|
|
|
|
$this->entityManager->flush();
|
|
|
|
|
} catch (Exception $e) {
|
|
|
|
|
$this->logger->error($e->getMessage());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-09 22:00:53 +02:00
|
|
|
private function saveUserToDb(string $gameAssoc, string $userName, ?UserInterface $user, int $count): array
|
2019-10-27 18:51:28 +01:00
|
|
|
{
|
2026-04-09 22:00:53 +02:00
|
|
|
$playedGame = $this->getPlayedGame($gameAssoc);
|
2019-10-27 18:51:28 +01:00
|
|
|
|
2026-04-09 22:00:53 +02:00
|
|
|
null !== $user
|
2019-10-27 18:51:28 +01:00
|
|
|
? $this->saveRegisteredUser($userName, $count, $playedGame)
|
|
|
|
|
: $this->saveAnonUser($userName, $count, $playedGame);
|
|
|
|
|
|
|
|
|
|
$this->entityManager->persist($playedGame);
|
|
|
|
|
$this->entityManager->flush();
|
|
|
|
|
|
|
|
|
|
return $this->getUserCollection($playedGame);
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-09 22:00:53 +02:00
|
|
|
private function saveRegisteredUser(string $userName, int $count, PlayedGame $playedGame): void
|
2019-10-27 18:51:28 +01:00
|
|
|
{
|
2026-04-09 22:00:53 +02:00
|
|
|
/** @var User $user */
|
2019-10-27 18:51:28 +01:00
|
|
|
$user = $this->entityManager
|
|
|
|
|
->getRepository(User::class)
|
|
|
|
|
->findOneByUsername($userName);
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
if ($count === 1) {
|
|
|
|
|
$random = random_int(0, 1);
|
|
|
|
|
!$random ? $playedGame->setRed($user) : $playedGame->setBlue($user);
|
|
|
|
|
} else {
|
|
|
|
|
null === $playedGame->getRed() && null === $playedGame->getRedAnon()
|
|
|
|
|
? $playedGame->setRed($user)
|
|
|
|
|
: $playedGame->setBlue($user);
|
|
|
|
|
}
|
|
|
|
|
} catch (Exception $e) {
|
|
|
|
|
$this->logger->error($e->getMessage());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-09 22:00:53 +02:00
|
|
|
private function saveAnonUser(string $userName, int $count, PlayedGame $playedGame): void
|
2019-10-27 18:51:28 +01:00
|
|
|
{
|
|
|
|
|
try {
|
|
|
|
|
$anon = new Gamer();
|
|
|
|
|
$anon->setUsername($userName);
|
|
|
|
|
$anon->setConnTimestamp(new DateTime());
|
|
|
|
|
$this->entityManager->persist($anon);
|
|
|
|
|
|
|
|
|
|
if ($count === 1) {
|
|
|
|
|
$random = random_int(0, 1);
|
|
|
|
|
!$random ? $playedGame->setRedAnon($anon) : $playedGame->setBlueAnon($anon);
|
|
|
|
|
} else {
|
|
|
|
|
null === $playedGame->getRed() && null === $playedGame->getRedAnon()
|
|
|
|
|
? $playedGame->setRedAnon($anon)
|
|
|
|
|
: $playedGame->setBlueAnon($anon);
|
|
|
|
|
}
|
|
|
|
|
} catch (Exception $e) {
|
|
|
|
|
$this->logger->error($e->getMessage());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private function getUserCollection(PlayedGame $playedGame): array
|
|
|
|
|
{
|
2026-04-09 20:21:01 +02:00
|
|
|
return [
|
2026-04-09 22:00:53 +02:00
|
|
|
'red' => null !== $playedGame->getRed() ? $playedGame->getRed()->getUsername() : '',
|
|
|
|
|
'blue' => null !== $playedGame->getBlue() ? $playedGame->getBlue()->getUsername() : '',
|
|
|
|
|
'redAnon' => null !== $playedGame->getRedAnon() ? $playedGame->getRedAnon()->getUserName() : '',
|
|
|
|
|
'blueAnon' => null !== $playedGame->getBlueAnon() ? $playedGame->getBlueAnon()->getUserName() : '',
|
2026-04-09 20:21:01 +02:00
|
|
|
];
|
2019-10-27 18:51:28 +01:00
|
|
|
}
|
|
|
|
|
}
|