Makes the autoload work without using a register function, as well as changes the networking to OpenSwoole so binary data can be send to the client

main
Tiger 2024-02-23 22:26:39 +01:00
parent 6b0d439f7c
commit fcee1f89d4
5 changed files with 155 additions and 1536 deletions

View File

@ -1,11 +1,11 @@
{ {
"require": { "require": {
"react/event-loop": "^1.5", "openswoole/core": "22.1.5",
"react/http": "^1.9", "openswoole/ide-helper": "~22.0.1"
"react/stream": "^1.3", },
"react/async": "^4.2", "autoload": {
"react/promise": "^3.1", "psr-4": {
"react/socket": "^1.15", "Emulator\\": "src/Emulator"
"cboden/ratchet": "^0.4.4" }
} }
} }

1586
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -2,10 +2,6 @@
require_once 'vendor/autoload.php'; require_once 'vendor/autoload.php';
spl_autoload_register(function(string $class) {
require_once str_replace('\\', DIRECTORY_SEPARATOR, $class) . '.php';
});
use Emulator\HabboEnvironment; use Emulator\HabboEnvironment;
HabboEnvironment::getInstance()->initialize(); HabboEnvironment::getInstance()->initialize();

View File

@ -7,33 +7,22 @@ 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 Override; use OpenSwoole\WebSocket\Server;
use Ratchet\ConnectionInterface; use OpenSwoole\Http\Request;
use Ratchet\Http\HttpServer; use OpenSwoole\WebSocket\Frame;
use Ratchet\RFC6455\Messaging\MessageInterface;
use Ratchet\Server\IoServer;
use Ratchet\WebSocket\MessageComponentInterface;
use Ratchet\WebSocket\WsConnection;
use Ratchet\WebSocket\WsServer;
use React\EventLoop\Loop;
use React\Socket\SocketServer;
class GameNetworkServer implements MessageComponentInterface { class GameNetworkServer {
private static ?GameNetworkServer $instance = null; private static ?GameNetworkServer $instance = null;
private array $sessions; private array $sessions;
public function start(int $port): void { public function start(int $port): void {
$loop = Loop::get(); $server = new Server("127.0.0.1", $port);
$server->on('Start', [$this, 'onStart']);
$this->sessions = []; $server->on('Open', [$this, 'onOpen']);
$socketServer = new SocketServer("127.0.0.1:{$port}", loop: $loop); $server->on('Close', [$this, 'onClose']);
new IoServer( $server->on('Disconnect', [$this, 'onDisconnect']);
new HttpServer( $server->on('Message', [$this, 'onMessage']);
new WsServer($this) $server->start();
),
$socketServer,
$loop
);
} }
public static function getInstance(): GameNetworkServer { public static function getInstance(): GameNetworkServer {
@ -44,27 +33,32 @@ class GameNetworkServer implements MessageComponentInterface {
return self::$instance; return self::$instance;
} }
#[Override] function onOpen(ConnectionInterface $conn): void { function onStart(Server $server): void {
$this->sessions[$conn->resourceId] = new Session(new WsConnection($conn)); Logger::info("Websocket server is started at $server->host:$server->port");
} }
#[Override] function onClose(ConnectionInterface $conn): void { function onOpen(Server $server, Request $request): void {
unset($this->sessions[$conn->resourceId]); $this->sessions[$request->fd] = new Session($server, $request);
} }
#[Override] function onError(ConnectionInterface $conn, \Exception $e): void { function onClose(Server $server, int $fd): void {
Logger::fatal($e->getMessage()); Logger::info("Connection #$fd has been closed");
unset($this->sessions[$fd]);
} }
#[Override] public function onMessage(ConnectionInterface $conn, MessageInterface $msg): void { function onDisconnect(Server $server, int $fd): void {
$raw = $msg->getPayload(); Logger::info("Connection #$fd has disconnected");
$data = unpack('C*', $raw); unset($this->sessions[$fd]);
}
function onMessage(Server $server, Frame $frame): void {
$data = unpack('C*', $frame->data);
if (count($data) >= 6) { if (count($data) >= 6) {
$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);
MessageHandler::getInstance()->handlePacket($this->sessions[$conn->resourceId], new ClientMessage($packet)); MessageHandler::getInstance()->handlePacket($this->sessions[$frame->fd], new ClientMessage($packet));
} }
} }
} }

View File

@ -5,15 +5,16 @@ namespace Emulator\Network\Game\Sessions;
use Emulator\Encoding\ByteEncoding; use Emulator\Encoding\ByteEncoding;
use Emulator\Messages\Outgoing\IMessageComposer; use Emulator\Messages\Outgoing\IMessageComposer;
use Emulator\Messages\Outgoing\ServerMessage; use Emulator\Messages\Outgoing\ServerMessage;
use Ratchet\RFC6455\Messaging\Frame; use OpenSwoole\Http\Request;
use Ratchet\RFC6455\Messaging\Message; use OpenSwoole\WebSocket\Server;
use Ratchet\WebSocket\WsConnection;
readonly class Session { readonly class Session {
private WsConnection $connection; private Server $server;
private Request $request;
public function __construct(WsConnection $connection) { public function __construct(Server $server, Request $request) {
$this->connection = $connection; $this->server = $server;
$this->request = $request;
} }
public function sendComposer(IMessageComposer $composer): void { public function sendComposer(IMessageComposer $composer): void {
@ -21,20 +22,6 @@ readonly class Session {
$composer->compose($message); $composer->compose($message);
$data = array_merge(ByteEncoding::int32ToArray(count($message->getPacket())), $message->getPacket()); $data = array_merge(ByteEncoding::int32ToArray(count($message->getPacket())), $message->getPacket());
$this->connection->send(new Frame(pack('C*', ...$data), true, Frame::OP_BINARY)); $this->server->push($this->request->fd, pack('C*', ...$data), Server::WEBSOCKET_OPCODE_BINARY);
} }
function encode($text) {
$b1 = 0x80 | (0x1 & 0x0f);
$length = strlen($text);
if ($length <= 125)
$header = pack('CC', $b1, $length);
elseif($length > 125 && $length < 65536)
$header = pack('CCn', $b1, 126, $length);
elseif($length >= 65536)
$header = pack('CCNN', $b1, 127, $length);
return $header.$text;
}
} }