Adds a Dictionary type for safer array creation in a similar fashion as C#
							parent
							
								
									792c3939ab
								
							
						
					
					
						commit
						6dd2118267
					
				| 
						 | 
					@ -7,27 +7,29 @@ use Emulator\Messages\Incoming\ClientMessage;
 | 
				
			||||||
use Emulator\Messages\Incoming\Handshake\ReleaseVersionMessageEvent;
 | 
					use Emulator\Messages\Incoming\Handshake\ReleaseVersionMessageEvent;
 | 
				
			||||||
use Emulator\Messages\Incoming\Handshake\SecurityTicketMessageEvent;
 | 
					use Emulator\Messages\Incoming\Handshake\SecurityTicketMessageEvent;
 | 
				
			||||||
use Emulator\Messages\Incoming\Header;
 | 
					use Emulator\Messages\Incoming\Header;
 | 
				
			||||||
 | 
					use Emulator\Messages\Incoming\IMessageEvent;
 | 
				
			||||||
use Emulator\Network\Game\Sessions\Session;
 | 
					use Emulator\Network\Game\Sessions\Session;
 | 
				
			||||||
 | 
					use Emulator\Utilities\Dictionary;
 | 
				
			||||||
use SplObjectStorage;
 | 
					use SplObjectStorage;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class MessageHandler {
 | 
					class MessageHandler {
 | 
				
			||||||
    private SplObjectStorage $handlers;
 | 
					    private Dictionary $handlers;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function __construct() {
 | 
					    public function __construct() {
 | 
				
			||||||
        $this->handlers = new SplObjectStorage();
 | 
					        $this->handlers = new Dictionary(IMessageEvent::class);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function initialize(): void {
 | 
					    public function initialize(): void {
 | 
				
			||||||
        $this->handlers[Header::ReleaseVersion] = new ReleaseVersionMessageEvent();
 | 
					        $this->handlers->add(Header::ReleaseVersion, new ReleaseVersionMessageEvent());
 | 
				
			||||||
        $this->handlers[Header::SecurityTicket] = new SecurityTicketMessageEvent();
 | 
					        $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 {
 | 
					    public function handlePacket(Session $session, ClientMessage $request): void {
 | 
				
			||||||
        if (($header = Header::tryFrom($request->getHeader()))) {
 | 
					        if (($header = Header::tryFrom($request->getHeader()))) {
 | 
				
			||||||
            if ($this->handlers->contains($header)) {
 | 
					            if ($this->handlers->containsKey($header->value)) {
 | 
				
			||||||
                $this->handlers[$header]->handle($session, $request);
 | 
					                $this->handlers->get($header)->handle($session, $request);
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                Logger::warn("[{$request->getHeader()}] [$header->name] - Unregistered!");
 | 
					                Logger::warn("[{$request->getHeader()}] [$header->name] - Unregistered!");
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,9 +7,7 @@ use Emulator\Messages\Outgoing\IMessageComposer;
 | 
				
			||||||
use Emulator\Messages\Outgoing\ServerMessage;
 | 
					use Emulator\Messages\Outgoing\ServerMessage;
 | 
				
			||||||
use Override;
 | 
					use Override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class AuthenticatedComposer implements IMessageComposer
 | 
					class AuthenticatedComposer implements IMessageComposer {
 | 
				
			||||||
{
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    #[Override] function compose(ServerMessage $message): void {
 | 
					    #[Override] function compose(ServerMessage $message): void {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,14 +7,15 @@ use Emulator\Encoding\ByteEncoding;
 | 
				
			||||||
use Emulator\Messages\Incoming\ClientMessage;
 | 
					use Emulator\Messages\Incoming\ClientMessage;
 | 
				
			||||||
use Emulator\Messages\MessageHandler;
 | 
					use Emulator\Messages\MessageHandler;
 | 
				
			||||||
use Emulator\Network\Game\Sessions\Session;
 | 
					use Emulator\Network\Game\Sessions\Session;
 | 
				
			||||||
 | 
					use Emulator\Utilities\Dictionary;
 | 
				
			||||||
use OpenSwoole\WebSocket\Server;
 | 
					use OpenSwoole\WebSocket\Server;
 | 
				
			||||||
use OpenSwoole\Http\Request;
 | 
					use OpenSwoole\Http\Request;
 | 
				
			||||||
use OpenSwoole\WebSocket\Frame;
 | 
					use OpenSwoole\WebSocket\Frame;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class GameNetworkServer {
 | 
					class GameNetworkServer {
 | 
				
			||||||
    private array $sessions;
 | 
					    private Dictionary $sessions;
 | 
				
			||||||
    public function __construct(private readonly MessageHandler $messageHandler) {
 | 
					    public function __construct(private readonly MessageHandler $messageHandler) {
 | 
				
			||||||
        $this->sessions = [];
 | 
					        $this->sessions = new Dictionary(Session::class);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function start(int $port): void {
 | 
					    public function start(int $port): void {
 | 
				
			||||||
| 
						 | 
					@ -32,17 +33,17 @@ class GameNetworkServer {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    function onOpen(Server $server, Request $request): void {
 | 
					    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 {
 | 
					    function onClose(Server $server, int $fd): void {
 | 
				
			||||||
        Logger::info("Connection #$fd has been closed");
 | 
					        Logger::info("Connection #$fd has been closed");
 | 
				
			||||||
        unset($this->sessions[$fd]);
 | 
					        $this->sessions->remove($fd);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    function onDisconnect(Server $server, int $fd): void {
 | 
					    function onDisconnect(Server $server, int $fd): void {
 | 
				
			||||||
        Logger::info("Connection #$fd has disconnected");
 | 
					        Logger::info("Connection #$fd has disconnected");
 | 
				
			||||||
        unset($this->sessions[$fd]);
 | 
					        $this->sessions->remove($fd);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    function onMessage(Server $server, Frame $frame): void {
 | 
					    function onMessage(Server $server, Frame $frame): void {
 | 
				
			||||||
| 
						 | 
					@ -52,7 +53,7 @@ class GameNetworkServer {
 | 
				
			||||||
            $length = ByteEncoding::getInt32(array_slice($data, 1, 4));
 | 
					            $length = ByteEncoding::getInt32(array_slice($data, 1, 4));
 | 
				
			||||||
            $packet = array_slice($data, 4, $length);
 | 
					            $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));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -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]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -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));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Loading…
	
		Reference in New Issue