Adds a Dictionary type for safer array creation in a similar fashion as C#

main
Tiger 2024-02-24 00:46:20 +01:00
parent 792c3939ab
commit 6dd2118267
5 changed files with 86 additions and 16 deletions

View File

@ -7,27 +7,29 @@ use Emulator\Messages\Incoming\ClientMessage;
use Emulator\Messages\Incoming\Handshake\ReleaseVersionMessageEvent;
use Emulator\Messages\Incoming\Handshake\SecurityTicketMessageEvent;
use Emulator\Messages\Incoming\Header;
use Emulator\Messages\Incoming\IMessageEvent;
use Emulator\Network\Game\Sessions\Session;
use Emulator\Utilities\Dictionary;
use SplObjectStorage;
class MessageHandler {
private SplObjectStorage $handlers;
private Dictionary $handlers;
public function __construct() {
$this->handlers = new SplObjectStorage();
$this->handlers = new Dictionary(IMessageEvent::class);
}
public function initialize(): void {
$this->handlers[Header::ReleaseVersion] = new ReleaseVersionMessageEvent();
$this->handlers[Header::SecurityTicket] = new SecurityTicketMessageEvent();
$this->handlers->add(Header::ReleaseVersion, new ReleaseVersionMessageEvent());
$this->handlers->add(Header::SecurityTicket, new SecurityTicketMessageEvent());
Logger::info("Loaded " . count($this->handlers) . " message handlers");
Logger::info("Loaded {$this->handlers->count()} message handlers");
}
public function handlePacket(Session $session, ClientMessage $request): void {
if (($header = Header::tryFrom($request->getHeader()))) {
if ($this->handlers->contains($header)) {
$this->handlers[$header]->handle($session, $request);
if ($this->handlers->containsKey($header->value)) {
$this->handlers->get($header)->handle($session, $request);
} else {
Logger::warn("[{$request->getHeader()}] [$header->name] - Unregistered!");
}

View File

@ -7,9 +7,7 @@ use Emulator\Messages\Outgoing\IMessageComposer;
use Emulator\Messages\Outgoing\ServerMessage;
use Override;
class AuthenticatedComposer implements IMessageComposer
{
class AuthenticatedComposer implements IMessageComposer {
#[Override] function compose(ServerMessage $message): void {
}

View File

@ -7,14 +7,15 @@ use Emulator\Encoding\ByteEncoding;
use Emulator\Messages\Incoming\ClientMessage;
use Emulator\Messages\MessageHandler;
use Emulator\Network\Game\Sessions\Session;
use Emulator\Utilities\Dictionary;
use OpenSwoole\WebSocket\Server;
use OpenSwoole\Http\Request;
use OpenSwoole\WebSocket\Frame;
class GameNetworkServer {
private array $sessions;
private Dictionary $sessions;
public function __construct(private readonly MessageHandler $messageHandler) {
$this->sessions = [];
$this->sessions = new Dictionary(Session::class);
}
public function start(int $port): void {
@ -32,17 +33,17 @@ class GameNetworkServer {
}
function onOpen(Server $server, Request $request): void {
$this->sessions[$request->fd] = new Session($server, $request);
$this->sessions->add($request->fd, new Session($server, $request));
}
function onClose(Server $server, int $fd): void {
Logger::info("Connection #$fd has been closed");
unset($this->sessions[$fd]);
$this->sessions->remove($fd);
}
function onDisconnect(Server $server, int $fd): void {
Logger::info("Connection #$fd has disconnected");
unset($this->sessions[$fd]);
$this->sessions->remove($fd);
}
function onMessage(Server $server, Frame $frame): void {
@ -52,7 +53,7 @@ class GameNetworkServer {
$length = ByteEncoding::getInt32(array_slice($data, 1, 4));
$packet = array_slice($data, 4, $length);
$this->messageHandler->handlePacket($this->sessions[$frame->fd], new ClientMessage($packet));
$this->messageHandler->handlePacket($this->sessions->get($frame->fd), new ClientMessage($packet));
}
}
}

View File

@ -0,0 +1,60 @@
<?php
namespace Emulator\Utilities;
use InvalidArgumentException;
class Dictionary {
private array $arr;
public function __construct(private readonly string $valueType) {
$this->arr = [];
}
public function add(mixed $key, mixed $value): void {
if (!is_int($key) && !is_string($key) && !TypeChecker::isEnum($key)) {
throw new InvalidArgumentException('Key must be an integer, string or an enum');
}
if (!$value instanceof $this->valueType) {
throw new InvalidArgumentException("Value must be an instance of {$this->valueType}");
}
if (TypeChecker::isEnum($key)) {
$key = $key->value;
}
if (array_key_exists($key, $this->arr)) {
throw new InvalidArgumentException("Key $key already exists");
}
$this->arr[$key] = $value;
}
public function get($key): mixed {
if (TypeChecker::isEnum($key)) {
$key = $key->value;
}
return $this->arr[$key] ?? null;
}
public function containsKey($key): bool {
if (TypeChecker::isEnum($key)) {
$key = $key->value;
}
return array_key_exists($key, $this->arr);
}
public function count(): int {
return count($this->arr);
}
public function remove($key): void {
if (TypeChecker::isEnum($key)) {
$key = $key->value;
}
unset($this->arr[$key]);
}
}

View File

@ -0,0 +1,9 @@
<?php
namespace Emulator\Utilities;
class TypeChecker {
public static function isEnum($var): bool {
return is_object($var) && enum_exists(get_class($var));
}
}