implement player stats

This commit is contained in:
ghost 2024-01-07 18:14:09 +02:00
parent fc950b0df3
commit cdc15d7e7c
5 changed files with 290 additions and 11 deletions

View File

@ -16,7 +16,7 @@ Web Monitor for Half-Life based on [HLServers](https://github.com/YGGverse/HLSer
* `chown -R www-data:www-data var` * `chown -R www-data:www-data var`
* `cp .env .env.local` * `cp .env .env.local`
* `crontab -e` > `* * * * * /usr/bin/curl --silent http://localhost/crontab/online &> /dev/null` * `crontab -e` > `* * * * * /usr/bin/curl --silent http://localhost/crontab/index &> /dev/null`
## Update ## Update

View File

@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20240107151414 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('CREATE TABLE player (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, crc32server BIGINT NOT NULL, crc32name BIGINT NOT NULL, joined BIGINT NOT NULL, updated BIGINT NOT NULL, online BIGINT NOT NULL, frags BIGINT NOT NULL, name VARCHAR(255) NOT NULL)');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('DROP TABLE player');
}
}

View File

@ -10,19 +10,20 @@ use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use App\Entity\Online; use App\Entity\Online;
use App\Entity\Player;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
class CrontabController extends AbstractController class CrontabController extends AbstractController
{ {
#[Route( #[Route(
'/crontab/online', '/crontab/index',
name: 'crontab_online', name: 'crontab_index',
methods: methods:
[ [
'GET' 'GET'
] ]
)] )]
public function online( public function index(
?Request $request, ?Request $request,
EntityManagerInterface $entityManagerInterface EntityManagerInterface $entityManagerInterface
): Response ): Response
@ -62,14 +63,14 @@ class CrontabController extends AbstractController
$total = $players + $bots; $total = $players + $bots;
// Generate CRC32 server ID // Generate CRC32 server ID
$crc32Server = crc32( $crc32server = crc32(
$hlserver->host . ':' . $hlserver->port $hlserver->host . ':' . $hlserver->port
); );
// Get last online value // Get last online value
$online = $entityManagerInterface->getRepository(Online::class)->findOneBy( $online = $entityManagerInterface->getRepository(Online::class)->findOneBy(
[ [
'crc32server' => $crc32Server 'crc32server' => $crc32server
], ],
[ [
'id' => 'DESC' // same as online.time but faster 'id' => 'DESC' // same as online.time but faster
@ -82,16 +83,16 @@ class CrontabController extends AbstractController
is_null($online) is_null($online)
|| ||
$players !== $online->getPlayers() $players !== $online->getPlayers()
|| // ||
$bots !== $online->getBots() // $bots !== $online->getBots()
|| // ||
$total !== $online->getTotal() // $total !== $online->getTotal()
) )
{ {
$online = new Online(); $online = new Online();
$online->setCrc32server( $online->setCrc32server(
$crc32Server $crc32server
); );
$online->setTime( $online->setTime(
@ -116,6 +117,104 @@ class CrontabController extends AbstractController
$entityManagerInterface->flush(); $entityManagerInterface->flush();
} }
// Update player stats
if ($players)
{
foreach ((array) $server->GetPlayers() as $session)
{
// Validate fields
if
(
!isset($session['Name']) || mb_strlen($session['Name']) > 255
||
!isset($session['TimeF']) || (int) $session['TimeF'] < 0
||
!isset($session['Frags']) || (int) $session['Frags'] < 0
)
{
continue;
}
// Skip bots
if ($session['TimeF'] == '59:59')
{
continue;
}
// Generate CRC32 server ID
$crc32name = crc32(
$session['Name']
);
$player = $entityManagerInterface->getRepository(Player::class)->findOneBy(
[
'crc32server' => $crc32server,
'crc32name' => $crc32name,
]
);
// Player exists
if ($player)
{
$player->setUpdated(
time()
);
$player->setOnline(
time()
);
if ((int) $session['Frags'] > $player->getFrags())
{
$player->setFrags(
(int) $session['Frags']
);
}
}
// Create new player
else
{
$player = new Player();
$player->setCrc32server(
$crc32server
);
$player->setCrc32name(
$crc32name
);
$player->setJoined(
time()
);
$player->setUpdated(
time()
);
$player->setOnline(
time()
);
$player->setName(
(string) $session['Name']
);
$player->setFrags(
(int) $session['Frags']
);
}
// Update DB
$entityManagerInterface->persist(
$player
);
$entityManagerInterface->flush();
}
}
} }
} }
} }

126
src/Entity/Player.php Normal file
View File

@ -0,0 +1,126 @@
<?php
namespace App\Entity;
use App\Repository\PlayerRepository;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity(repositoryClass: PlayerRepository::class)]
class Player
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
private ?int $id = null;
#[ORM\Column(type: Types::BIGINT)]
private ?string $crc32server = null;
#[ORM\Column(type: Types::BIGINT)]
private ?string $crc32name = null;
#[ORM\Column(type: Types::BIGINT)]
private ?string $joined = null;
#[ORM\Column(type: Types::BIGINT)]
private ?string $updated = null;
#[ORM\Column(type: Types::BIGINT)]
private ?string $online = null;
#[ORM\Column(type: Types::BIGINT)]
private ?string $frags = null;
#[ORM\Column(length: 255)]
private ?string $name = null;
public function getId(): ?int
{
return $this->id;
}
public function getCrc32server(): ?string
{
return $this->crc32server;
}
public function setCrc32server(string $crc32server): static
{
$this->crc32server = $crc32server;
return $this;
}
public function getCrc32name(): ?string
{
return $this->crc32name;
}
public function setCrc32name(string $crc32name): static
{
$this->crc32name = $crc32name;
return $this;
}
public function getJoined(): ?string
{
return $this->joined;
}
public function setJoined(string $joined): static
{
$this->joined = $joined;
return $this;
}
public function getUpdated(): ?string
{
return $this->updated;
}
public function setUpdated(string $updated): static
{
$this->updated = $updated;
return $this;
}
public function getOnline(): ?string
{
return $this->online;
}
public function setOnline(string $online): static
{
$this->online = $online;
return $this;
}
public function getFrags(): ?string
{
return $this->frags;
}
public function setFrags(string $frags): static
{
$this->frags = $frags;
return $this;
}
public function getName(): ?string
{
return $this->name;
}
public function setName(string $name): static
{
$this->name = $name;
return $this;
}
}

View File

@ -0,0 +1,23 @@
<?php
namespace App\Repository;
use App\Entity\Player;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @extends ServiceEntityRepository<Player>
*
* @method Player|null find($id, $lockMode = null, $lockVersion = null)
* @method Player|null findOneBy(array $criteria, array $orderBy = null)
* @method Player[] findAll()
* @method Player[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
*/
class PlayerRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, Player::class);
}
}